Query API
Last updated
The query API is a read-only API over your raw events and the same totals the dashboard shows. Use it to pull events into a script, a notebook or a BI tool, or to sync them on a schedule. It's on the Pro, Agency and Enterprise plans. For a full daily copy of every event, the warehouse export is usually a better fit.
Base URL and versions
https://app.metrickle.com/api/data/v1
Within v1, fields are only ever added, never removed or renamed. Anything that would break a client will be a new version. Every response carries a metrickle-api-version: 1 header.
Authentication
Send a workspace API token as a bearer token:
Authorization: Bearer mk_sk_…
Make one in the dashboard under Connect AI. See API tokens and permissions. A token needs:
data.export(Export raw events, with user ids and properties) for/events.analytics.read(See analytics, goals, funnels and protected tasks) for/summary,/timeseriesand/breakdown.
A token's Read only preset includes both, as long as your own role has them.
Every page of raw events you read is recorded in the workspace's audit log as Data exported.
Rate limits
About 120 requests a minute per token. Over the limit you get a 429 with retry-after: 60. Responses carry ratelimit-policy: 120;w=60.
Common parameters
| Parameter | Meaning |
|---|---|
from, to | The time range in Unix milliseconds, from from up to but not including to. Defaults to the last 30 days. At most about two years (732 days) |
filters | A URL-encoded JSON array of up to 10 filters, as in the dashboard: [{"field":"country","op":"eq","value":"NL"}] |
limit, cursor | Paging. Pass each response's next_cursor back as cursor until it's null. Cursors are opaque |
Each filter has a field, an op (eq, neq or contains) and a value (up to 512 characters). Fields are path, event, referrer_domain, utm_source, utm_medium, utm_campaign, country, device_type, os, browser, app_version, platform, a11y and survey. A survey filter matches visitors who answered a survey question: its value is campaignId|questionId|min|max for a score, or campaignId|questionId|=value for a choice.
Endpoints
GET /apps
The apps the token can read. Each has id, workspace_id, name, platform, timezone, data_api (whether the workspace's plan includes this API), can_read_events and can_read_aggregates.
GET /apps/{appId}/events
Raw events, oldest first. limit is 1 to 1,000 (default 100).
For incremental pulls, add received_from and received_to (Unix milliseconds) to get only events the server received in that window. Store the time you started each sync and pass it as received_from next time, so events that arrive late, such as from a phone that was offline, are still picked up.
{
"data": [
{
"app_id": "app_…", "id": "…", "ts": 1759536000000, "type": "track", "name": "checkout_completed",
"visitor_id": "u_42", "user_id": "42", "session_id": "…", "path": "/checkout", "url": "…", "title": "…",
"referrer": null, "referrer_domain": "google.com", "utm_source": null, "utm_medium": null, "utm_campaign": null,
"utm_term": null, "utm_content": null, "country": "NL", "region": "NH", "city": "Amsterdam", "platform": "web",
"device_type": "desktop", "os": "macOS", "browser": "Safari", "app_version": null, "screen_w": 1512, "screen_h": 982,
"locale": "en-GB", "value": 49, "a11y": ["keyboard"], "properties": { "plan": "pro" }, "received_at": 1759536000412
}
],
"next_cursor": "eyJ0cyI6…",
"has_more": true
}
idis unique within an app.valueis the event's revenue, when it has one.visitor_idisu_plus the user id once a device has been seen signed in. A person's earlier anonymous events move to that id over time, so re-read recent days if you need them joined up.
GET /apps/{appId}/summary
visitors, sessions, pageviews, events, bounceRate, avgSessionMs, conversions, conversionRate and revenue for the range (data), and for the same length of time just before it (previous). Rates are fractions from 0 to 1 and durations are milliseconds. The response also has range and previous_range.
GET /apps/{appId}/timeseries
The same measures in time buckets. interval is hour, day, week or month; without it, one is picked from the length of the range. hour works for ranges up to 31 days. tz is an offset from UTC in minutes, and defaults to the app's time zone. The response has data, interval, tz_offset_min and range.
GET /apps/{appId}/breakdown
The top values of one dimension, most visitors first. Dimensions are path, event, referrer_domain, utm_source, utm_medium, utm_campaign, country, device_type, os, browser, app_version, platform, entry_path, exit_path and a11y. limit is 1 to 500 (default 50), and you can page through up to 1,000 rows in all.
Errors
Errors are JSON: { "error": "<code>" }.
| Status | Code | Means |
|---|---|---|
400 | invalid_range, range_too_large, interval_too_small, invalid_filters, invalid_cursor, invalid_dimension, invalid_received_range | Fix the request |
401 | invalid_token | The token is unknown, revoked or expired |
402 | plan_lacks_data_out | The workspace's plan doesn't include the query API |
403 | forbidden, not_allowed_for_api_tokens | The token, or the person who made it, lacks the permission |
404 | not_found | No such app, or not one this token can see |
429 | rate_limited | Wait retry-after seconds |
What's included
The API returns only the event fields listed above: what the SDK sends, and what Metrickle works out from it, such as location, device, referrer domain and revenue. It never returns session replays, screenshots, feedback text, study participants' details or IP addresses, which Metrickle doesn't store. Form inputs are masked on the device before anything is sent.
Example: a nightly pull
FROM=$(($(date -u -d yesterday +%s) * 1000))
TO=$((FROM + 86400000))
cursor=""
while :; do
page=$(curl -sf -H "Authorization: Bearer $METRICKLE_TOKEN" \
"https://app.metrickle.com/api/data/v1/apps/$APP/events?from=$FROM&to=$TO&limit=1000${cursor:+&cursor=$cursor}")
echo "$page" | jq -c '.data[]' >> events.ndjson
cursor=$(echo "$page" | jq -r '.next_cursor // empty')
[ -z "$cursor" ] && break
done
For more than a few hundred thousand events a day, use the warehouse export.