storebound/skills/ads-mediation-checks/SKILL.md
CRT b63f2fdfbc Store operations: TestFlight wait / expire, IAP review submissions, listing pulls, release notes per language, offers, custom product pages, in-app events, reports, triage, keyword ranks, AdAttributionKit scan
- 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
2026-10-11 23:58:17 +08:00

7.5 KiB

name description
ads-mediation-checks 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

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.