- 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
7.5 KiB
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
- 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).
- Debug tool on a test device: every network listed with its adapter and SDK versions as a supported pair, test ads loading per format.
- No fill before launch is normal: networks start filling once the app is live and its store URLs are set in the mediation dashboard.
- 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 inads.appAdsTxtsostorebound validate --playchecks 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). - iOS: SKAdNetwork ids of every network in Info.plist (from each network's list or generator),
NSUserTrackingUsageDescriptionand the ATT prompt before the ad SDK starts, privacy manifests of every SDK (storebound privacy-manifest --ios ios/App,privacy-manifestskill). - Android:
com.google.android.gms.permission.AD_IDand 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). - 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). - 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 withSKAdNetworkIdentifier) and, for AdAttributionKit, inAdNetworkIdentifiers(array of strings). Apple: lowercase, "otherwise, the system doesn't recognize it as a valid network" (capital letters = blocker)..skadnetworkand.adattributionkitids work for both frameworks, so the same list can go into both keys; ids only inSKAdNetworkItemsare 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 anAdAttributionKitdictionary 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 withEligibleForAdAttributionKitReengagementPostbackCopies= YES (needs the copy endpoint); SKAdNetwork copies (and Private Click Measurement) withNSAdvertisingAttributionReportEndpoint. The app must callupdateConversionValue(AdAttributionKit) orupdatePostbackConversionValue(SKAdNetwork) at least once, best at first launch, or an attribution SDK (AppsFlyer, Adjust, Branch, Singular, Kochava) must do it. - Attribution rules:
AdAttributionKitConfigurations>AttributionWindows>globalor an ad network id >install>click1-30 days,view1-7 days,ignoreInteractionTypeview | click (ad network entries only);AttributionCooldown>install-cooldown-hours/re-engagement-cooldown-hours0-720. - AdAttributionKit and SKAdNetwork need no ATT prompt; keep
NSUserTrackingUsageDescriptiononly 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'sshowMediationDebugger). 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)
- After init call the SDK's
validateIntegration(); the device log (Xcode console, Android logcat tagIntegrationHelper) must list every network as "Adapter - Version x - VERIFIED". Adapter + network SDK versions must be a pair from Unity's adapter tables. - Unity Ads "Invalid Game ID" / iOS "Initialization failed: not found" is often account-side: compare
https://publisher-config.unityads.unity3d.com/games/<gameId>/configurationfor your id with Unity's demo id14851. 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). - 509 "Mediation No fill" before launch: the LevelPlay app is not live / not linked to store URLs yet.
- app-ads.txt:
ironsrc.com, <id>, DIRECTplus 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.