- apple testflight wait --build N (progress, timeout, exit 0/1/7) and expire --keep N | --older-than D (dry run, asks) - apple iap-submit: IAP / subscription / group versions into a review submission; first of a type only with the app version (--with-version), --no-submit keeps the draft; read-only MCP plan - apple listing pull, play listing pull (diff, --write), catalog pull (config proposal, never rewritten) - whats-new --languages / check / apply: one file per language, agent or hook translation, per-store limits - apple offer-codes, win-back, promoted, preorder; Play pre-registration as a guide (no API) - apple cpp and apple events: list, create, upload, submit (asks) - reports: Apple sales / finance, Play earnings / sales into .storebound/reports with summary and CSV - triage: TestFlight crash / feedback and Play error reports grouped by signature, device, OS - aso rank: iTunes Search API ranks and competitors, rate limited - ads scan: AdAttributionKit / SKAdNetwork Info.plist and source checks - tests against recorded, sanitized answers; skills, README, CHANGELOG
86 lines
7.5 KiB
Markdown
86 lines
7.5 KiB
Markdown
---
|
|
name: ads-mediation-checks
|
|
description: Diagnose and verify ad mediation in a mobile app or game before and after store release - Google AdMob (Ad Inspector), AppLovin MAX (Mediation Debugger) and Unity LevelPlay / ironSource (validateIntegration) with their networks - app ids and ad unit ids, adapter versions, test devices, no-fill before launch, app-ads.txt on the developer website, SKAdNetwork ids, AdAttributionKit (ad network ids, postback copies, attribution windows; storebound ads scan), ATT, privacy manifests, consent, COPPA and Data safety / App Privacy answers. Use when ads do not load, a network reports invalid ids, the user adds an ad SDK, or prepares ads for launch.
|
|
---
|
|
|
|
# Ad mediation checks (AdMob, AppLovin MAX, LevelPlay)
|
|
|
|
CLI: `storebound ads scan --ios <path>` (AdAttributionKit / SKAdNetwork configuration, below), `storebound validate
|
|
--play` (app-ads.txt) and `storebound privacy-manifest`; the rest are checks to run and read. Ask the owner before changing any dashboard setting. Most apps without ads can skip this skill.
|
|
|
|
## Every mediation platform
|
|
1. **Ids per platform**: iOS and Android have different app ids / keys and ad unit ids. Production ids only in release
|
|
builds; test ids or registered test devices during development (real units with test traffic can get the account
|
|
flagged).
|
|
2. **Debug tool on a test device**: every network listed with its adapter and SDK versions as a supported pair, test
|
|
ads loading per format.
|
|
3. **No fill before launch is normal**: networks start filling once the app is live and its store URLs are set in
|
|
the mediation dashboard.
|
|
4. **app-ads.txt** at the root of the developer website named in both listings (`https://<domain>/app-ads.txt`; IAB
|
|
spec: https://github.com/InteractiveAdvertisingBureau/Supply-Chain-Validation/blob/main/app-ads.txt.md): the
|
|
platform's own line plus each network's lines from the dashboard. Put them in `ads.appAdsTxt` so
|
|
`storebound validate --play` checks the file. The listing website domain must match exactly (AdMob: the developer
|
|
website; on iOS the marketing URL; verification can take a day, https://support.google.com/admob/answer/9363762).
|
|
5. **iOS**: SKAdNetwork ids of every network in Info.plist (from each network's list or generator),
|
|
`NSUserTrackingUsageDescription` and the ATT prompt before the ad SDK starts, privacy manifests of every SDK
|
|
(`storebound privacy-manifest --ios ios/App`, `privacy-manifest` skill).
|
|
6. **Android**: `com.google.android.gms.permission.AD_ID` and the Play advertising ID declaration; the AdMob app id in
|
|
the manifest when any AdMob adapter is present (the app crashes at launch without it).
|
|
7. **Privacy and audience**: consent (CMP) in the EU / EEA / UK / CH or non-personalized ads; "not directed at
|
|
children" unless the app is for kids (Families policy otherwise); Data safety and App Privacy list the ad data as
|
|
shared / tracking (`store-declarations`).
|
|
8. **Placement**: no ads at launch, on exit or mid-task / mid-round; close buttons visible; rewarded ads always
|
|
optional. Reviewers test the first minutes.
|
|
|
|
## AdAttributionKit and SKAdNetwork (iOS)
|
|
`storebound ads scan --ios ios/App [--json]` (MCP: `ads_scan`; local, read-only, exit 1 on a blocker) reads the app's
|
|
Info.plist (Pods, build output, tests and extensions left out), `Podfile.lock` / `Package.resolved` and the Swift /
|
|
Objective-C sources. What it checks, with Apple's documentation (links in `cli/lib/adattribution.ts`):
|
|
- **Publisher app** (shows ads): every network's ids in `SKAdNetworkItems` (dictionaries with `SKAdNetworkIdentifier`)
|
|
and, for AdAttributionKit, in `AdNetworkIdentifiers` (array of strings). Apple: lowercase, "otherwise, the system
|
|
doesn't recognize it as a valid network" (capital letters = blocker). `.skadnetwork` and `.adattributionkit` ids work
|
|
for both frameworks, so the same list can go into both keys; ids only in `SKAdNetworkItems` are flagged for
|
|
AdAttributionKit. Ad SDKs without any ids = blocker (installs from those ads cannot be attributed).
|
|
- **Advertised app** (runs ad campaigns): copies of winning postbacks with `AttributionCopyEndpoint` ("AdAttributionKit -
|
|
Postback Copy URL" in Xcode; storebound reads it inside an `AdAttributionKit` dictionary or at the top level), an
|
|
https URL whose registrable domain gets POSTs at `/.well-known/appattribution/report-attribution/` (a path is
|
|
ignored); re-engagement copies with `EligibleForAdAttributionKitReengagementPostbackCopies` = YES (needs the copy
|
|
endpoint); SKAdNetwork copies (and Private Click Measurement) with `NSAdvertisingAttributionReportEndpoint`. The app
|
|
must call `updateConversionValue` (AdAttributionKit) or `updatePostbackConversionValue` (SKAdNetwork) at least once,
|
|
best at first launch, or an attribution SDK (AppsFlyer, Adjust, Branch, Singular, Kochava) must do it.
|
|
- **Attribution rules**: `AdAttributionKitConfigurations` > `AttributionWindows` > `global` or an ad network id >
|
|
`install` > `click` 1-30 days, `view` 1-7 days, `ignoreInteractionType` view | click (ad network entries only);
|
|
`AttributionCooldown` > `install-cooldown-hours` / `re-engagement-cooldown-hours` 0-720.
|
|
- AdAttributionKit and SKAdNetwork need **no ATT prompt**; keep `NSUserTrackingUsageDescription` only when the app
|
|
really tracks across apps (store-declarations).
|
|
Test attribution with Developer Mode and the postback testing in Settings > Developer (Apple: "Testing ad
|
|
attributions with Developer Mode"); the scan only checks the configuration, not delivery.
|
|
|
|
## Google AdMob
|
|
- Ad Inspector (SDK 20.0.0+, test devices only) shows each ad unit's mediation waterfall, adapter status and errors:
|
|
https://developers.google.com/admob/android/ad-inspector (iOS: the same page under /admob/ios/).
|
|
- Register test devices in the AdMob UI or in code; use Google's demo ad unit ids during development.
|
|
|
|
## AppLovin MAX
|
|
- Mediation Debugger: `AppLovinSdk.getInstance(context).showMediationDebugger()` (iOS: the SDK's
|
|
`showMediationDebugger`). It lists integration status per network, missing SKAdNetwork ids and the app-ads.txt
|
|
entries; enable test mode per network under Completed Integrations > Test Ad, then restart the app.
|
|
https://support.applovin.com/en/max/android/testing-networks/mediation-debugger/
|
|
- SKAdNetwork: AppLovin's Info.plist generator for the networks you use
|
|
(https://support.applovin.com/en/max/ios/overview/skadnetwork).
|
|
|
|
## Unity LevelPlay (ironSource)
|
|
1. After init call the SDK's `validateIntegration()`; the device log (Xcode console, Android logcat tag
|
|
`IntegrationHelper`) must list every network as "Adapter - Version x - VERIFIED". Adapter + network SDK versions
|
|
must be a pair from Unity's adapter tables.
|
|
2. **Unity Ads "Invalid Game ID" / iOS "Initialization failed: not found"** is often account-side: compare
|
|
`https://publisher-config.unityads.unity3d.com/games/<gameId>/configuration` for your id with Unity's demo id
|
|
`14851`. If yours 404s or is empty, the Unity Ads project / game id is not set up or not linked to the LevelPlay app
|
|
(Monetization > Projects, and the LevelPlay network setup with exactly those ids).
|
|
3. **509 "Mediation No fill"** before launch: the LevelPlay app is not live / not linked to store URLs yet.
|
|
4. app-ads.txt: `ironsrc.com, <id>, DIRECT` plus the network lines from LevelPlay's app-ads.txt page
|
|
(https://docs.unity.com/en-us/grow/programmatic/ironsource-exchange/app-ads-txt).
|
|
|
|
## Gotchas
|
|
- A network failing to init does not break mediation; the others still fill once the app is live.
|
|
- Adding a network can add Data safety / App Privacy data types and SKAdNetwork ids: update both before release.
|