Skip to content

t1k:marketing:monetization:mintegral-regional-report

FieldValue
Modulemonetization
Version1.16.9
Effortmedium
Tools—
/t1k:marketing:monetization:mintegral-regional-report

Produces a finished, archived regional report that breaks Mintegral monetization down by macro-region and renders it as a self-contained HTML dashboard (gradient header + KPI strip, color-coded regional rollup with revenue-share bars, per-region cards with top countries, and a channel-level UA section). Markdown and JSON are optional secondary outputs.

Sibling to t1k:marketing:monetization:mintegral-report (the day-over-day daily report) and t1k:marketing:monetization:mintegral (the API/MCP integration reference). THIS skill is the geo / regional deliverable and the default for “give me an HTML report”.

Activate on: “regional report”, “report by region”, “report for each region”, “mintegral region/geo breakdown”, “html report”, “mintegral report as html”, “regional revenue/eCPM”.

  • Default window = last 7 complete UTC+8 days. A 7-day window is the right default for regional cuts — small countries have tiny daily samples, so a single day is noisy. Override with an explicit date range when asked.
  • For a single-day day-over-day report (headline + trend + top apps + campaigns), use the daily report skill instead.

Needs the Publisher + Advertiser credential families in ~/.claude.json (local scope) — same setup as the daily report. The generator reads them automatically (never hardcoded, never from the repo):

FamilyEnv varsPowers
PublisherMINTEGRAL_PUB_SKEY / MINTEGRAL_PUB_SECRETregional revenue, eCPM, fill, per-country
AdvertiserMINTEGRAL_ADV_USERNAME (Access Key) / MINTEGRAL_ADV_API_KEYUA channel total (spend / installs / CPI)

Missing a family → the generator prints WARNING: missing credential … to stderr and that part comes back empty. Surface that rather than reporting zeroes as real.

Steps 1–2 (resolve the window, run the generator) and step 3 (open the HTML) are mechanical; step 4, the analyst notes on the markdown variant, is the judgment part and stays on a reasoning tier (routing SSOT: rules/orchestration-rules.md § “Task-Type → Agent Routing”):

StepAgent
Run fetch-mintegral-regional-report.cjs for the resolved window and report the emitted tablest1k-fact-fetcher
Step 4 — write the 4–6 evidence-based analyst takeaways (--md variant)stays on a reasoning tier, not delegated
Commit + push the archived reportt1k-git-manager (via /t1k:git)

The generator already computes the regional rollup, per-format eCPM, and the bid-floor matrix — a cheap agent’s job is to run it and surface the rendered output (including any WARNING: missing credential line) verbatim, not to recompute per-region ratios by hand.

  1. Resolve the window. Default = last 7 complete days (UTC+8). Accept an explicit start end (YYYY-MM-DD or YYYYMMDD) or --days=N.

  2. Run the generator (deterministic — fetches, aggregates by region, recomputes ratios, renders, archives):

    Terminal window
    # default last-7-days HTML, archived to data/mintegral/reports/regional-<start>_<end>.html
    node .claude/skills/t1k-marketing-monetization-mintegral-regional-report/scripts/fetch-mintegral-regional-report.cjs
    # explicit range, also emit markdown + json alongside the HTML
    node .claude/skills/.../scripts/fetch-mintegral-regional-report.cjs 2026-06-04 2026-06-10 --html --md --json
    # print to stdout without archiving (preview)
    node .claude/skills/.../scripts/fetch-mintegral-regional-report.cjs --no-write

    Flags: --html (default), --md, --json, --days=N, --no-write. HTML is written when no format flag is given.

  3. Open it for the user. open data/mintegral/reports/regional-<start>_<end>.html (macOS) so they see the dashboard immediately.

  4. (If --md) write analyst notes. The markdown variant has an ## Analyst notes placeholder — replace it with 4–6 evidence-based takeaways: ad-format eCPM spread + per-format/per-geo floor recommendations (from the bid-floor matrix), the Banner-drags-the-blend caveat, value-vs-volume split, the Top-5% premium tail, and the UA data gap. The HTML’s strategic-takeaways section is auto-generated by computeInsights() (includes a per-format floor takeaway). Tie each note to a number in the report.

  5. Commit + push so the report history accrues (per CLAUDE.md data policy):

    /t1k:git cp → docs(mintegral): regional report <start>..<end>
  • KPI strip — total ad revenue, blended eCPM, fill, impressions, UA spend, UA installs.
  • Regional rollup — 8–9 macro-regions ranked by revenue, with share bars, eCPM, Top-5% eCPM (premium-inventory ceiling), fill, impressions, country count, and a TOTAL row.
  • Per-region cards — each region’s revenue/eCPM/fill/impressions, a Top-5%-inventory eCPM line, and top-6 countries (with flag emoji).
  • eCPM by ad type — Rewarded Video / Interstitial / Banner (+ “Other” remainder): revenue, share, eCPM, fill, impressions. The blended eCPM is a near-useless average across formats — this table is the real read.
  • eCPM by ad type × region — bid-floor matrix — per-format eCPM within each region, the cut used to set per-format/per-geo target_ecpm / ecpm_floor.
  • UA channel total — spend / installs / CPI / clicks / impressions / active offers, with the hard NOT-a-regional-split caveat.

