Skip to content

drift/app-store-analytics

Repository files navigation

@drift/app-store-analytics

CI

Unified analytics client for App Store Connect and Google Play. Works with live APIs or CSV exports.

Install

pnpm add @drift/app-store-analytics

Quick start

CSV adapter (works immediately with your exports)

import { AppAnalyticsClient, CsvAdapter } from '@drift/app-store-analytics'

const adapter = await CsvAdapter.fromFile('./fixit-active_last_30_days.csv', 'ios', 'app-id', 'FIXiT')
console.log(adapter.getAvailableMetrics()) // ['active_devices']

const client = new AppAnalyticsClient()
client.registerAdapter(adapter)

const series = await client.getMetrics('ios', 'app-id', 'active_devices', {
  start: new Date('2026-01-01'),
  end: new Date('2026-06-30'),
})

App Store Connect API

Get credentials from App Store Connect → Users & Access → Integrations → App Store Connect API.

import { AppAnalyticsClient } from '@drift/app-store-analytics'
import { readFile } from 'node:fs/promises'

const client = new AppAnalyticsClient({
  appStoreConnect: {
    keyId: process.env.ASC_KEY_ID!,
    issuerId: process.env.ASC_ISSUER_ID!,
    privateKey: await readFile('./AuthKey_XXXXXX.p8', 'utf-8'),
  },
})

const apps = await client.getApps('ios')
const reviews = await client.getReviews('ios', apps[0].id, { limit: 50 })

Google Play

Create a service account in Google Cloud Console, grant it access in Play Console → Users & Permissions.

const client = new AppAnalyticsClient({
  googlePlay: {
    clientEmail: process.env.GOOGLE_CLIENT_EMAIL!,
    privateKey: process.env.GOOGLE_PRIVATE_KEY!,
  },
})

const reviews = await client.getReviews('android', 'nz.govt.wellington.fixit')

Caching

App Store Connect rate limits are strict. Opt into read-through caching with cache — an in-memory store with sensible per-method TTLs by default:

const client = new AppAnalyticsClient({
  appStoreConnect: { /* ... */ },
  cache: {}, // enables an in-memory cache (apps 24h, metrics 6h, reviews 30m, ratings 1h)
})

// Override TTLs, or plug in your own store (Redis, etc.)
const client2 = new AppAnalyticsClient({
  appStoreConnect: { /* ... */ },
  cache: { ttls: { metrics: 60 * 60_000 }, store: myRedisStore },
})

Errors are never cached, metric date-ranges are keyed by the day (so a moving "last 30 days" window still hits), and concurrent identical calls are coalesced into a single request. Implement the CacheStore interface to back it with anything — note that a serialising store loses Date types on revive.

Cross-platform

const summary = await client.getCrossPlatformSummary(
  { ios: 'ios-app-id', android: 'com.example.app' },
  ['installs', 'active_devices'],
  { start: new Date('2026-01-01'), end: new Date('2026-06-30') },
)

CLI

Quick terminal queries — works against CSV exports immediately, or the live APIs when credentials are set (env vars, or a .env in the working directory).

# Build once, then use the bin (or `pnpm cli -- <args>` in dev)
pnpm build

# Metric series from a CSV export
app-store-analytics metrics --csv ./active.csv --metric active_devices

# Reviews from the live App Store Connect API, one-star only
app-store-analytics reviews --app 1234567890 --rating 1

# Rating summary as JSON
app-store-analytics ratings --csv ./reviews.csv --json
FIXiT — active_devices  (ios)
2026-03-01 → 2026-06-30 · 4 points

  ▁▃▅█

  first   1100  (2026-03-01)
  latest  1500  (2026-06-30)
  peak    1500
  total   5100
  change  +36.4%

Run app-store-analytics help for the full flag list.

Web API + dashboard

The api/ directory holds Vercel serverless functions that wrap the library, and public/index.html is a self-contained dashboard. Deploy with zero config:

vercel --prod

Set ASC_KEY_ID / ASC_ISSUER_ID / ASC_PRIVATE_KEY and GOOGLE_CLIENT_EMAIL / GOOGLE_PRIVATE_KEY as project env vars for live data.

Endpoint Query
GET /api/metrics platform, app, metric, days (or start/end)
GET /api/reviews platform, app, limit?, rating?
GET /api/summary ios?, android?, metrics (csv), days

The dashboard calls these for live data and falls back to parsing CSV exports entirely in the browser when no credentials are configured — so it's useful even before you have API keys.

Metrics

Key App Store Connect Google Play
installs ✓ live (report-based) ✓ (Cloud Storage)
active_devices ✓ live (report-based) ✓ (Cloud Storage)
sessions ✓ live (report-based) ✓ (Cloud Storage)
crashes no data yet¹ via Vitals API
page_views ✓ live (report-based)
paying_users

App Store Connect metrics are live via the report-based pipeline. getMetrics discovers the app's ONGOING analytics report request, fetches DAILY instances, downloads gzipped TSV segments from S3, and aggregates rows by date. Report data has a ~24–48h provisioning delay per app — use pnpm asc:enable <appId> to create the ONGOING request if you haven't already. CSV exports remain the fallback for any metric without live instances yet.

Column → MetricKey mapping (verified from live data 2026-06-11):

Metric Report Column Filter
installs App Downloads Standard Counts Download Type = First-time download
sessions App Sessions Standard Sessions
active_devices App Sessions Standard Unique Devices
page_views App Store Discovery and Engagement Standard Counts Event = Page view
crashes App Crashes Crashes (assumed)

¹ crashes: the App Crashes report has no DAILY instances yet as of 2026-06-11 (report request created 2026-06-08). Will auto-enable once Apple provisions it. active_devices sums Unique Devices per row across dimensional combinations (source type, territory, etc.) — may slightly overcount the true unique total; this is the best available approximation from the report API.

Google Play rich metrics (installs, sessions, etc.) require a Cloud Storage linked account. Reviews and ratings work without it.

App Store Connect credentials

  1. Go to App Store Connect → Users and Access → Integrations → App Store Connect API
  2. Generate a new key (Admin role for full analytics access)
  3. Download the .p8 file — you can only download it once
  4. Note your Key ID and Issuer ID

Adding a custom adapter

import type { AnalyticsAdapter } from '@drift/app-store-analytics'

class MyAdapter implements AnalyticsAdapter {
  readonly platform = 'ios' as const
  // implement getApps, getMetrics, getReviews, getRatingSummary
}

client.registerAdapter(new MyAdapter())

About

Unified analytics client for App Store Connect and Google Play

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors