Usage
Use the Phase API to read analytics reports from your own scripts, dashboards, and backend services.
API keys are app-scoped and read-only.
Get your API key
- Sign in to Phase Dashboard.
- Create a new project or select an existing one.
- Open Application → API Keys.
- Copy your API key. Keys for this API start with
phase_public_. - Copy the App ID from the same screen. You need it in every request path.
Base URL
https://api.phase.sh/public-api/v1First request
curl "https://api.phase.sh/public-api/v1/apps/<app_id>/reports/events/overview" \
-H "Authorization: Bearer phase_public_your_key"const response = await fetch(
'https://api.phase.sh/public-api/v1/apps/<app_id>/reports/events/overview',
{
headers: {
Authorization: 'Bearer phase_public_your_key',
},
}
);
if (!response.ok) {
throw new Error(`Request failed with ${response.status}`);
}
const data = await response.json();
console.log(data);Example response
{
"totalEvents": 216,
"events24h": 0,
"totalEventsChange24h": 0,
"events24hChange": 0,
"meta": {
"generatedAt": "2026-04-06T15:02:52.814Z",
"consistency": "eventual",
"identityModel": "user"
}
}Request format
Path parameter
appId- Type:
string - Required: yes
- Value: the App ID shown in Application → API Keys
- Type:
Header
Authorization- Type:
string - Required: yes
- Format:
Bearer phase_public_your_key - Value: your API key
- Type:
Query parameters
-
startDate- Type:
string - Required: no
- Format: ISO 8601 timestamp
- Example:
2026-01-15T00:00:00.000Z - Used by: timeseries endpoints, date-filtered breakdown endpoints, and funnel endpoints
- Type:
-
endDate- Type:
string - Required: no
- Format: ISO 8601 timestamp
- Example:
2026-02-15T23:59:59.999Z - Used by: timeseries endpoints, date-filtered breakdown endpoints, and funnel endpoints
- Type:
-
metric- Type:
string - Required: no
- Used by: timeseries endpoints
- Allowed values depend on the endpoint:
- Sessions:
sessionCount,avgSessionDuration,bounceRate - Users:
activeUsers,totalUsers,newUsers
- Sessions:
- Type:
-
dimension- Type:
string - Required: no
- Used by: breakdown endpoints
- Allowed values depend on the endpoint:
- Events:
eventName,screenName - Sessions:
platform,country - Users:
platform,country
- Events:
- Type:
-
limit- Type:
number - Required: no
- Used by: breakdown endpoints
- Range:
1to50 - Default:
10
- Type:
The maximum supported date range is 365 days.
Events
Use event reports for headline counts, daily trends, and top events or screens.
Endpoints
-
GET /apps/:appId/reports/events/overview- Returns total events, 24h events, and change values.
-
GET /apps/:appId/reports/events/timeseries- Returns daily event counts.
- Supports
startDateandendDate.
-
GET /apps/:appId/reports/events/breakdown- Returns event counts grouped by
eventNameorscreenName. - Supports
dimension,startDate,endDate, andlimit.
- Returns event counts grouped by
Example: event breakdown
curl "https://api.phase.sh/public-api/v1/apps/<app_id>/reports/events/breakdown?dimension=eventName&startDate=2026-01-15T00:00:00.000Z&endDate=2026-02-15T23:59:59.999Z&limit=10" \
-H "Authorization: Bearer phase_public_your_key"const params = new URLSearchParams({
dimension: 'eventName',
startDate: '2026-01-15T00:00:00.000Z',
endDate: '2026-02-15T23:59:59.999Z',
limit: '10',
});
const response = await fetch(
`https://api.phase.sh/public-api/v1/apps/<app_id>/reports/events/breakdown?${params}`,
{
headers: {
Authorization: 'Bearer phase_public_your_key',
},
}
);
const data = await response.json();Sessions
Use session reports for totals, duration, bounce rate, and session distribution by platform or location.
Endpoints
-
GET /apps/:appId/reports/sessions/overview- Returns total sessions, active sessions, average session duration, and bounce rate.
-
GET /apps/:appId/reports/sessions/timeseries- Returns daily session metrics.
- Supported
metricvalues:sessionCount,avgSessionDuration,bounceRate. - Supports
startDate,endDate, andmetric.
-
GET /apps/:appId/reports/sessions/breakdown- Returns session counts grouped by
platformorcountry. - Supports
dimension,startDate,endDate, andlimit.
- Returns session counts grouped by
Example: session timeseries
curl "https://api.phase.sh/public-api/v1/apps/<app_id>/reports/sessions/timeseries?metric=sessionCount&startDate=2026-01-15T00:00:00.000Z&endDate=2026-02-15T23:59:59.999Z" \
-H "Authorization: Bearer phase_public_your_key"const params = new URLSearchParams({
metric: 'sessionCount',
startDate: '2026-01-15T00:00:00.000Z',
endDate: '2026-02-15T23:59:59.999Z',
});
const response = await fetch(
`https://api.phase.sh/public-api/v1/apps/<app_id>/reports/sessions/timeseries?${params}`,
{
headers: {
Authorization: 'Bearer phase_public_your_key',
},
}
);
const data = await response.json();Users
Use user reports for totals, active users, new users, and user distribution by platform or location.
Endpoints
-
GET /apps/:appId/reports/users/overview- Returns total users, active users, new users, and summary breakdowns.
-
GET /apps/:appId/reports/users/timeseries- Returns daily user metrics.
- Supported
metricvalues:activeUsers,totalUsers,newUsers. - Supports
startDate,endDate, andmetric.
-
GET /apps/:appId/reports/users/breakdown- Returns user counts grouped by
platformorcountry. - Supports
dimensionandlimit.
- Returns user counts grouped by
Example: user overview
curl "https://api.phase.sh/public-api/v1/apps/<app_id>/reports/users/overview" \
-H "Authorization: Bearer phase_public_your_key"const response = await fetch(
'https://api.phase.sh/public-api/v1/apps/<app_id>/reports/users/overview',
{
headers: {
Authorization: 'Bearer phase_public_your_key',
},
}
);
const data = await response.json();Funnels
Use funnel reports for activation conversion and saved custom funnels from the dashboard.
Endpoints
-
GET /apps/:appId/reports/funnels/activation- Returns the built-in activation funnel.
- Steps: First open → Total session ≥10m → Returned day 1 → Returned day 3.
- Supports
startDateandendDatefor the acquisition cohort.
-
GET /apps/:appId/reports/funnels- Lists saved custom funnels for the app.
- Returns funnel id, name, steps, and window hours.
-
GET /apps/:appId/reports/funnels/:funnelId- Runs a saved custom funnel and returns step conversion.
- Supports
startDateandendDate.
-
POST /apps/:appId/reports/funnels/run- Runs an ad-hoc funnel without saving it.
- Body:
steps, optionalwindowHours(default168), optionalstartDate/endDate. - Step kinds:
first_seen,session,session_30s,session_10m,engaged_10m,return_d1,return_d3,event. - Event steps require
name.
Example: activation funnel
curl "https://api.phase.sh/public-api/v1/apps/<app_id>/reports/funnels/activation?startDate=2026-01-15T00:00:00.000Z&endDate=2026-02-15T23:59:59.999Z" \
-H "Authorization: Bearer phase_public_your_key"const params = new URLSearchParams({
startDate: '2026-01-15T00:00:00.000Z',
endDate: '2026-02-15T23:59:59.999Z',
});
const response = await fetch(
`https://api.phase.sh/public-api/v1/apps/<app_id>/reports/funnels/activation?${params}`,
{
headers: {
Authorization: 'Bearer phase_public_your_key',
},
}
);
const data = await response.json();
console.log(data.overallConversion, data.steps);Example: run a custom funnel
curl "https://api.phase.sh/public-api/v1/apps/<app_id>/reports/funnels/run" \
-H "Authorization: Bearer phase_public_your_key" \
-H "Content-Type: application/json" \
-d '{
"windowHours": 168,
"steps": [
{ "kind": "first_seen" },
{ "kind": "session" },
{ "kind": "event", "name": "purchase_completed" }
]
}'const response = await fetch(
'https://api.phase.sh/public-api/v1/apps/<app_id>/reports/funnels/run',
{
method: 'POST',
headers: {
Authorization: 'Bearer phase_public_your_key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
windowHours: 168,
steps: [
{ kind: 'first_seen' },
{ kind: 'session' },
{ kind: 'event', name: 'purchase_completed' },
],
}),
}
);
const data = await response.json();Query
Run the same read-only SQL engine as Dashboard → Analytics → Query from your backend.
POST /apps/:appId/query- Body: JSON with
sqland optionalpage(default1) - Auth:
Authorization: Bearer phase_public_your_key
LIMIT in SQL sets page size (default 100 if omitted, max 50 on the API). Do not use OFFSET in SQL. Pass page to fetch the next slice. The response meta object includes hasNextPage, hasPreviousPage, offset, and pageSize.
Full table reference, time-range defaults, pagination, and examples are documented in Query.
Example: run a query
curl "https://api.phase.sh/public-api/v1/apps/<app_id>/query" \
-H "Authorization: Bearer phase_public_your_key" \
-H "Content-Type: application/json" \
-d '{
"sql": "SELECT name, count(*) AS events FROM events GROUP BY name ORDER BY events DESC LIMIT 20",
"page": 1
}'const response = await fetch(
'https://api.phase.sh/public-api/v1/apps/<app_id>/query',
{
method: 'POST',
headers: {
Authorization: 'Bearer phase_public_your_key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
sql: `SELECT name, count(*) AS events
FROM events
GROUP BY name
ORDER BY events DESC
LIMIT 20`,
page: 1,
}),
}
);
const data = await response.json();
console.log(data.result.columns, data.result.rows);
console.log(data.meta.hasNextPage);Example: paginate
let page = 1;
let hasNextPage = true;
while (hasNextPage) {
const response = await fetch(
'https://api.phase.sh/public-api/v1/apps/<app_id>/query',
{
method: 'POST',
headers: {
Authorization: 'Bearer phase_public_your_key',
'Content-Type': 'application/json',
},
body: JSON.stringify({ sql, page }),
}
);
const data = await response.json();
// process data.result.rows
hasNextPage = data.meta.hasNextPage;
page += 1;
}Response metadata
Every report response includes a meta object.
generatedAtis the server-side timestamp for the response.consistencyis currentlyeventual.identityModelis currentlyuser.
Security guidance
Do not use API keys in mobile apps, browser bundles, or any other untrusted client. Use them from your own backend, jobs, or internal tooling.