Read API: overview
The same reports as in the dashboard, for scripts and exports, with a secret sk_ key.
The Read API returns the portfolio, audience, retention, realtime, profiles and integration health as JSON. These are the same endpoints the dashboard uses, so the numbers match the screens down to the last unit. The full list of parameters and schemas is in the API reference.
Base URL and key
The base URL is your installation's API; the examples use the placeholder
https://api.analytics.example.com. An sk_… key is created in Settings → API keys and is shown
only once: the server stores only its hash and prefix. Pass the key in a header:
export AM_SK="sk_…"
curl -sS https://api.analytics.example.com/v1/apps -H "Authorization: Bearer $AM_SK"Keys in the query string are not accepted. A pk_… write key doesn't work with the Read API.
| Key setting | What it grants |
|---|---|
scope read | All GET /v1/* |
scope delete | Creating data deletion requests (POST …/deletion-requests) |
| Bound to an app | The key sees only one app; the others respond with 404 app_not_found |
A revoked key stops working immediately.
Common report parameters
| Parameter | Value |
|---|---|
from, to | YYYY-MM-DD dates in the app's time zone, both inclusive; at most 366 days |
environment | production (default) or development |
unit | persons (default) for people, installs for installations, as in AppMetrica (see Identity) |
platform, app_version, os_name, country | Filters; a parameter can be repeated: values of one parameter are combined with OR, different parameters with AND |
compare | previous_period (default) adds a period of the same length before from; none means no comparison |
split | audience/timeseries only: platform returns a separate series for each platform of the period in splits[], and compare is ignored; none (default) returns a single series |
Example: an audience summary for a week for iOS versions 3.4.0 and 3.5.0:
curl -sS -G "https://api.analytics.example.com/v1/apps/$APP_ID/audience/summary" \
-H "Authorization: Bearer $AM_SK" \
--data-urlencode "from=2026-10-06" \
--data-urlencode "to=2026-10-12" \
--data-urlencode "platform=ios" \
--data-urlencode "app_version=3.4.0" \
--data-urlencode "app_version=3.5.0"{
"from": "2026-10-06",
"to": "2026-10-12",
"active": 41230,
"new": 8120,
"sessions": 201554,
"avg_duration_ms": 214500,
"median_duration_ms": 98000,
"compare": {
"from": "2026-09-29",
"to": "2026-10-05",
"active": 40102,
"new": 7998,
"sessions": 195020,
"avg_duration_ms": 209870,
"median_duration_ms": 96500,
"delta_pct": { "active": 2.81, "new": 1.53, "sessions": 3.35, "avg_duration_ms": 2.21, "median_duration_ms": 1.55 }
}
}Shares (retention, share) are numbers from 0 to 1, delta_pct is in percent and is null when
the base is zero. Times are in UTC, except for series bucket starts (ts, minute): those carry the
app's time zone offset so that day boundaries match the report.
Endpoints
| Endpoint | Returns |
|---|---|
GET /v1/apps | Apps; include_archived=true includes archived ones |
GET /v1/apps/{app_id} | A single app: platforms (platforms; the platform field is deprecated), time zone, status |
GET /v1/portfolio | Portfolio: DAU and its change vs. the same day last week, new users, sessions, D1, D7, a 30-day trend and the shares of active users by platform (platforms; the shares can add up to more than DAU) for each app |
GET /v1/apps/{app_id}/audience/summary | Active and new users, sessions, duration for the period |
GET /v1/apps/{app_id}/audience/timeseries | A metric series by hour, day, week or month; split=platform returns a series per platform |
GET /v1/apps/{app_id}/audience/rolling-active | DAU, WAU, MAU by day |
GET /v1/apps/{app_id}/audience/breakdown | Breakdown by platform, OS and its version, app version, device model and type, country, city, language |
GET /v1/apps/{app_id}/retention | Classic retention by daily and weekly cohorts |
GET /v1/apps/{app_id}/realtime | Active now and the latest events; platform filter |
GET /v1/apps/{app_id}/profiles | Search for people by exact user_id or install_id |
GET /v1/apps/{app_id}/profiles/{person_key} | Profile and session feed |
GET /v1/apps/{app_id}/integration/health | First event, accepted and rejected events by hour, rejection reasons, client versions |
POST /v1/apps/{app_id}/deletion-requests | Deleting a person's data (delete scope) |
GET /v1/apps/{app_id}/deletion-requests/{request_id} | Status of a deletion request (read or delete scope) |
Profile sessions are paginated with a cursor: sessions_limit (up to 500) and before, the
next_before value from the previous response. All other lists are returned in full.
Errors and limits
Errors come in an error envelope with code, message and request_id fields, as in ingest (see
Errors and retries).
| HTTP | Code | Reason |
|---|---|---|
| 400 | invalid_request | Invalid parameter; the field name is in details.field |
| 400 | range_too_large | The period is longer than 366 days, or longer than 7 days for granularity=hour |
| 401 | unauthenticated | No key, or the key is invalid or revoked |
| 403 | insufficient_scope | The key doesn't have the required scope |
| 404 | app_not_found | The app doesn't exist or the key isn't bound to it |
| 429 | rate_limited | More than 10 requests per second per key (short bursts up to 30); the response includes Retry-After |
| 503 | storage_unavailable | Storage is unavailable; the response includes Retry-After |
In the dashboard, every audience report has a Copy as Read API request button: it puts a ready-to-run curl command with the current period and filters on the clipboard.
Privacy and GDPR
What data is stored, for how long, and how to delete a user's data on request.
Ingest a batch of events (1..500) POST
Validates, enriches (geo, default context) and writes the events. Invalid events do not fail the batch: they are listed in `rejected`. The whole batch is rejected only on batch-level errors (400/401/403/413/415/429/503).