Building an App Store Analytics Dashboard from Scratch
We connected App Store Connect API, handled JWT auth, parsed TSV sales reports, and set up daily cron jobs. Here's how we built Apsity's core dashboard — and the pitfalls we hit along the way.
Why build your own dashboard?
App Store Connect works, but it doesn't scale. With 12 apps, you're logging in 12 times, clicking through 12 dashboards, and mentally summing revenue across currencies. ASC also had a bug in January 2026 where IAP revenue showed as $0 for days.
Third-party tools exist — Sensor Tower starts at $30K/year, AppFollow at $39/month with a 5-app limit. For an indie developer managing 12 apps, the economics don't work.
Connecting App Store Connect API
The first hurdle is authentication. ASC uses JWT tokens signed with an ES256 private key. You create an API key in App Store Connect, download a .p8 file, and use the Key ID + Issuer ID + private key to generate short-lived tokens.
We encrypt the private key with AES-256-GCM before storing it in the database. The key is only decrypted server-side when making API calls — it never touches the browser.
Parsing sales reports
Apple's Sales Report API returns gzipped TSV files, not JSON. Each row represents a product type + country + device combination for a single day. The vendor-level report includes all apps for the account — you must filter by Apple ID to isolate each app's data.
Product type identifiers determine what each row represents: 1/1F/1T for initial downloads, 3/3F/3T for re-downloads, 7/7F/7T for updates, IA for IAP, and separate subscription reports via the Subscription Summary endpoint.
The daily sync architecture
A Vercel Cron job runs every day at 3 AM KST (18:00 UTC). It dispatches sync tasks for each app using the after() pattern — the cron endpoint returns 200 immediately, then processes apps in the background. This avoids Vercel's function timeout.
Apple's sales data has a 1–2 day delay. Data for Monday typically becomes available Tuesday evening (KST). To handle this, we always re-fetch the last 3 days and upsert — if Apple revises the data, we automatically pick up the correction.
Download counting: matching ASC exactly
This tripped us up. ASC's "Sales > Units" chart shows only initial downloads — product types 1, 1F, and 1T. If you include re-downloads (type 3) or updates (type 7), your numbers won't match.
We define DOWNLOAD_TYPES = ['1', '1F', '1T'] and filter consistently across every query — dashboard, revenue page, weekly report, and alerts.
What we learned
Building this saved about 15 minutes every morning — time previously spent clicking through ASC tabs. But more importantly, having all 12 apps in one view surfaces patterns you'd never notice checking them individually. That's what led to the AI Growth Agent (our next post).