Advertiser UA pull — chunk to ≤7-day windows + zero-result guard

Section titled “Advertiser UA pull — chunk to ≤7-day windows + zero-result guard”

The advertiser (UA) report enforces an undeclared date-range cap: a single request spanning more than ~7 days returns an empty / $0 payload with no error (HTTP looks fine). The default 7-day window is safe, but any wider window (--days=30, an explicit multi-week range) silently truncates to $0. Treat the cap as a hard procedure, not a footnote:

  1. Auto-chunk the advertiser pull into ≤7-day segments spanning the full requested window. Walk the window in contiguous ≤7-day slices, issue one advertiser request per slice, and SUM spend / installs / clicks / impressions across all slices (recompute CPI = total spend ÷ total installs at the end — never average per-slice CPIs). A 7-day-or-shorter window is one slice; do not chunk needlessly.
  2. Zero-result guard (errors over silent fallbacks). If the requested window spans >1 day and the advertiser pull comes back empty / $0 across the whole window, do NOT render $0 as truth. Treat it as suspect and surface a warning in the report and to the user — e.g. WARNING: advertiser UA returned $0 over an N-day window — likely a date-range-cap truncation or auth issue, not real zero spend. Re-pull in ≤7-day chunks before trusting this. A genuine $0 over a multi-day live channel is implausible; a capped/empty pull looks identical, so flag rather than report.
  3. Per-slice empties are still suspect. If any individual ≤7-day slice returns $0 while sibling slices return spend, flag that slice rather than silently summing a zero into the total.

This is the same est_revenue is estimated / errors-over-silent-fallbacks discipline applied to the advertiser side: a quiet empty payload must never be presented as a real number. The chunking also matches the publisher surface, which already caps at 7 days per request.

  • Advertiser date-range cap → $0 over long windows. See “Advertiser UA pull” above. A multi-day advertiser window beyond ~7 days returns empty/$0 silently — always chunk to ≤7-day slices and SUM, and zero-guard any empty multi-day result. (Was: the generator pulled the whole window in one advertiser call, so a 30-day window returned $0 while a 7-day subset returned real spend — issue #20.)
  • UA is channel-level ONLY — never split UA by region. The advertiser API returns spend grouped by offer, and each offer’s geo field is its targeting allow-list (a ~200-country “WW” string), NOT the delivery geo. Allocating UA spend to regions is fabrication. A true regional UA cut needs MMP (AppsFlyer/Adjust) install-by-country data. The generator hard-codes this caveat into the report — keep it.
  • Never average ratios. eCPM and fill are recomputed per region (and per ad type) from summed raw est_revenue / impression / filled / request. Averaging the per-country eCPM/fill columns would be wrong (it ignores volume weighting).
  • Ad type is a FILTER, not a group_by dimension. The publisher API’s group_by only accepts date,country,app_id,platform,placement_id,unit_id,bidding_type,timestamp — group_by=ad_type/ad_format silently falls back to grouping by date (a classic silent-wrong-result trap). Ad-type eCPM is obtained by running one filtered country pull per ad_format and aggregating. The verified live tokens (2026-06) are exactly three: rewarded_video, new_interstitial (interstitial video), sdk_banner. Other guesses (interstitial, reward_video, banner, native, splash) return zero rows. They reconcile to ~100% of the unfiltered total; the small remainder is shown as “Other”. If a new format appears, add its token to the AD_FORMATS array.
  • Banner skews the blend. Banner (sdk_banner) is typically ~30% of impressions but ~1% of revenue at a ~$0.30 eCPM and ~35% fill — it single-handedly drags both the blended eCPM and the blended fill down. Rewarded Video and Interstitial fill at ~98%. Read eCPM/fill per ad type, not blended, especially before concluding there’s “fill headroom”.
  • Top-5% eCPM = volume-weighted eCPM of the highest-eCPM countries making up the top 5% of a region’s impressions (premium-inventory ceiling). Volume-weighting keeps micro-sample geos from skewing it; the displayed country list may include tiny high-eCPM geos that contribute ~0 weight to the blend.
  • Timezone is UTC+8 (Mintegral default) throughout. Publisher uses YYYYMMDD; Advertiser uses Unix-second integers — the generator handles both.
  • NOT total revenue / NOT ROAS. Monetization is Mintegral-mediated ad revenue only; the UA total is Mintegral-channel spend only. Same-day/same-window in vs out is not profit.
  • The region map is a fixed ISO-2 → macro-region lookup in the script. New/unknown country codes fall into “Other / Unmapped” (filtered from the report when negligible). If a real territory lands there, add it to the REGIONS map.
  • The generator is read-only — never mutates Mintegral, no write guard involved.
  • Data + HTML generator: scripts/fetch-mintegral-regional-report.cjs (self-contained: fetch → aggregate → render).
  • Auth model + API params: base skill t1k:marketing:monetization:mintegral §Authentication.
  • Archive location: data/mintegral/reports/regional-<start>_<end>.{html,md,json}.