Analytics
Consent rates and traffic over time.
/v1/analytics/changesConsent-rate drops this week, with what else happened at the time
Week on week, per domain, for domains with enough decisions in both weeks to compare. Each drop names a publish or a newly seen tracker in the same window where there was one — a correlation, not a cause, and the wording says so.
Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.
| Status | Body | When |
|---|---|---|
| 200 | ConsentChangesDto |
| Field | Type | What it is |
|---|---|---|
| items required | ConsentChangeDto[] | Biggest drop first. Empty for a workspace where nothing moved, which is most weeks. |
| items[].domainId required | string | |
| items[].hostname required | string | |
| items[].current required | number | Accept rate this week and last, as whole percentages. |
| items[].previous required | number | |
| items[].deltaPct required | number | Negative for a drop, in whole percentage points. |
| items[].cause required | "unknown" | "publish" | "new_tracker" | What else happened in the same week: publish (a banner was published), new_tracker (a tracker was seen for the first time) or unknown (nothing we can name). |
| items[].causeDetail required | string | null | What happened in the same window, in a customer's words. |
| items[].causeAt required | string | null | |
| items[].summary required | string | The finding as one sentence — the same wording the digest email uses. |
| thresholdPct required | number | The drop, in percentage points, that has to be exceeded before a week is reported. |
/v1/analytics/geoConsent decisions by country
Explicit decisions only. Decisions with no country are returned as unknown rather than dropped, so the percentages can be read honestly.
Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.
| Name | Where | Type | What it is |
|---|---|---|---|
| range | query | "24h" | "7d" | "30d" | |
| domainId | query | string (uuid) |
| Status | Body | When |
|---|---|---|
| 200 | AnalyticsGeoDto |
| Field | Type | What it is |
|---|---|---|
| range required | "24h" | "7d" | "30d" | |
| located required | number | Decisions we could attribute to a country. |
| unknown required | number | Decisions with no country. Reported rather than hidden: consent geography drives which regime applies, so a reader has to know how much of the picture is missing before drawing a conclusion from the percentages. |
| countries required | CountryConsentDto[] | Descending by decisions. |
| countries[].iso required | string | ISO-3166-1 alpha-2, e.g. "DE". |
| countries[].name required | string | English country name, or the code itself when we do not have a name for it. |
| countries[].gdpr required | boolean | Whether GDPR / UK-GDPR applies here — drives the compliance framing, not the count. |
| countries[].decisions required | number | Explicit decisions from this country in the window. |
| countries[].acceptAll required | number | |
| countries[].rejectAll required | number | |
| countries[].custom required | number | |
| countries[].acceptRate required | number | accept-all / decisions (%). |
| countries[].share required | number | This country's share of all located decisions (%). |
/v1/analytics/summaryConsent figures for this workspace, or for one domain
Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.
| Name | Where | Type | What it is |
|---|---|---|---|
| range | query | "24h" | "7d" | "30d" | |
| domainId | query | string (uuid) |
| Status | Body | When |
|---|---|---|
| 200 | AnalyticsSummaryDto |
| Field | Type | What it is |
|---|---|---|
| range required | "24h" | "7d" | "30d" | |
| impressions required | number | Banner impressions (shown events) — the denominator. |
| decisions required | number | Total explicit decisions (accept/reject/custom). |
| acceptAll required | number | |
| rejectAll required | number | |
| custom required | number | |
| gpc required | number | Opt-outs the browser sent, not the visitor — Global Privacy Control. Counted here and nowhere else. A GPC opt-out is binding in California, Colorado and Connecticut and belongs on this screen, but it has no impression behind it: adding it to decisions would make the consent rate a fraction whose numerator the denominator cannot contain, and a site with enough GPC traffic would report more than a hundred per cent of its banners answered. |
| acceptRate required | number | accept-all ÷ decisions (%). Banner decisions only — see gpc. |
| consentRate required | number | decisions ÷ impressions (%) — how many shown banners got a choice. |
| categories required | CategoryOptInDto | |
| categories.analytics required | number | Opt-in rate (%) among decisions for each optional category. |
| categories.marketing required | number | |
| categories.preferences required | number |
/v1/analytics/timeseriesConsent metrics over time (zero-filled buckets)
Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.
| Name | Where | Type | What it is |
|---|---|---|---|
| range | query | "24h" | "7d" | "30d" | |
| domainId | query | string (uuid) |
| Status | Body | When |
|---|---|---|
| 200 | AnalyticsTimeseriesDto |
| Field | Type | What it is |
|---|---|---|
| range required | "24h" | "7d" | "30d" | |
| bucket required | "day" | "hour" | |
| points required | ConsentPointDto[] | |
| points[].t required | string | Bucket start, ISO-8601 (UTC). |
| points[].total required | number | Impressions in the bucket. |
| points[].accept required | number | |
| points[].reject required | number | |
| points[].custom required | number | |
| points[].rate required | number | accept-all ÷ decisions in the bucket (%). |
/v1/analytics/vitalsReal-user performance for one domain, day by day
The daily 75th percentile of LCP, INP and CLS as the site’s own visitors measured them, for up to 90 days, alongside our banner’s own CI-measured layout shift. Empty until the domain has real-user measurement switched on.
Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.
| Name | Where | Type | What it is |
|---|---|---|---|
| domainId required | query | string |
| Status | Body | When |
|---|---|---|
| 200 | WebVitalsDto |
| Field | Type | What it is |
|---|---|---|
| days required | WebVitalsDayDto[] | Oldest first, up to 90 days. Empty when the domain has no measurement switched on. |
| days[].day required | string | UTC day, ISO date. |
| days[].p75Lcp required | number | Largest Contentful Paint, milliseconds. |
| days[].p75Inp required | number | null | Interaction to Next Paint, milliseconds. Null where no browser reported one. |
| days[].p75Cls required | number | Cumulative Layout Shift. |
| days[].samples required | number | Page views this is computed from — a p75 over nine visits is noise. |
| latest required | WebVitalsDayDto | null | The latest complete day, or null when nothing has been rolled up yet. |
| latest.day required | string | UTC day, ISO date. |
| latest.p75Lcp required | number | Largest Contentful Paint, milliseconds. |
| latest.p75Inp required | number | null | Interaction to Next Paint, milliseconds. Null where no browser reported one. |
| latest.p75Cls required | number | Cumulative Layout Shift. |
| latest.samples required | number | Page views this is computed from — a p75 over nine visits is noise. |
| bannerCls required | number | Our own banner's contribution to layout shift, measured in CI on every build. Shown beside the site's own number because "did your banner do this?" is the question the chart exists to answer. |
Next groupPortfolio