The Tracking area publishes 45 REST endpoints. Paths are relative to https://api.lepsto.com; see Authentication for the required header.
GET/tracking/catalog
List the event-name catalog for the current product with counts, first/last seen, sampled prop keys, and status.
MCP tool: tracking_event-names_list
Parameters
| Name | In | Type | Required | Description |
|---|
status | query | stringone of: active, archived
| — | Filter by status; omit for all |
search | query | string
| — | Case-insensitive substring match on the event name |
sort | query | stringone of: count, last_seen, first_seen, name
| — | Sort column (default count) |
order | query | stringone of: asc, desc
| — | Sort direction (default desc) |
Response
Returns object.
| Field | Type | Always | Description |
|---|
names | object[]
| • | The matching catalogue entries, ordered by the requested sort |
POST/tracking/catalog/archive
Archive an event name (hides it from dashboards only; ingestion and counts continue unchanged).
MCP tool: tracking_event-names_archive
Parameters
| Name | In | Type | Required | Description |
|---|
name | body | string
| • | The event name to archive/unarchive |
Response
Returns object.
| Field | Type | Always | Description |
|---|
name | string
| • | Event name whose status was changed |
status | stringone of: active, archived
| • | The status as it now stands: `archived` hides the name from pickers and reports, `active` restores it |
POST/tracking/catalog/set-conversion
Mark an event name as a conversion, or unmark it. A marked name publishes `tracking/conversion.recorded` every time that event is recorded, which a workflow can trigger on; an unmarked one publishes nothing. Ingestion, counts and dashboards are unchanged either way.
MCP tool: tracking_event-names_set-conversion
Parameters
| Name | In | Type | Required | Description |
|---|
name | body | string
| • | The event name to mark or unmark |
isConversion | body | boolean
| • | true makes this event name a workflow trigger; false stops it being one |
Response
Returns object.
| Field | Type | Always | Description |
|---|
name | string
| • | Event name the conversion flag was applied to |
isConversion | boolean
| • | The flag as it now stands after the change |
POST/tracking/catalog/unarchive
Unarchive an event name (restores its visibility in dashboards).
MCP tool: tracking_event-names_unarchive
Parameters
| Name | In | Type | Required | Description |
|---|
name | body | string
| • | The event name to archive/unarchive |
Response
Returns object.
| Field | Type | Always | Description |
|---|
name | string
| • | Event name whose status was changed |
status | stringone of: active, archived
| • | The status as it now stands: `archived` hides the name from pickers and reports, `active` restores it |
GET/tracking/domains
List the product's custom domains and tracking-host bindings
MCP tool: tracking_domains_list
Parameters
No parameters.
Response
Returns object.
| Field | Type | Always | Description |
|---|
domains | object[]
| • | The product's domains as the platform vouches for them — the set a new tracking host may be claimed under |
bindings | object[]
| • | Tracking-host bindings this toolkit currently holds across those domains |
POST/tracking/domains
Claim a first-party tracking host under a product domain
MCP tool: tracking_domains_create
Parameters
| Name | In | Type | Required | Description |
|---|
domainId | body | string
| • | Product domain to claim the tracking host under, as listed in `domains[].domainId` by tracking_domains_list |
host | body | string
| — | Bare hostname to serve tracking from, which must sit under the chosen domain (e.g. analytics.example.com); a suggestion is used when omitted |
records | body | object[]
| — | DNS records to request instead of the default CNAME to the tracking edge; leave unset unless the domain needs custom records |
Response
Returns object.
| Field | Type | Always | Description |
|---|
binding | object
| • | The binding as just claimed; it starts `pending` and goes `active` once the DNS is observed live |
instructions | string[]
| • | Ordered, human-readable steps for publishing the DNS the claim needs; empty when the platform manages the domain itself |
DELETE/tracking/domains/:bindingId
Release a tracking-host binding
MCP tool: tracking_domains_delete
Parameters
| Name | In | Type | Required | Description |
|---|
bindingId | path | string
| • | Id of the tracking-host binding to act on, as returned in `bindings[].bindingId` by tracking_domains_list |
Response
Returns object.
| Field | Type | Always | Description |
|---|
ok | booleanone of: true
| • | Always true — the release succeeded; a failure arrives as an error, not as false |
GET/tracking/domains/:bindingId
Get one tracking-host binding and its status
MCP tool: tracking_domains_get
Parameters
| Name | In | Type | Required | Description |
|---|
bindingId | path | string
| • | Id of the tracking-host binding to act on, as returned in `bindings[].bindingId` by tracking_domains_list |
Response
Returns object.
| Field | Type | Always | Description |
|---|
host | string
| • | Fully-qualified tracking host this binding serves, e.g. analytics.example.com |
status | stringone of: pending, active, failed
| • | Where the claim stands: `pending` while DNS has not been observed live, `active` once it serves, `failed` when the check gave up |
records | array
| • | DNS records the platform expects to see published for this host, as returned when the binding was claimed |
domainId | string
| • | Product domain this tracking host sits under |
bindingId | string
| • | Id of the tracking-host binding to act on, as returned in `bindings[].bindingId` by tracking_domains_list |
createdAt | string (date-time)
| • | When the binding was claimed |
productId | string
| • | Product the binding belongs to |
updatedAt | string (date-time)
| • | When the binding last changed status or records |
statusDetail | string | null
| • | Human-readable reason behind the current status, such as the DNS error that made it fail; null while there is nothing to report |
ownerExtension | string
| • | Extension that claimed the binding; tracking bindings are owned by this toolkit |
POST/tracking/domains/:bindingId/verify
Run an immediate liveness check for a pending binding
MCP tool: tracking_domains_verify
Parameters
| Name | In | Type | Required | Description |
|---|
bindingId | path | string
| • | Id of the tracking-host binding to act on, as returned in `bindings[].bindingId` by tracking_domains_list |
Response
Returns object.
| Field | Type | Always | Description |
|---|
host | string
| • | Fully-qualified tracking host this binding serves, e.g. analytics.example.com |
status | stringone of: pending, active, failed
| • | Where the claim stands: `pending` while DNS has not been observed live, `active` once it serves, `failed` when the check gave up |
records | array
| • | DNS records the platform expects to see published for this host, as returned when the binding was claimed |
domainId | string
| • | Product domain this tracking host sits under |
bindingId | string
| • | Id of the tracking-host binding to act on, as returned in `bindings[].bindingId` by tracking_domains_list |
createdAt | string (date-time)
| • | When the binding was claimed |
productId | string
| • | Product the binding belongs to |
updatedAt | string (date-time)
| • | When the binding last changed status or records |
statusDetail | string | null
| • | Human-readable reason behind the current status, such as the DNS error that made it fail; null while there is nothing to report |
ownerExtension | string
| • | Extension that claimed the binding; tracking bindings are owned by this toolkit |
GET/tracking/entitlement-drops/current
Report the /collect events and session recordings this product lost this UTC month because billing refused to store them (trial monthly limit reached, billing paused). Counts events that were never stored; tracking_reports_event_volume counts the events that were. Returns: { month, drops: { droppedEvents, droppedBatches, droppedRecordings, firstDroppedAt, lastDroppedAt, lastReason, upgradeUrl, plan } | null }. Fails when: the call carries no product.
MCP tool: tracking_entitlement-drops_get
Parameters
No parameters.
Response
Returns object.
| Field | Type | Always | Description |
|---|
drops | object | null
| • | Null when no event and no session recording was refused this month. |
month | string
| • | First day of the current UTC month the figures cover, YYYY-MM-DD, e.g. 2026-09-01. |
GET/tracking/googleads/connection
Google Ads connection status for the current product: whether a Google Ads account is connected and which account (loginCustomerId / customerId), or whether it still needs account selection or re-auth.
MCP tool: tracking_googleads_connection_status
Parameters
No parameters.
Response
Returns object.
GET/tracking/googleads/feedback/config
Get the Google Ads conversion-feedback config for the current product (enabled, mode, lookbackDays, event→conversion-action rules, accountCurrency — the connected account's currency, best-effort, null if unavailable — useful for defaulting a fixed-value rule's currency, and dynamicValueEvents — the revenue-eligible event-names that may use the Dynamic value source).
MCP tool: tracking_googleads_feedback_config_get
Parameters
No parameters.
Response
Returns object.
| Field | Type | Always | Description |
|---|
mode | stringone of: existing_pixel, fresh_pixel
| • | How the uploads coexist with the account's own tag: existing_pixel means the Google tag also records these conversions, so send only to actions the tag does not already cover; fresh_pixel means these uploads are the only source. |
rules | object[]
| • | Which tracked events become which Google Ads conversion action, and where each one takes its money value from. Disabled rules stay listed. |
enabled | boolean
| • | Whether conversions are being sent to Google Ads at all. False leaves every rule below in place but uploads nothing. |
productId | string
| • | The tenant this configuration belongs to. Never supplied by a caller — it comes from the authenticated identity. |
lookbackDays | number
| • | How many days back each pass looks for conversions to send, and how far back a click may be matched. Google rejects clicks older than about 90 days. |
accountCurrency | string | null
| • | Currency of the connected Google Ads account, as a three-letter ISO 4217 code such as EUR. Null when the account could not be read. |
dynamicValueEvents | string[]
| • | The event names that may use the Dynamic value source, because revenue is known for them. Any other event needs a fixed amount. |
enhancedConversions | boolean
| • | Whether a stored email or phone number is sent alongside the click, so Google can match conversions the click id alone would miss. |
POST/tracking/googleads/feedback/config
Set the Google Ads conversion-feedback config (enable/disable, mode, lookback, rules, enhancedConversions). enhancedConversions adds hashed email/phone as additive match keys alongside gclid. Returns the config plus safety guidance. Rules are validated against the account's conversion actions.
MCP tool: tracking_googleads_feedback_config_set
Parameters
| Name | In | Type | Required | Description |
|---|
enabled | body | boolean
| — | Master switch for conversion feedback (default off) |
mode | body | stringone of: existing_pixel, fresh_pixel
| — | existing_pixel = fill gaps; fresh_pixel = our data only |
lookbackDays | body | integer
| — | Click lookback window for gclid match (<=90) |
rules | body | object[]
| — | Map a tracked event to a Google conversion action with a per-rule value (net revenue or a fixed amount) |
enhancedConversions | body | boolean
| — | Enhanced conversions: also send hashed email/phone as additive match keys alongside gclid (default off) |
Response
Returns object.
| Field | Type | Always | Description |
|---|
config | object
| • | The config as it now stands after the write, with server-side normalisation applied |
guidance | string[]
| • | Plain-language safety notes about what this combination of mode and match keys will do to the connected account |
GET/tracking/googleads/feedback/conversion-actions
List the connected Google Ads account's conversion actions (resource, name, category, status) so you can map a tracked event to a Google conversion action with a per-rule value (net revenue or a fixed amount).
MCP tool: tracking_googleads_conversion_actions
Parameters
No parameters.
Response
Returns object[].
| Item field | Type | Always | Description |
|---|
id | string
| • | — |
name | string
| • | — |
status | string
| • | — |
category | string
| • | — |
resourceName | string
| • | — |
POST/tracking/googleads/feedback/run
Manually run one conversion-feedback upload pass for the current product now (uploads newly-attributed conversions across all enabled rules since the last run). Useful for testing; the daily cron runs this automatically.
MCP tool: tracking_googleads_feedback_run
Parameters
No parameters.
Response
Returns object.
| Field | Type | Always | Description |
|---|
runId | string
| • | This one upload pass. Match the completion event back to this step on it, not on productId: the daily cron pass and a manual run on the same day are two passes of the same product. |
failed | number
| • | Rows Google rejected in this pass. |
matched | number
| • | Of those, the ones that had a usable click id and a value, so a payload was actually built for them. |
noGclid | number
| • | Conversions dropped because no Google click could be tied to the person. A high count here is a tagging problem, not a Google one. |
skipped | stringone of: disabled, no_rules, not_connected
| — | Present only when the pass did no work, and says why: feedback is switched off, no rule is enabled, or no Google Ads account is connected. Absent on a pass that ran. |
selected | number
| • | Conversions in the lookback window that an enabled rule applied to. |
uploaded | number
| • | Rows Google accepted in this pass. |
productId | string
| • | The tenant whose conversions this pass uploaded. |
zeroValue | number
| • | Conversions held back because their money value had not landed yet. They are retried on a later pass. |
partialFailureError | string
| — | Google's own rejection detail, passed through unchanged, when it refused part of the batch. Absent when it accepted everything. |
GET/tracking/googleads/feedback/status
Google Ads conversion-feedback status for the current product: enabled/mode, rule count, cumulative uploaded/failed counts, last-run coverage (selected vs matched vs uploaded, plus noGclid so gclid-match coverage is visible), safety guidance, accountCurrency (the connected account's currency, best-effort, null if unavailable), and dynamicValueEvents (the revenue-eligible event-names that may use the Dynamic value source).
MCP tool: tracking_googleads_feedback_status
Parameters
No parameters.
Response
Returns object.
| Field | Type | Always | Description |
|---|
mode | stringone of: existing_pixel, fresh_pixel
| • | How the uploads coexist with the account's own tag: existing_pixel means the Google tag also records these conversions; fresh_pixel means these uploads are the only source. |
failed | number
| • | Rows Google has rejected since this product was connected, across every pass. |
enabled | boolean
| • | Whether conversions are being sent to Google Ads at all. |
lastRun | object | null
| • | Coverage of the most recent pass. Null when no pass has run for this product yet. |
guidance | string[]
| • | Plain-language warnings about the current setup, such as double counting when the Google tag already records the same conversion. Empty when nothing needs saying. |
uploaded | number
| • | Rows Google has accepted since this product was connected, across every pass. |
ruleCount | number
| • | How many event-to-conversion-action rules are configured, enabled or not. |
lookbackDays | number
| • | How many days back each pass looks for conversions to send, and how far back a click may be matched. |
accountCurrency | string | null
| • | Currency of the connected Google Ads account, as a three-letter ISO 4217 code such as EUR. Null when the account could not be read. |
dynamicValueEvents | string[]
| • | The event names that may use the Dynamic value source, because revenue is known for them. |
enhancedConversions | boolean
| • | Whether a stored email or phone number is sent alongside the click, so Google can match conversions the click id alone would miss. |
GET/tracking/googleads/feedback/uploads
List the most recent Google Ads offline-conversion uploads for the current product (per-row ledger: conversionKey, gclid, conversionAction, conversionDatetime, valueMicros, currency, orderId, status, error, uploadedAt). Newest first. Query: limit (default 100, max 500).
MCP tool: tracking_googleads_feedback_uploads
Parameters
| Name | In | Type | Required | Description |
|---|
limit | query | integer
| — | — |
Response
Returns object[].
| Item field | Type | Always | Description |
|---|
error | string | null
| • | — |
gclid | string
| • | — |
status | string
| • | — |
orderId | string
| • | — |
currency | string
| • | — |
uploadedAt | string
| • | — |
valueMicros | number
| • | — |
conversionKey | string
| • | — |
conversionAction | string
| • | — |
conversionDatetime | string
| • | — |
GET/tracking/googleads/reports/roas
Reads what each Google Ads campaign cost and what it earned back, with ad groups and ads nested underneath. Return on ad spend and cost per customer are worked out at campaign level from the revenue we traced ourselves; spend, impressions, clicks and Google's own conversion counts are there at every level. Each account currency is reported separately and never added to another. Covers the last 30 days unless a window is given.
MCP tool: tracking_googleads_roas_report
Parameters
| Name | In | Type | Required | Description |
|---|
from | query | string (date-time)
| — | Start of the reporting window, inclusive. ISO-8601 date or timestamp, e.g. 2026-01-01. Omit to start 30 days before the end of the window. |
to | query | string (date-time)
| — | End of the reporting window, inclusive. ISO-8601 date or timestamp; a date-only value covers that whole day, so revenue after midnight is not cut off. Omit to end now. |
model | query | stringone of: last_click, first_click
| — | Which touchpoint gets the credit for a conversion: the last paid click before it, or the first. Defaults to last_click. |
lookbackDays | query | integer
| — | How far back before a conversion a paid click may sit and still earn the credit, in days. 1-365, silently clamped into that range; defaults to 30. |
domain | query | string
| — | Restrict to conversions tracked on this installed site, e.g. acme.com. Omit to cover every domain of the product. |
customerId | query | string
| — | Restrict to one Google Ads account, by its customer id without dashes. Omit to cover every connected account. |
Response
Returns object.
| Field | Type | Always | Description |
|---|
to | string (date-time)
| • | End of the window this report covers, echoed back as an ISO-8601 UTC timestamp. |
from | string (date-time)
| • | Start of the window this report covers, echoed back as an ISO-8601 UTC timestamp. |
model | stringone of: last_click, first_click
| • | Which touchpoint earned the credit in these numbers: the last paid click before the conversion, or the first. |
stale | boolean
| • | True when any account below is running on cost older than the freshness threshold, or on no cost at all — read this before acting on the numbers. |
domain | string | null
| • | The installed site this report was restricted to; null when it covers every domain of the product. |
accounts | object[]
| • | One entry per Google Ads account and currency. Kept apart on purpose: amounts in different currencies are never added together. |
currency | string | null
| • | ISO-4217 code every amount in this report is expressed in, when all accounts share one; null when the report spans several currencies. |
computedAt | string (date-time)
| • | When this report was calculated (ISO-8601 UTC). The figures are a snapshot at this moment, not live. |
customerId | string | null
| • | Google Ads account this whole report covers, when it covers exactly one; null when it spans several accounts. |
lookbackDays | number
| • | How far back before a conversion a paid click was allowed to sit and still earn the credit, in days. |
costLastSyncedAt | string (date-time) | null
| • | Oldest moment cost was pulled from Google Ads across the accounts below (ISO-8601 UTC); null when any account has never synced. |
unmatchedAttributed | object[]
| • | Revenue we tracked but could not tie to any Google Ads campaign, grouped by the utm_campaign we saw. A long list here means the ad tagging needs fixing, not that the ads failed. |
GET/tracking/googleads/reports/us-vs-platform
Puts our own revenue and customer counts beside the conversions Google reports, one row per campaign, so the gap between the two is visible. Both sides stay in the account currency and are never converted. Use it to decide which number to trust before acting on either. Covers the last 30 days unless a window is given.
MCP tool: tracking_googleads_us_vs_platform
Parameters
| Name | In | Type | Required | Description |
|---|
from | query | string (date-time)
| — | Start of the reporting window, inclusive. ISO-8601 date or timestamp, e.g. 2026-01-01. Omit to start 30 days before the end of the window. |
to | query | string (date-time)
| — | End of the reporting window, inclusive. ISO-8601 date or timestamp; a date-only value covers that whole day, so revenue after midnight is not cut off. Omit to end now. |
model | query | stringone of: last_click, first_click
| — | Which touchpoint gets the credit for a conversion: the last paid click before it, or the first. Defaults to last_click. |
lookbackDays | query | integer
| — | How far back before a conversion a paid click may sit and still earn the credit, in days. 1-365, silently clamped into that range; defaults to 30. |
domain | query | string
| — | Restrict to conversions tracked on this installed site, e.g. acme.com. Omit to cover every domain of the product. |
customerId | query | string
| — | Restrict to one Google Ads account, by its customer id without dashes. Omit to cover every connected account. |
Response
Returns object.
| Field | Type | Always | Description |
|---|
to | string (date-time)
| • | End of the window this comparison covers, echoed back as an ISO-8601 UTC timestamp. |
from | string (date-time)
| • | Start of the window this comparison covers, echoed back as an ISO-8601 UTC timestamp. |
model | stringone of: last_click, first_click
| • | Which touchpoint earned the credit on OUR side of the comparison: the last paid click before the conversion, or the first. Google always uses its own model. |
stale | boolean
| • | True when any account below is running on cost older than the freshness threshold, or on no cost at all — read this before acting on the numbers. |
domain | string | null
| • | The installed site this comparison was restricted to; null when it covers every domain of the product. |
accounts | object[]
| • | One entry per Google Ads account and currency, each holding its per-campaign comparison rows. Currencies are never added together. |
currency | string | null
| • | ISO-4217 code every amount in this report is expressed in, when all accounts share one; null when the report spans several currencies. |
computedAt | string (date-time)
| • | When this comparison was calculated (ISO-8601 UTC). The figures are a snapshot at this moment, not live. |
customerId | string | null
| • | Google Ads account this whole report covers, when it covers exactly one; null when it spans several accounts. |
lookbackDays | number
| • | How far back before a conversion a paid click was allowed to sit and still earn the credit on our side, in days. |
costLastSyncedAt | string (date-time) | null
| • | Oldest moment cost was pulled from Google Ads across the accounts below (ISO-8601 UTC); null when any account has never synced. |
POST/tracking/googleads/sync
Pull the current product's Google Ads campaign/ad-group/ad structure and daily spend/metrics into the reporting tables now (backfill window). Returns per-table row counts. Skips gracefully if the account is pending selection or needs re-auth.
MCP tool: tracking_googleads_sync_now
Parameters
No parameters.
Response
Returns object.
| Field | Type | Always | Description |
|---|
rows | object
| • | How much this sweep wrote, split by what it wrote. Re-running the same window updates rows in place rather than adding, so these are rows touched, not rows gained. All zero when the status is skipped. |
runId | string
| • | This one sync run. Match the completion event back to this step on it, not on productId: a product syncs many times, and the daily cron run and a manual one are different runs. |
reason | string
| — | Why nothing was written, when the status is skipped: the account is not chosen yet, the authorisation expired, or Google was unavailable. Absent on a sweep that ran. |
status | stringone of: ok, skipped
| • | Whether the sweep ran. skipped means the Google Ads account could not be reached and nothing at all was written. |
window | object
| • | The range of days this sweep read spend and metrics for. |
productId | string
| • | The tenant whose Google Ads account was swept. |
lastSyncedAt | string (date-time) | null
| • | When the sweep finished. Null when nothing was written. |
GET/tracking/googleads/tracking-health
Google Ads URL-tracking health for the current product over a date range: how many Google paid clicks arrived, how many carried our ValueTrack URL parameters (marker _lt_campaign) vs how many were UNTAGGED (template not installed / broken), the breakage rate, whether the template is verified live, first/last untagged times, sample offending landing URLs. Read-only; computed on the fly from stored events (no Google Ads API call). dataQuality describes how complete the figures above are and holds no metric of its own: dataQuality.cookielessPaidClicks is how many of the paid clicks arrived cookieless (the visitor declined consent) — counted INSIDE paidClicks, never added to it, because a cookieless paid click is a real click and belongs in the breakage denominator. It is broken out so breakageRate is not read as one homogeneous population. Clicks from sites running no consent banner at all are NOT counted as cookieless: nobody was ever asked there, which is not the same as being told no.
MCP tool: tracking_googleads_tracking_health
Parameters
| Name | In | Type | Required | Description |
|---|
from | query | string (date-time)
| — | Range start (ISO); defaults to 30 days ago |
to | query | string (date-time)
| — | Range end (ISO); defaults to now |
Response
Returns object.
| Field | Type | Always | Description |
|---|
to | string (date-time)
| • | End of the range these figures cover, as an instant. |
from | string (date-time)
| • | Start of the range these figures cover, as an instant. Echoes back the range that was asked for. |
installed | boolean
| • | Whether the tracking template has been seen working live: true once at least one tagged click has arrived. |
truncated | boolean
| • | Whether the sample above was cut short. True means more untagged URLs exist than are listed. |
paidClicks | number
| • | Google paid clicks that arrived on the site in this range. The denominator for everything below. |
dataQuality | object
| • | How complete the figures above are. Holds no metric of its own — it exists so the breakage rate is not read as one uniform population. |
breakageRate | number
| • | Share of paid clicks that arrived untagged, between 0 and 1. Anything much above zero means the tracking template needs fixing. |
taggedClicks | number
| • | Of those, the ones that arrived carrying our URL tracking parameters, so the campaign behind them is known. |
lastUntaggedAt | string (date-time) | null
| • | When the most recent untagged click arrived. Close to now means the breakage is still live. Null when none did. |
untaggedClicks | number
| • | Of those, the ones that arrived without our parameters, so the money spent on them cannot be attributed. This is what the tracking template being missing or broken looks like. |
firstUntaggedAt | string (date-time) | null
| • | When the first untagged click of the range arrived — roughly when the breakage started. Null when none did. |
sampleUntaggedUrls | string[]
| • | A handful of the actual landing URLs that arrived untagged, to paste into a browser while fixing the template. Real customer URLs, query strings included. |
GET/tracking/heatmaps/page
Get the heatmap of one page for one device: where visitors clicked (per element, on a 50x50 grid inside it), how far they scrolled, and which recording to draw the page from. sessions counts the recordings of the period and filters with a click or a scroll sample on the page — the same recordings tracking_recordings_list returns with the same device, campaign, source and conversion filters. scroll.reached[i] is a share of the sessions that reported a scroll depth on the page (a click-only session reports none), reaching (i+1)*5% of its height. Below 10 sessions the map is withheld: belowThreshold is true, clicks and scroll.reached are empty. Returns: { sessions, belowThreshold, clicks, scroll, background }. Fails when: the period is longer than 30 days; the call carries no product.
MCP tool: tracking_heatmaps_get
Parameters
| Name | In | Type | Required | Description |
|---|
pageKey | query | string
| • | The page, as tracking_heatmaps_pages returns it: host + normalized path, e.g. shop.example.com/pricing. |
from | query | string (date-time)
| • | Start of the period, ISO 8601 (e.g. 2026-10-01T00:00:00Z): recordings that started at or after it. At most 30 days before `to`. |
to | query | string (date-time)
| • | End of the period, ISO 8601: recordings that started at or before it. |
utmCampaign | query | string
| — | Only recordings whose entry page carried this utm_campaign, e.g. spring. |
utmSource | query | string
| — | Only recordings whose entry page carried this utm_source, e.g. google. |
converted | query | boolean
| — | true: only sessions with a conversion or a payment; false: only sessions without one. Omit for both. |
device | query | stringone of: desktop, tablet, mobile
| • | Required: a map is drawn for one kind of device (desktop, tablet or mobile), since layouts differ. |
Response
Returns object.
| Field | Type | Always | Description |
|---|
clicks | object[]
| • | At most 300 elements, most clicked first. |
scroll | object
| • | How far down the page the sessions scrolled. |
sessions | integer
| • | Recordings of the period, device and filters with a click or a scroll sample on this page. |
background | object | null
| • | The latest recording of this device (any time in retention) whose segment loaded this page with a full snapshot at its start. Null when none: a page only ever reached by in-app navigation has no picture of its own. |
belowThreshold | boolean
| • | True when sessions < 10: clicks and scroll.reached are then empty and medianDocHeight null. |
GET/tracking/heatmaps/pages
List the pages of the current product that have heatmap data (clicks, scroll depth) from session recordings, most sessions first. A page is host + normalized path (no query, no hash, ids replaced by *). Filter by period (required, at most 30 days), device, campaign, source, conversion and page text; cursor-paged. sessions counts the recordings with a click or a scroll sample on the page, selected like tracking_recordings_list with the same filters. Returns: { pages, nextCursor }. Fails when: the period is longer than 30 days; cursor is not one this tool issued; the call carries no product.
MCP tool: tracking_heatmaps_pages
Parameters
| Name | In | Type | Required | Description |
|---|
from | query | string (date-time)
| • | Start of the period, ISO 8601 (e.g. 2026-10-01T00:00:00Z): recordings that started at or after it. At most 30 days before `to`. |
to | query | string (date-time)
| • | End of the period, ISO 8601: recordings that started at or before it. |
utmCampaign | query | string
| — | Only recordings whose entry page carried this utm_campaign, e.g. spring. |
utmSource | query | string
| — | Only recordings whose entry page carried this utm_source, e.g. google. |
converted | query | boolean
| — | true: only sessions with a conversion or a payment; false: only sessions without one. Omit for both. |
device | query | stringone of: desktop, tablet, mobile
| — | Only recordings from this kind of device: desktop, tablet or mobile. Omit for all. |
q | query | string
| — | Only pages whose key contains this text, case-insensitively, e.g. /pricing. |
cursor | query | string
| — | Continue a previous page: pass the nextCursor it returned. |
limit | query | integer
| — | Pages per page of results, 1 to 100 (default 50). |
Response
Returns object.
| Field | Type | Always | Description |
|---|
pages | object[]
| • | Most sessions first. |
nextCursor | string | null
| • | Pass back as cursor for the next page. Null on the last page. |
GET/tracking/identity/health
Identity match-rate metric: share of identified profiles and share with an ad touchpoint (proxy = has >=1 click_id identifier).
MCP tool: tracking_identity_health
Parameters
No parameters.
Response
Returns object.
| Field | Type | Always | Description |
|---|
computedAt | string (date-time)
| • | When these numbers were computed, ISO 8601 UTC. They are a live count, so this is effectively the moment of the call. |
totalProfiles | integer
| • | How many people the product holds in total, anonymous ones included. The denominator of both rates below. |
identifiedRate | number
| • | Identified people as a share of the total, normally 0 to 1 (0.42 is 42%). A drop here usually means a broken identify() call, not fewer visitors. |
adTouchpointRate | number
| • | People with an ad touchpoint as a share of the total, normally 0 to 1. It counts click-id identifiers, so an identifier outliving its profile can push it just above 1 — read it as an indicator, not as a proportion to assert on. |
identifiedProfiles | integer
| • | How many of them an email or phone is known for — the people a message can actually be sent to. |
adTouchpointProfiles | integer
| • | How many people arrived carrying an ad click id. A proxy for paid reach: it counts anyone with at least one click id on record. |
GET/tracking/install/domains
List install-verification domains for the current product with per-domain "script seen" status, plus auto-discovered domains sending events
MCP tool: tracking_install-domains_list
Parameters
No parameters.
Response
Returns object.
| Field | Type | Always | Description |
|---|
discovered | object[]
| • | Domains sending events that nobody registered — usually a staging host, a typo, or an install worth adding |
registered | object[]
| • | Domains deliberately put on the install checklist, each with whether its script has been seen |
windowDays | number
| • | Length in days of the lookback window the `seen` and `lastSeen` figures are measured over |
POST/tracking/install/domains
Register a domain in the install-verification checklist for the current product
MCP tool: tracking_install-domains_create
Parameters
| Name | In | Type | Required | Description |
|---|
domain | body | string
| • | Domain to add to the install checklist (e.g. acme.com) |
Response
Returns object.
| Field | Type | Always | Description |
|---|
domain | string
| • | The domain as stored after normalisation, which may differ from what was submitted |
DELETE/tracking/install/domains/:domain
Remove a domain from the install-verification checklist for the current product
MCP tool: tracking_install-domains_delete
Parameters
| Name | In | Type | Required | Description |
|---|
domain | path | string
| • | Registered domain to remove from the checklist |
Response
Returns object.
| Field | Type | Always | Description |
|---|
ok | booleanone of: true
| • | Always true — the domain was removed; a failure arrives as an error, not as false |
GET/tracking/link/domains
List the cross-domain linking group (domains whose links the tracking script decorates with the visitor id) for the current product
MCP tool: tracking_link-domains_list
Parameters
No parameters.
Response
Returns object.
| Field | Type | Always | Description |
|---|
domains | string[]
| • | Root domains in the linking group; the tracking script decorates links between any two of them so one visitor stays one visitor |
POST/tracking/link/domains
Add a root domain to the cross-domain linking group for the current product
MCP tool: tracking_link-domains_create
Parameters
| Name | In | Type | Required | Description |
|---|
domain | body | string
| • | Root domain to add to the cross-domain linking group (e.g. acme.io) |
Response
Returns object.
| Field | Type | Always | Description |
|---|
domain | string
| • | The domain as stored after normalisation, which may differ from what was submitted |
DELETE/tracking/link/domains/:domain
Remove a root domain from the cross-domain linking group for the current product
MCP tool: tracking_link-domains_delete
Parameters
| Name | In | Type | Required | Description |
|---|
domain | path | string
| • | Root domain to remove from the cross-domain linking group |
Response
Returns object.
| Field | Type | Always | Description |
|---|
ok | booleanone of: true
| • | Always true — the domain left the linking group; a failure arrives as an error, not as false |
GET/tracking/live
List recent tracking events for the current product, cursor-paged for incremental polling. From the rollout, a d: anonymous id marks a cookieless one-day visitor rotating every UTC midnight, never a toolkit profile; these events appear as separate people each day in funnels, person counts and retention. Filter consent_statistics = true for consented-only figures and always for retention.
MCP tool: tracking_live-events_list
Parameters
| Name | In | Type | Required | Description |
|---|
since | query | string
| — | Opaque cursor from a previous response; omit for the newest events |
domain | query | string
| — | Filter to a single domain (e.g. acme.com) |
limit | query | integer
| — | Max events to return (default 50, max 200) |
Response
Returns object.
| Field | Type | Always | Description |
|---|
cursor | string | null
| • | Pass back as `since` to fetch what arrived after this page. Null when there is nothing older to page into. |
events | object[]
| • | The page of events, newest first. |
GET/tracking/profiles
List/search people (profiles) for the product; filter by email and status, cursor-paged.
MCP tool: tracking_profiles_list
Parameters
| Name | In | Type | Required | Description |
|---|
email | query | string
| — | Email to search people by — the whole address by default, or its beginning when emailMatch is prefix. Omit to search across everyone. |
emailMatch | query | stringone of: exact, prefix
| — | How the email filter is matched: exact (default) compares the whole address case-insensitively, prefix matches everyone whose address starts with what you typed. |
status | query | stringone of: anonymous, identified, customer
| — | Keep only people at this stage — anonymous, identified or customer. Omit to get all three. |
limit | query | integer
| — | Max profiles per page (default 25, max 100) |
cursor | query | string
| — | Continue a previous page: pass the cursor that page returned. Omit to start from the most recently seen person. |
Response
Returns object.
| Field | Type | Always | Description |
|---|
cursor | string | null
| • | Pass this back as `cursor` to fetch the next page. Null on the last page — that null is how a loop knows to stop. |
profiles | object[]
| • | The page of people, most recently seen first. Shorter than the requested limit on the last page. |
DELETE/tracking/profiles/:profileId
GDPR erasure: permanently delete a person and their events from Postgres and record an erasure request. Archived events are flagged as a deletion gap.
MCP tool: tracking_profiles_delete
Parameters
| Name | In | Type | Required | Description |
|---|
profileId | path | string (uuid)
| • | The profile id (uuid) |
Response
Returns object.
| Field | Type | Always | Description |
|---|
ok | booleanone of: true
| • | Always true: the response only exists when the erasure ran. A failure arrives as an error, not as ok=false. |
archive | object
| • | What happened to the archived copy of the events. Postgres is erased synchronously; the archive is not, and this says so out loud. |
deleted | object
| • | How much was actually destroyed, by kind. Worth recording: it is the evidence that the erasure did something. |
profileId | string (uuid)
| • | The person who was erased. Nothing else of them remains, so this is all there is left to name them by. |
requestId | string (uuid)
| • | This erasure attempt. The completion event carries the same value under the same name, so a step recognises its own completion even when another workflow is erasing the same person at the same moment. |
recordings | object
| • | What happened to the session recordings of this person. Unlike the events archive, they are deleted per person. |
GET/tracking/profiles/:profileId
Get one person: profile, identity signals, and their chronological journey (query-time join over the person's anonymous ids).
MCP tool: tracking_profiles_get
Parameters
| Name | In | Type | Required | Description |
|---|
profileId | path | string (uuid)
| • | The profile id (uuid) |
journeyCursor | query | string
| — | Continue paging back through the journey: pass the cursor the previous page returned. Omit to start at the most recent event. |
journeyLimit | query | integer
| — | Journey events per page (default 100, max 200) |
Response
Returns object.
| Field | Type | Always | Description |
|---|
ltv | object | null
| • | Lifetime value of this person, per currency. Null when revenue tracking is not in use for the product. |
journey | object
| • | What this person did, newest first, one page at a time. Use the export step instead when the whole history is wanted in one go. |
profile | object
| • | The person themselves: their handle, how far they have come, and when they were seen. |
signals | object
| • | Everything known about who this person is: the addresses they have been identified by, the ad clicks they arrived by, and the sites they were seen on. Every part of it is a list, and none of the lists names a primary. |
acquisition | object | null
| • | First touch: the campaign that brought this person in, frozen at their earliest event and never overwritten by later visits. Null for a person with no events at all. |
GET/tracking/profiles/:profileId/export
Export a person as JSON: profile + identity signals + full journey (capped at 50k events; truncated flag set if exceeded).
MCP tool: tracking_profiles_export
Parameters
| Name | In | Type | Required | Description |
|---|
profileId | path | string (uuid)
| • | The profile id (uuid) |
Response
Returns object.
| Field | Type | Always | Description |
|---|
journey | object[]
| • | The complete history, newest event first, capped at 50000 events — check `truncated` before treating it as complete. |
profile | object
| • | The person themselves: their handle, how far they have come, and when they were seen. |
signals | object
| • | Everything known about who this person is: the addresses they have been identified by, the ad clicks they arrived by, and the sites they were seen on. Every part of it is a list, and none of the lists names a primary. |
truncated | boolean
| • | True when the history hit the 50000-event cap and older events were left out. False means this export is everything held. |
exportedAt | string (date-time)
| • | When this export was produced, ISO 8601 UTC — the as-of date to put on a subject-access response. |
acquisition | object | null
| • | First touch: the campaign that brought this person in, frozen at their earliest event and never overwritten by later visits. Null for a person with no events at all. |
GET/tracking/recording-settings
Get the session recording setting of the current product: whether recording is on, the percent of sessions recorded, the hosts whose pages are recorded, and candidate hosts to choose from. Off at 0% with no hosts until it is set; on with no hosts records nothing. Returns: { enabled, sampleRate, hosts, candidateHosts }. Fails when: the call carries no product.
MCP tool: tracking_recording-settings_get
Parameters
No parameters.
Response
Returns object.
| Field | Type | Always | Description |
|---|
hosts | string[]
| • | Exact hostnames whose pages are recorded, e.g. ["example.com", "www.example.com"]; pages on any other host are never recorded. Bare hosts only — no scheme, port, path or wildcard; www and each subdomain are separate hosts. Up to 20. Recording on with no hosts records nothing. |
enabled | boolean
| • | Whether session recording is on. Only visitors in full tracking mode (statistics consent, or no consent banner) are recorded. |
sampleRate | integer
| • | Percent of sessions recorded, 1 to 100 when on (e.g. 25); 0 is allowed only when off. |
candidateHosts | string[]
| • | Hosts to choose from when setting hosts: the stored hosts, the product’s install domains, then hosts its tracked pages were on in the last 30 days. A suggestion list, not a filter. |
PUT/tracking/recording-settings
Turn session recording on or off for the current product, choose the hosts whose pages are recorded, and set the percent of sessions recorded (1 to 100 when on). Turning it on requires at least one host: list only the sites meant to be recorded (e.g. the marketing site, not an app or console showing customer data — page text is recorded as shown). tracking_recording-settings_get returns candidate hosts. Browsers pick the change up within about 10 minutes; the server applies it to new data within a minute. Returns: { enabled, sampleRate, hosts }. Fails when: enabled is true and hosts is missing or empty ("choose at least one host to record"); a host is not a bare hostname; more than 20 hosts; sampleRate is outside 1..100 while enabled; the call carries no product.
MCP tool: tracking_recording-settings_set
Parameters
| Name | In | Type | Required | Description |
|---|
enabled | body | boolean
| • | Whether session recording is on. Only visitors in full tracking mode (statistics consent, or no consent banner) are recorded. |
sampleRate | body | integer
| • | Percent of sessions recorded, 1 to 100 when on (e.g. 25); 0 is allowed only when off. |
hosts | body | string[]
| — | Exact hostnames whose pages are recorded, e.g. ["example.com", "www.example.com"]; pages on any other host are never recorded. Bare hosts only — no scheme, port, path or wildcard; www and each subdomain are separate hosts. Up to 20. Recording on with no hosts records nothing. Required, at least one, when enabled is true; when turning recording off it may be left out to keep the stored list. |
Response
Returns object.
| Field | Type | Always | Description |
|---|
hosts | string[]
| • | Exact hostnames whose pages are recorded, e.g. ["example.com", "www.example.com"]; pages on any other host are never recorded. Bare hosts only — no scheme, port, path or wildcard; www and each subdomain are separate hosts. Up to 20. Recording on with no hosts records nothing. |
enabled | boolean
| • | Whether session recording is on. Only visitors in full tracking mode (statistics consent, or no consent banner) are recorded. |
sampleRate | integer
| • | Percent of sessions recorded, 1 to 100 when on (e.g. 25); 0 is allowed only when off. |
GET/tracking/recordings
List session recordings of the current product, newest first: who (profile), how they arrived (entry page, utm, ad click), device, length, and whether the session converted. Filter by period (default the last 30 days), person, visitor, device, campaign, source, entry page, conversion and minimum length; cursor-paged. Device, campaign, source and conversion select the same recordings as tracking_heatmaps_get with the same filters. Returns: { items, nextCursor }. Fails when: cursor is not one this tool issued; the call carries no product.
MCP tool: tracking_recordings_list
Parameters
| Name | In | Type | Required | Description |
|---|
from | query | string (date-time)
| — | Start of the period, ISO 8601 (e.g. 2026-10-01T00:00:00Z): recordings that started at or after it. Default: 30 days before `to`, the whole retention window. |
to | query | string (date-time)
| — | End of the period, ISO 8601: recordings that started at or before it. Default: now. |
profileId | query | string (uuid)
| — | Only this person: every browser they were seen on, merged profiles included. |
anonymousId | query | string
| — | Only this visitor id (one browser). |
utmCampaign | query | string
| — | Only recordings whose entry page carried this utm_campaign, e.g. spring. |
utmSource | query | string
| — | Only recordings whose entry page carried this utm_source, e.g. google. |
device | query | stringone of: desktop, tablet, mobile
| — | Only recordings from this kind of device, as classified on ingest: desktop, tablet or mobile. |
entryUrlContains | query | string
| — | Only recordings whose entry page URL contains this text, case-insensitively, e.g. /pricing. |
converted | query | boolean
| — | true: only sessions with a conversion or a payment; false: only sessions without one. Omit for both. |
minDurationMs | query | integer
| — | Only recordings at least this long, in milliseconds, e.g. 30000. |
cursor | query | string
| — | Continue a previous page: pass the nextCursor it returned. Omit to start from the newest recording. |
limit | query | integer
| — | Recordings per page, 1 to 100 (default 50). |
Response
Returns object.
| Field | Type | Always | Description |
|---|
items | object[]
| • | Newest first. |
nextCursor | string | null
| • | Pass back as cursor for the next page. Null on the last page. |
GET/tracking/recordings/:id
Get one session recording: its summary, its segments (page loads, in play order) and the tracker events of the recording itself (its hosts, its time span) with their offset on the player clock, for a timeline, and the first conversion of the session after the recording. Returns: the summary plus { clockOffsetMs, segments, events, eventsTruncated, laterConversion }. Fails when: no recording with that id is visible in this product.
MCP tool: tracking_recordings_get
Parameters
| Name | In | Type | Required | Description |
|---|
id | path | string (uuid)
| • | The recording id (uuid), from tracking_recordings_list. |
Response
Returns object.
| Field | Type | Always | Description |
|---|
id | string (uuid)
| • | The recording id. Pass it to tracking_recordings_get. |
device | string | null
| • | desktop, mobile or tablet, from the browser. Null when unknown. |
events | object[]
| • | Tracker events of the recording itself — pages on the recording's hosts, from 5 s before its start to 5 s after its end — oldest first, at most 2000. |
status | stringone of: active, closed
| • | active: the session may still be recording; closed: finished (4 h cap). |
entryUrl | string | null
| • | The first page recorded. Personal data: a URL can carry an email. Null when unknown. |
segments | object[]
| • | In start order — the order to play them in. |
viewport | object
| • | Browser viewport at the start of the recording. |
converted | boolean
| • | True when the same session has an event marked as a conversion or a signup, trial, subscription or payment. |
profileId | string (uuid) | null
| • | The person behind the visitor, resolved now, so a later merge is honoured. Null for a visitor never tied to a profile. |
startedAt | string (date-time)
| • | When the recording started, ISO 8601 UTC, on the server clock. |
utmMedium | string | null
| • | utm_medium of the entry page. Null when untagged. |
utmSource | string | null
| • | utm_source of the entry page. Null when untagged. |
durationMs | integer
| • | Length of the recording in milliseconds. |
clickIdType | string | null
| • | Ad network of the click that opened the session: gclid for Google Ads, fbclid for Meta. Null for a non-ad arrival. |
utmCampaign | string | null
| • | utm_campaign of the entry page. Null when untagged. |
segmentCount | integer
| • | Page loads (and consent re-starts) recorded in the session. |
clockOffsetMs | integer
| • | Server clock minus browser clock, measured on the first slice. rrweb timestamps and `events[].at` are on the browser clock. |
eventsTruncated | boolean
| • | True when the recording had more than 2000 events and the rest were left out. |
laterConversion | object | null
| • | The first conversion of the same session that is not in events: after the recording ended (up to 24 h later), or during it on a host the recording has no page of. Any host. Compare at with the span of the recording to tell which. Null when there is none. |
GET/tracking/recordings/:id/chunks
Get the rrweb events of one segment of a recording for playback, one page at a time (about 2 MiB of events by default); follow nextSeq until it is null. Lost or undecodable stretches are reported in gaps, never as an error. Returns: { events, gaps, nextSeq }. Fails when: the recording is not visible in this product or has no such segment.
MCP tool: tracking_recordings_chunks_get
Parameters
| Name | In | Type | Required | Description |
|---|
id | path | string (uuid)
| • | The recording id (uuid), from tracking_recordings_list. |
pid | query | string
| • | Page load of the segment, from the segments of tracking_recordings_get. |
seg | query | integer
| • | Consent (re)start of the segment within that page load, from tracking_recordings_get. |
fromSeq | query | integer
| — | Continue a segment: pass the nextSeq the previous page returned. Default 0, the start. |
maxBytes | query | integer
| — | Decoded bytes per page (default 2097152, max 8388608). A page ends at the first whole payload past it and always holds at least one. |
Response
Returns object.
| Field | Type | Always | Description |
|---|
gaps | object[]
| • | Stretches of the segment that could not be played: lost slices, or payloads that did not decode. Show "part of the recording is lost" there. |
events | array
| • | rrweb events of this page of the segment, in order. Feed them to the player. |
nextSeq | integer | null
| • | Pass back as fromSeq for the next page. Null once the segment is read to its end. On an active recording it can equal the fromSeq you sent, with no events: the last part is still arriving — ask again later. |
GET/tracking/reports/attributed-journey/:profileId
One person's journey with, for their originating conversion, the attribution decision explained (winning touchpoint + why) under the requested model and lookback window. Attribution is never locked in — changing model/window re-reads the same history.
MCP tool: tracking_reports_attributed_journey
Parameters
| Name | In | Type | Required | Description |
|---|
profileId | path | string (uuid)
| • | The profile id (uuid) |
model | query | stringone of: last_click, first_click
| — | Attribution model to explain the decision under; re-reads the same history, so switching it is free (default 'last_click'). |
lookbackDays | query | integer
| — | How far back before the conversion a touchpoint may be credited, in days (default 30). |
from | query | string (date-time)
| — | Show only journey events at or after this instant (ISO). Omit for the whole history. |
to | query | string (date-time)
| — | Show only journey events at or before this instant (ISO). Omit for the whole history. |
Response
Returns object.
| Field | Type | Always | Description |
|---|
journey | object
| • | What this person actually did, in order. |
decisions | object[]
| • | Holds at most one entry: the decision for this person's originating conversion, present only when that conversion falls inside the requested window. Kept as a list for callers that already read it; `originatingDecision` is the same value at a bindable path. |
profileId | string
| • | The person this journey belongs to, echoed back from the request. |
originatingDecision | object | null
| • | The attribution decision for this person's originating conversion — the same value as `decisions[0]`, at a path a workflow can bind. Null means the decision is not in THIS window, not that the person never converted: a conversion before `from` or after `to` is excluded here while still being their originating one. Widen the window to see it. |
GET/tracking/reports/event-volume
Traffic for a date range as TWO headline figures plus a data-quality block. totalEvents counts events. visitorsDeduplicatedPerUtcDay counts PEOPLE, over both populations at once: consenting and no-banner visitors by anonymous_id, cookieless visitors by server-derived daily_visitor_key. It is one COUNT DISTINCT, not a sum of two figures, and there is no second set of numbers to add to it. READ THE FIELD NAME LITERALLY — the daily key rotates every UTC midnight, so a returning cookieless visitor is counted again. From the rollout, that key also appears as anonymous_id = d:<daily key> on the event: a one-day graph person, never a toolkit profile. These visitors enter funnels, person counts and retention as separate people each day. Weekly and monthly uniques are OVERSTATED for this traffic; filter consent_statistics = true for consented-only figures and always for retention, returning-visitor, frequency and loyalty analysis. dataQuality.visitorsOverstated tells you whether the over-count applies to this window, and dataQuality.utcDaysInRange gives its UTC-day span. dataQuality describes how COMPLETE the two headline figures are and contains no metric of its own — never present anything inside it as a headline number and never add it to anything. cookielessShare and noBannerShare are the fractions of events from cookieless visitors and from sites with no banner. consentGrantedEvents + cookielessEvents + noBannerEvents = totalEvents. noBannerEvents (nobody was ever asked) stays distinct from cookielessEvents (denied or undecided). identifiedEvents counts only non-cookieless events carrying an anonymous_id, excluding d: rows; never add it to the consent buckets.
MCP tool: tracking_reports_event_volume
Parameters
| Name | In | Type | Required | Description |
|---|
from | query | string (date-time)
| — | Start of the range to count, inclusive (ISO 8601). Optional — defaults to 30 days back, the start of that UTC day. |
to | query | string (date-time)
| — | End of the range to count, inclusive (ISO 8601). Optional — defaults to the moment of the call. |
domain | query | string
| — | Count only this site. Omit to count every site the product sends from. |
Response
Returns object.
| Field | Type | Always | Description |
|---|
to | string (date-time)
| • | End of the range the figures cover, echoed back (ISO 8601, UTC). |
from | string (date-time)
| • | Start of the range the figures cover, echoed back (ISO 8601, UTC). |
domain | string | null
| • | Site the figures were restricted to; null when every site of the product is included. |
computedAt | string (date-time)
| • | When this report was computed (ISO 8601, UTC). |
dataQuality | object
| • | How COMPLETE the two headline figures above are. Contains no metric of its own — never present a field of it as a headline number and never add it to anything. consentGrantedEvents + cookielessEvents + noBannerEvents = totalEvents. |
totalEvents | number
| • | How many events arrived in the range, across every consent state. |
visitorsDeduplicatedPerUtcDay | number
| • | How many PEOPLE those events came from: one COUNT DISTINCT over consenting visitors (by anonymous id) and declining visitors (by a daily key destroyed each UTC midnight) at once. Over a range longer than one UTC day this is an OVER-count of the declining half — read `dataQuality.visitorsOverstated` before reporting it. |
GET/tracking/reports/revenue-by-source
Revenue attributed by channel + UTM breakdown for a date range, under a chosen attribution model and lookback window. Includes a distinct unattributed row, totals, and a count-based match rate. Revenue is per-currency (never summed across currencies); refunds are netted explicitly.
MCP tool: tracking_reports_revenue_by_source
Parameters
| Name | In | Type | Required | Description |
|---|
from | query | string (date-time)
| — | Cohort window start (ISO); selects conversions by subscription start. Optional — defaults to 30 days back, the start of that UTC day. |
to | query | string (date-time)
| — | Cohort window end (ISO). Optional — defaults to the moment of the call. |
model | query | stringone of: last_click, first_click
| — | Attribution model |
lookbackDays | query | integer
| — | Lookback window in days (default 30) |
domain | query | string
| — | Only consider touchpoints on this domain |
Response
Returns object.
| Field | Type | Always | Description |
|---|
to | string (date-time)
| • | End of the cohort window the figures cover, echoed back (ISO 8601, UTC). |
from | string (date-time)
| • | Start of the cohort window the figures cover, echoed back (ISO 8601, UTC). |
model | stringone of: last_click, first_click
| • | Attribution model the credit was assigned under, echoed back. Pass the same value to `tracking_reports_source_people` to drill into a row. |
domain | string | null
| • | Site touchpoints were restricted to; null when every site of the product was considered. |
totals | object
| • | Every channel plus `unattributed`. This is the whole window, not the attributed part of it. |
channels | object[]
| • | One row per channel that earned revenue in the window. Channels with none are omitted. |
matchRate | number
| • | Fraction of paying people (0..1) a touchpoint could be found for: attributed customers over `totals.customers`. Count-based, never revenue-weighted. |
computedAt | string (date-time)
| • | When this report was computed (ISO 8601, UTC). |
lookbackDays | number
| • | How far back before a conversion a touchpoint was allowed to be credited, in days; echoed back. |
unattributed | object
| • | Revenue that reached no channel — kept as its own row so the channel rows are never quietly inflated to cover it. |
GET/tracking/reports/source-people
List the people (profiles) behind one channel / UTM row from the revenue-by-source report, under the same model + window. Keyset-paginated; each person carries their attributed lifetime revenue per currency.
MCP tool: tracking_reports_source_people
Parameters
| Name | In | Type | Required | Description |
|---|
channel | query | stringone of: paid, organic, direct, email
| • | Channel to drill into |
utmSource | query | string
| — | utm_source of the breakdown row to drill into. Omit for no filter; to match the IS-NULL row, list it in utmNulls instead. |
utmMedium | query | string
| — | utm_medium of the breakdown row to drill into. Omit for no filter; to match the IS-NULL row, list it in utmNulls instead. |
utmCampaign | query | string
| — | utm_campaign of the breakdown row to drill into. Omit for no filter; to match the IS-NULL row, list it in utmNulls instead. |
clickIdType | query | string
| — | Native click-id type of the breakdown row to drill into (e.g. 'gclid'). Tri-state: omit for no filter (all click ids), pass a value to match it, or list 'clickIdType' in utmNulls to match the IS-NULL row. |
utmNulls | query | string
| — | Comma-separated dimension names (utmSource,utmMedium,utmCampaign,clickIdType) that must be IS NULL |
model | query | stringone of: last_click, first_click
| — | Attribution model to credit the touchpoint under; must match the report this row came from (default 'last_click'). |
lookbackDays | query | integer
| — | How far back before a conversion a touchpoint may be credited, in days; must match the report this row came from (default 30). |
from | query | string (date-time)
| — | Cohort window start (ISO); must match the report this row came from. Optional — defaults to 30 days back, the start of that UTC day. |
to | query | string (date-time)
| — | Cohort window end (ISO); must match the report this row came from. Optional — defaults to the moment of the call. |
domain | query | string
| — | Only consider touchpoints on this domain; must match the report this row came from. Omit for no restriction. |
cursor | query | string
| — | Opaque keyset cursor from a previous page |
limit | query | integer
| — | People per page (default 50, max 200) |
Response
Returns object.
| Field | Type | Always | Description |
|---|
cursor | string | null
| • | Pass back as `cursor` for the next page. Null on the last page. |
people | object[]
| • | The page of people behind the requested row, ordered by the keyset the cursor walks. |
GET/tracking/snippet
Get the tracking snippet for the caller's current product. Install it unconditionally. Do NOT wrap it in a consent gate and do NOT load it only after consent is granted: the tracker reads the visitor consent decision itself and switches to a cookieless mode that writes no cookies and sends no identifiers when statistics consent is declined or not yet given. Gating this tag makes declining and undecided visitors invisible entirely — the failure this behaviour exists to prevent. Set consentBanner: true when the page runs the Lepsto consent banner. Without it, a tracker that loads before the banner sees no consent API yet and can write cookies before the visitor decides. Do NOT set it on a page without the banner: the tracker would then wait for a decision that never comes and stay cookieless for every visitor.
MCP tool: tracking_snippets_get
Parameters
| Name | In | Type | Required | Description |
|---|
consentBanner | query | boolean
| — | true when the page runs the Lepsto consent banner: both snippets then carry data-consent="banner", and the tracker stays cookieless until the banner reports a decision. Default false. |
Response
Returns object.
| Field | Type | Always | Description |
|---|
host | string
| • | Tracking host the snippet sends to — the customer-facing domain events and the bundle are served from. |
snippet | string
| • | The tag to paste into every page, verbatim, before </head>. Includes the consent-aware bootstrap; install it unconditionally rather than behind a consent gate. |
scriptUrl | string
| • | Absolute URL of the tracker bundle the snippet loads; already points at this product's own tracking host. |
minimalSnippet | string
| • | The same tag stripped to the bare script element, for tag managers and CMS fields that reject anything else. Behaves identically; use it only when the full snippet will not fit. |
Was this page helpful?Thanks for your feedback!