Analytics

Analytics API reference

Report screen views, sessions and push opens over HTTP, and read the analytics aggregates back.

Base URL: https://app.nativenotify.com

The native-notify SDK calls the reporting endpoints for you. Call them yourself from custom clients such as web apps and backends.

Report screen views

POST /api/analytics/screen
{
  "appId": 123,
  "appToken": "yourAppToken",
  "screenName": "Home",
  "deviceId": "optional-stable-device-id",
  "token": "ExponentPushToken[...]",
  "subId": "optional-indie-sub-id"
}

Or batch 1 to 50 events per request:

{
  "appId": 123,
  "appToken": "yourAppToken",
  "events": [
    { "screenName": "Home", "deviceId": "optional-stable-device-id" },
    { "screenName": "Settings", "deviceId": "optional-stable-device-id" }
  ]
}
  • screenName is required per event and trimmed to 120 characters.
  • For unique views, send deviceId (best), subId or token. With none, the view counts toward totals only. In a batch, put them inside each event: top-level device keys are ignored.
  • Answers 201 {"ok": true, "accepted": N}, 400 for missing or invalid fields, 401 for a bad app token.

Report sessions

POST /api/analytics/session
{
  "appId": 123,
  "appToken": "yourAppToken",
  "sessionId": "unique-session-id",
  "durationMs": 45000,
  "deviceId": "optional-stable-device-id"
}

sessionId is required and deduplicated per app, so the same id counts once. Longer ids are cut to 80 characters, and durationMs is clamped to 24 hours. Answers 201 {"ok": true}, or 400 {"error": "sessionId is required"}.

Report notification opens

POST /api/notification/opened
{
  "appId": 123,
  "appToken": "yourAppToken",
  "notification_id": "1000000412",
  "deviceId": "optional-stable-device-id"
}

notification_id is the nn_notification_id the push carried. Every report adds to opened. A deviceId (or subId / token) also counts it toward opened_unique, once per device. Answers 201 {"ok": true}, 400 when appId, appToken or notification_id is missing, and 404 {"error": "Notification not found for this app"} for an id this app never sent.

Read aggregates

GET with the app credentials in the path. Out-of-range values are clamped (days to 1–365).

EndpointQueryReturns
/api/analytics/summary/:appId/:appTokendays (default 30)Growth and a daily series, below
/api/analytics/screens/:appId/:appTokendays (default 30), limit (1–25, default 10)screens: [{ screen_name, total_views, unique_views, series: [{ day, total, unique_views }] }], ranked by total views. unique_views counts distinct devices across the range.
/api/analytics/retention/:appId/:appTokenweeks (1–52, default 8)cohorts: weekly cohorts by first-activity week, each with size and per-week week, users, pct
/api/analytics/best-times/:appId/:appTokendays (default 90)cells: [{ dow, hour, opened }] (0 = Sunday, hours in UTC), and the total opens
/api/notification/failures/:appId/:appTokendays (default 30)errors: [{ error_code, count, last_seen }] from Expo receipt errors (DeviceNotRegistered, InvalidCredentials, …) and push API transport codes (APNs:*, FCM:*, WebPush:*)
/api/notification/stats/:appId/:appTokentake (default 10), skipPer-notification rollup, below
/api/analytics/export/:appId/:appTokentype, days (default 30)A text/csv download, below

Summary

{
  "days": 30,
  "seriesSource": "live",
  "current": { "dau": 120, "wau": 480, "mau": 1300, "newUsers": 210, "returningUsers": 1090, "sessions": 5400, "avgSessionMs": 64000, "stickiness": 0.09 },
  "previous": { "dau": 110, "wau": 450, "mau": 1250, "sessions": 5100 },
  "growth": { "dau": 9.1, "wau": 6.7, "mau": 4, "sessions": 5.9 },
  "series": [{ "day": "2026-10-01", "dau": 118, "wau": 470, "mau": 1290, "newUsers": 7, "returningUsers": 111, "sessions": 180, "avgSessionMs": 61000 }]
}

In current, dau, wau and mau are rolling 1, 7 and 30 days, newUsers and returningUsers cover the trailing days, and stickiness is DAU ÷ MAU. previous is one period earlier, and growth is its percent change, null with no baseline. seriesSource is "live" (from raw activity, days ≤ 90) or "rollup" (the nightly rollup, for longer ranges).

Per-notification stats

Rows are most recently updated first, with the total in the X-Total-Count header. Each has notification_id, source ("mass", "indie" or "universal"), accepted, delivered, failed, opened, opened_unique, first_opened_at, last_opened_at, updated_at, date and title.

CSV export

An unknown type falls back to summary.

typeColumns
summary (default)day, dau, wau, mau, new_users, returning_users, sessions, avg_session_seconds. At most the last 90 days, whatever days asks for.
screensscreen_name, day, total_views, unique_views
sendsnotification_id, source, date, title, accepted, delivered, failed, opened, opened_unique. Mass, individual and push API sends, at most 1000 rows.