Skip to main content
Retrieve the cohort data of your app: users grouped by install date, then followed day by day (or week, or month) after install. The numbers are the same as the Cohorts view of the Appstack dashboard. For event-level rows, use the Export API.

Quick start

ROAS of October’s cohorts by media source:
ROAS curve from D0 to D30 (add up the rows from D0 to D7 for the D7 ROAS):
One of your own events, paywall_viewed: count, value and ROAS per day since install:
Weekly cohorts of Meta campaigns, in euros, as CSV:

Authentication

Every request must include an Authorization header containing your Appstack API key, as for the Export API.
Cohorts are built from production data only, whatever the environment of the key.

Endpoint

Query parameters

Cohorts

string
required
First install date (inclusive), YYYY-MM-DD.
string
required
Last install date (inclusive), YYYY-MM-DD. The range is capped at 366 days.
string
One cohort per install day, week (weeks start on Sunday) or month, returned in install_date. Without it, the whole date range is one cohort. Only installs between start_date and end_date count, so the first and last weeks or months can be partial.
string
One row per day, week or month since install, returned in days_since_install, weeks_since_install or months_since_install. Without it, you get the cohort totals.
integer
With period: stop at this period. period=day&max_period=30 returns D0 to D30.
string
Split the cohorts by media_source, campaign_name, adset_name, ad_name or keyword. Several values allowed. event_name is also accepted, to list your custom events.

Filters

string
Keep only these media sources, for example meta or organic.
string
Keep only these campaigns. adset_name, ad_name and keyword work the same way.
string
default:"USD"
Currency of spend, revenue and values, as an ISO 4217 code such as EUR. Amounts are converted with each day’s exchange rate.

Metrics and output

string
default:"installs,total_spend,cohort_revenue"
The metrics to return, one column each. See Measures.
string
default:"json"
json (default), ndjson, csv, tsv, xml, xlsx or parquet.
integer
default:"10000"
Maximum number of rows, between 1 and 10000.
integer
default:"0"
Rows to skip. Increase it by limit to get the next page; a page with fewer than limit rows is the last one.
To pass several values, repeat the parameter: group_by=media_source&group_by=campaign_name. measures, group_by and media_source also accept commas: group_by=media_source,campaign_name. campaign_name, adset_name, ad_name and keyword don’t, since names can contain commas.

Measures

How measures work: cohort totals vs. by period

You can query a cohort in two ways:
  • Cohort totals (no period): one value per cohort, covering everything since install.
  • By period (with period): one row per period since install (D0, D1, D2…), so you can build curves.
Installs and ad spend happen once, at install. They are always recorded on the install period (days_since_install = 0) and never on later periods. As a result, any measure that divides by or subtracts spend (CPI, ROAS, profit, cost per event) is only available on cohort totals. To get ROAS or profit by period, use the roas_of_* and profit_of_* measures.

Measures

Measures marked ✗ are rejected with a 422 when period is set.

Event measures

Every standard in-app event has three measures: The event name is prefixed with its source:

Custom events

Your own (non-standard) events don’t have fixed measure names. Query them with custom: followed by the event name, exactly as your app sends it: Server-to-server events keep their prefix: custom:s2s_paywall_viewed. Each one is its own column, so you can request several custom events in one call, next to any other measure: measures=installs,custom:paywall_viewed,custom:onboarding_start. An event name your app never sent returns null. Listing your custom events. Custom events also share a single set of measures per source: To choose which event these measures refer to:
  • All events side by side: add group_by=event_name. This is also how you list the event names available. Installs, spend and revenue have no event name: they come back on a separate row whose event_name is N/A.
  • One event: pass its name in event_name (only these measures are allowed with it).
If you set neither event_name nor group_by=event_name, these measures return the sum of all your custom events combined. custom: measures already pick their event, so they can’t be combined with event_name or group_by=event_name.

ROAS and profit by period

roas_of_<value measure> and profit_of_<value measure> compute ROAS and profit for a given value measure, matching the Cohorts view of the dashboard. Unlike roas and profit, they work with period, so use them to build ROAS or profit curves. How they are calculated
  • ROAS = value ÷ the cohort’s total ad spend.
  • Profit = value − the cohort’s total ad spend.
  • By period: each period’s ROAS is that period’s value divided by the cohort’s spend. Spend is subtracted from profit on the install period only. To get cumulative figures, sum the periods: D7 ROAS = ROAS of D0 + D1 + … + D7.
  • With group_by=event_name: each event is measured against the cohort’s whole spend, not a share of it.
  • Cohort without spend: ROAS is null.
Extra rows. If a group has no value on the install period (for example, an event first tracked on day 7), the response still adds an install-period row for it, so its profit includes the spend. A page can therefore contain slightly more rows than limit.
Missing periods. With period, a missing row means no value, not 0. Either nothing happened in that period, or the cohort hasn’t reached it yet (e.g. D30 for a cohort installed last week).
Finding measures. An unknown measure is rejected with a 422 that names it. To list every measure available to your app, use the MCP server’s list_metrics tool with view eac_cohorts_view.

Response

format=json returns a JSON object. The other formats return a file whose columns are, in order: install_date, the group_by dimensions, the period, then the measures. With period=day&group_by=media_source:
array
One row per cohort (and per period with period). install_date is the first day of the install day, week or month (2026-10-01T00:00:00.000). A measure with no value for the row is null.
integer
Number of rows in this page.

Errors

A 422 is returned when:
  • a date is missing or invalid, end_date is before start_date, or the range exceeds 366 days;
  • period, group_by, install_date_granularity, format or currency has an invalid value, or max_period is set without period;
  • a measure is unknown, or is marked ✗ in Measures while period is set;
  • roas_of_ or profit_of_ isn’t followed by a revenue or value measure;
  • a custom: measure has no event name, or is combined with event_name or group_by=event_name;
  • event_name is used with measures other than the custom event ones;
  • the request covers too many cohorts to compute roas_of_, profit_of_ or custom: measures (narrow the dates or the group_by);
  • limit or offset is out of range.
Last modified on November 10, 2026