Acquisition
Where your traffic comes from, grouped into GA4-style marketing channels.
1 endpoint, all relative to https://analytics.appfor.you. Shared rules live in Conventions, Rate limits and Error codes.
Channel grouping
/api/v2/sites/{siteId}/channelsscope: readGroups pageviews by referrer / utm_source / utm_medium, classifies each row into a channel and rolls the rows up. Visitors are counted by `visitorId`, falling back to `sessionId`, and are **unioned** across the rows of a channel rather than summed — one person who arrives through three different ChatGPT URLs is one visitor, and the per-channel figures do not add up to the site total because one person can legitimately arrive through two channels. Channel labels: Direct, Organic Search, Paid Search, Paid Social, Organic Social, Email, Referral, AI Assistant, Other. `AI Assistant` counts people referred by an AI assistant — a human who read an answer in ChatGPT, Perplexity, Claude, Microsoft Copilot, Google Gemini or one of the other assistants in `src/data/ai-assistants.json` and clicked through. That channel, and only that channel, carries an `assistants` array naming the individual assistant. AI *crawlers* (GPTBot, ClaudeBot, PerplexityBot …) are matched on the user agent, are dropped as bots before persistence and never appear in this channel. Coverage is honest about its limits: attribution is host-based on `document.referrer`, with `utm_source` as a fallback when the assistant tags its outbound links. Assistants that strip the referrer entirely and tag nothing are indistinguishable from Direct and are **not** counted here. Assistant traffic we can recognise but cannot attribute to a specific product is reported inside `assistants` as `AI Assistant (unattributed)` rather than being merged silently into the channel total.
Path parameters
| siteId | string | The Mongo _id returned as `siteId` by GET /api/v2/sites, or the public `trackingId` embedded in the tracking snippet. Both are accepted everywhere. |
Query parameters
| Name | Type | Description |
|---|---|---|
| range | string | Relative window: `today`, `7d`, `30d`, `90d`, `6m` or `12m`. Default `7d`. Ignored when both `from` and `to` are supplied. |
| from | string (YYYY-MM-DD) | Explicit window start (inclusive), from `T00:00:00.000Z` on that day. Supply together with `to` to override `range`. An unparseable value, a window that ends before it starts, or a window that starts in the future returns 400. |
| to | string (YYYY-MM-DD) | Explicit window end (inclusive) — the WHOLE day, through `T23:59:59.999Z`, clamped to now when it is in the future. `from=X&to=X` is therefore a full 24-hour day. Supply together with `from` to override `range`. An unparseable value, a window that ends before it starts, or a window that starts in the future returns 400. |
Example request
curl -H "Authorization: Bearer $ANALYTICS_API_KEY" \ "https://analytics.appfor.you/api/v2/sites/6507f1f77bcf86cd799439011/channels?range=30d"
Example response
{
"range": {
"since": "2025-02-19T00:00:00.000Z",
"until": "2025-03-21T00:00:00.000Z"
},
"channels": [
{ "channel": "Organic Search", "visitors": 820, "pageviews": 2140 },
{ "channel": "Direct", "visitors": 610, "pageviews": 1502 },
{ "channel": "Referral", "visitors": 133, "pageviews": 288 },
{
"channel": "AI Assistant",
"visitors": 96,
"pageviews": 211,
"assistants": [
{ "assistant": "ChatGPT", "visitors": 61, "pageviews": 140 },
{ "assistant": "Perplexity", "visitors": 22, "pageviews": 47 },
{ "assistant": "Google Gemini", "visitors": 9, "pageviews": 18 },
{ "assistant": "AI Assistant (unattributed)", "visitors": 4, "pageviews": 6 }
]
}
]
}