t1k:marketing:monetization:admob
| Field | Value |
|---|---|
| Module | monetization |
| Version | 1.16.9 |
| Effort | high |
| Tools | — |
How to invoke
Section titled “How to invoke”/t1k:marketing:monetization:admobGoogle AdMob setup, optimization, mediation, and revenue reporting integration.
When to Use
Section titled “When to Use”- Integrating AdMob SDK (Unity / iOS / Android)
- Setting up AdMob mediation waterfall or bidding
- Configuring eCPM floors / implementing UMP consent
- Pulling mediation revenue via the AdMob API mediation report (per-network/ad-source dashboards)
Reporting API — endpoint & auth
Section titled “Reporting API — endpoint & auth”- AdMob API (REST):
accounts.mediationReport.generateandaccounts.networkReport.generate. Base:https://admob.googleapis.com/v1/accounts/{publisherId}/mediationReport:generate - Auth: OAuth 2.0 (Google service account / user consent) — NOT a static key.
- The request body is a
ReportSpec(dateRange, dimensions, metrics, dimensionFilters, sortConditions). Response streams rows asdimensionValues+metricValuesobjects.
Per-network dimension — AD_SOURCE (no two-call conflict)
Section titled “Per-network dimension — AD_SOURCE (no two-call conflict)”- The mediation report exposes
AD_SOURCEandAD_SOURCE_INSTANCEdimensions — this IS the per-network/mediated-source breakdown (the AdMob equivalent of AppLovin’snetwork). - Unlike AppLovin MAX, AdMob has no
requests⊥ network conflict — you can requestAD_SOURCEalongside request-style metrics in a single call. - Standard dimensions:
DATE,APP,AD_UNIT,FORMAT,COUNTRY, plusAD_SOURCE/AD_SOURCE_INSTANCE(mediation report only). - Metrics:
ESTIMATED_EARNINGS,IMPRESSIONS,CLICKS,AD_REQUESTS,MATCHED_REQUESTS,IMPRESSION_CTR,OBSERVED_ECPM, etc.
estimated earnings semantics
Section titled “estimated earnings semantics”ESTIMATED_EARNINGSis reported in micros of the account currency (divide by 1,000,000). It is estimated and finalized later.- When grouped by
AD_SOURCE, per-source earnings decompose the mediated total — sum back to the all-source total per (date, app).
Quirks
Section titled “Quirks”- Response dimension/metric values are nested objects (
row.dimensionValues['DATE'].value,row.metricValues['ESTIMATED_EARNINGS'].microsValue), NOT flat columns — different shape from a columnar revenue table. - Date range max per request is large but paginate via the streaming response; respect Google API quotas.
- This platform’s
apps/admob-apialready requestsAD_SOURCE/AD_SOURCE_INSTANCEinadmob.service.tsand serves revenue fromHistoricalDataAggregated(not arevenue_datacolumnar table) — admob’s per-network path differs from applovin/adjust/mintegral. - The googleads dashboard pulls its revenue numbers from admob-api (Google monetization = AdMob).
References
Section titled “References”- AdMob API — Mediation report: https://developers.google.com/admob/api/v1/reference/rest/v1/accounts.mediationReport/generate
- AdMob API — ReportSpec dimensions/metrics: https://developers.google.com/admob/api/v1/reference/rest/v1/accounts.networkReport/generate
Diagnosing accounts.list → bare 400 INVALID_ARGUMENT (READ BEFORE concluding “no publisher”)
Section titled “Diagnosing accounts.list → bare 400 INVALID_ARGUMENT (READ BEFORE concluding “no publisher”)”A bare 400 INVALID_ARGUMENT (no details[].fieldViolations) from GET /v1[beta]/accounts does NOT prove the identity has no AdMob publisher. accounts.list is a quirky discovery call — per the docs it “lists the AdMob publisher account most recently signed in to from the AdMob UI” — and it returns this bare 400 in several distinct situations. Do NOT jump to “no publisher / retire the integration” from accounts.list alone. Work the checklist in order:
- Console access ≠ API access. A user added to an AdMob account (even full Administrator in
console.admob.com→ Settings → Users) can see everything in the UI yet still getaccounts.list400. The AdMob API authorizes the Google identity differently from the console. - Confirm scope on the MINTED token, not the consent request. Refresh the token and read the
/tokenresponsescope=. It MUST containadmob.readonly(needed foraccounts.list/apps/adUnits) ANDadmob.report(needed for reports). Old refresh tokens keep their old scopes — a re-consent is required after any scope change. - Don’t trust
accounts.listas the access test — test the publisher DIRECTLY. Get the realpub-XXXXXXXXXXXXXXXXfromconsole.admob.com→ Settings → Account information, then callGET /v1beta/accounts/pub-XXXX(accounts.get) and a tinymediationReport:generatewith the token. An added Admin CAN read via the API even whenaccounts.listreturns 400 — configure the knownpub-idand skipaccounts.listentirely. - googleapis-client path may silently drop auth (returns
401 CREDENTIALS_MISSING). If using the googleapisOAuth2Client, verify thatclient_id,client_secret, andrefresh_tokenare all set on the client before any call — missing client credentials cause the library to omit theAuthorizationheader entirely. Working alternative: mint an access token via a manual token-refresh POST and useAuthorization: Bearer <accessToken>on direct HTTP calls; the googleapis streaming*Report:generatecan drop the header when the client is misconfigured. - API-enabled check: if
mediationReport/networkReportreturns a field-violation 400 (e.g. “Empty metrics”), the API IS enabled and the token works — that is NOT the no-publisher signature. A truly disabled API returns403 SERVICE_DISABLEDwith an activation URL. A401 CREDENTIALS_MISSINGmeans the token wasn’t attached (see #4), NOT an auth/permission denial.
Net rule: never conclude “no AdMob publisher” / “no access” / “retire integration” from accounts.list 400 — verify with accounts.get on the real pub-id first.
Standalone AdMob mediation vs AdMob-as-a-MAX-adapter — use MEDIATION_GROUP to prevent double-count
Section titled “Standalone AdMob mediation vs AdMob-as-a-MAX-adapter — use MEDIATION_GROUP to prevent double-count”When a studio runs AdMob both as a standalone mediator AND as an adapter inside AppLovin MAX (the common case), the AdMob account report double-reports every impression AdMob serves through MAX (AdMob logs it too). So the full AdMob account total = standalone + AdMob-as-MAX-adapter, and the MAX-adapter slice is already counted in MAX (demandNetwork='admob'). Adding the full AdMob account total to MAX double-counts.
Do NOT use subtraction (account_total − MAX(demandNetwork=admob)) — it depends on MAX per-network data (often only recent dates) and is approximate. Use the MEDIATION_GROUP dimension instead — it’s API-native, exact, and works for ALL dates:
mediationReport:generatewithreportSpec.dimensions=['MEDIATION_GROUP', …]returns earnings per mediation group, matching the AdMob console (Mediation → Mediation groups) to the cent.- Standalone AdMob = sum of the NAMED custom mediation groups; EXCLUDE
AdMob (default). The named groups are the studio’s own mediation setups;AdMob (default)is the catch-all that absorbs the MAX-adapter + unmatched traffic (the overlap already in MAX). - Ingest standalone (named-group) revenue as the authoritative
source='admob'line (additive to MAX, zero double-count). Store/keepAdMob (default)rows as non-authoritative reference only.
Rule of thumb for ANY mediation network that is also a bidder in another mediator: never sum the network’s full account with the other mediator’s revenue — isolate the network’s own-mediation slice (here, named MEDIATION_GROUPs) before counting it as a separate line.
Gotchas
Section titled “Gotchas”- UMP SDK is required for EU/UK/CH traffic — without consent UMP-handled, AdMob will throttle or zero-fill those geos. Test with a VPN before claiming integration is done.
- SKAdNetwork conversion-value model affects iOS revenue, not delivery — wrong CV mapping silently underreports campaign ROAS without breaking ad serving.
- Mediation A/B tests require a 7-14 day ramp — earlier reads are noise, especially in low-fill geos.
- Banner refresh rate has a recommended floor (60s) — going faster gets you flagged for invalid traffic and revenue clawbacks.