◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/Dev Tools
⬡ Dev Tools/2026-05-26Advanced

Aggregating App Store Connect, RevenueCat, and AdMob into One Morning Digest with Cloudflare Workers — A Six-App Indie Architecture

A practical architecture for indie developers running multiple Rork apps: aggregate App Store Connect API, RevenueCat REST, and AdMob Reporting API in a Cloudflare Workers Cron job and ship a single daily Slack digest each morning.

Rork585Cloudflare Workers25App Store Connect API5RevenueCat30AdMob73indie developer43metricsarchitecture13

✦ Premium Article

Before I'd even poured the coffee, I would open App Store Connect, then RevenueCat, then AdMob, then Firebase Console, then Crashlytics. Six tabs per app. For six apps, that's thirty-something tabs, a spreadsheet copy-paste session, and forty minutes gone. Some mornings the Crashlytics graph would pull my mood down; other mornings the RevenueCat MRR line would loosen my shoulders. Either way, by the time I had the numbers in my head I had also lost the freshest part of my day.

I have been shipping iOS and Android apps as a one-person developer since 2014. Cumulative downloads now exceed 50 million, mostly across wallpaper, healing, and manifestation-style image apps. My current portfolio of 5–7 active titles holds AdMob revenue over one million yen per month, but that number is held up by the unglamorous habit of looking at numbers every morning and deciding the day's tuning. When the numbers alone took 30–40 minutes, that habit was being squeezed at its narrowest point.

This article walks through the architecture I actually run in production today: an App Store Connect API + RevenueCat REST + AdMob Reporting API aggregator on Cloudflare Workers Cron Triggers, posting a single morning digest to Slack at 08:00 JST. The morning check is now under five minutes. The monthly Cloudflare bill sits at $0–$5, which is fair for a one-person operation.

What we're aggregating, and where the data comes from

Before any code, lay the sources side by side. Each API has its own auth, rate limit, and freshness, and ignoring this leads to swampy code later.

SourceMetricsAuthFreshnessRate limit
App Store Connect APIdownloads, revenue, IAP counts per appJWT (ES256)T-1 day200 req/min
RevenueCat REST v1MRR, retention, cancellationsBearer Tokennear real-time1,200 req/min
AdMob Reporting APIeCPM, impressions, revenue per appOAuth 2.0T-1 day750 req/min
Firebase Crashlytics (via BigQuery export)crash-free users, impacted usersService AccountT-1 day (requires export)BigQuery quotas

App Store Connect API and AdMob Reporting API finalize "yesterday" sometime around noon the next day. For an 08:00 run, you're safely reading the day before yesterday. RevenueCat allows same-day reads, but cancellations take up to two hours to reflect, so I anchor on the 23:59 JST snapshot of the previous day. Stable beats fresh here.

High-level architecture

The whole system runs on Cloudflare Workers. To keep the monthly cost at zero, the only state stores are Workers KV (for the previous-day snapshot used in diff calculations) and D1 (for the rolling 30-day history that powers weekly retro views).

┌────────────────────────────────────────────┐
│  Cloudflare Workers (Cron: 0 23 * * *)     │
│  ┌────────────────────────────────────┐    │
│  │  1. fetch App Store Connect API    │    │
│  │  2. fetch RevenueCat REST           │    │
│  │  3. fetch AdMob Reporting API       │    │
│  │  4. fetch Crashlytics (BigQuery)    │    │
│  │  5. normalize + diff vs prev day    │    │
│  │  6. detect anomalies (±20% / +0.5pt)│    │
│  │  7. post to Slack (Block Kit)       │    │
│  └────────────────────────────────────┘    │
│              ↓                ↓             │
│        Workers KV         D1 (history)      │
│   (last snapshot)    (last 30 days)         │
└────────────────────────────────────────────┘

Anything older than 30 days I defer to GA4's BigQuery export rather than carry inside Workers. As an indie, dragging long-horizon data into a hand-rolled store creates a quiet maintenance debt I do not want to own.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Full code for signing App Store Connect JWTs (ES256), pulling RevenueCat REST overview, and calling the AdMob Reporting API from a Cloudflare Workers Cron — including the gotchas with JWT aud, gzipped TSV, and AdMob streaming JSON
✦Real numbers: 30–40 minutes of morning dashboard hopping compressed to under 5 minutes across six apps, run on Workers + KV + D1 within a monthly cost of $0–$5
✦Anomaly detection thresholds (DL ±20%, revenue ±25%, crash-free-users dropping below 99.5%) routed into Slack Block Kit so only the abnormal lines demand attention
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⬡ Dev Tools2026-06-12
Building a Developer Debug Menu Into Your Rork App — Verify Ads, Purchases, and Remote Config Before Release
A production-safe developer debug menu for Rork apps — switch environments, force test ads, simulate entitlements, and override Remote Config, with working TypeScript code and the pitfalls I hit running six apps.
⬡ Dev Tools2026-05-23
Auditing Privacy Manifests for Rork-Generated Expo Apps — A One-Day Pre-Submission Workflow for Indie Developers
A pre-submission workflow for indie developers shipping Rork-generated Expo apps: enumerate every dependency, tell ITMS-91053 apart from ITMS-91061, and catch the Pods that npm names never show you — hermes included.
⬡ Dev Tools2026-05-19
Rolling Out Firebase App Check in Rork Without Breaking AdMob or Crashlytics
A practical, staged rollout for Firebase App Check in Rork apps that keeps Crashlytics reporting, Realtime Database listeners, and AdMob payouts intact — written from running AdMob-funded indie apps in production.