Documentation menu

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

GET/api/v2/sites/{siteId}/channelsscope: read

Groups 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

siteIdstringThe 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

NameTypeDescription
rangestringRelative window: `today`, `7d`, `30d`, `90d`, `6m` or `12m`. Default `7d`. Ignored when both `from` and `to` are supplied.
fromstring (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.
tostring (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 }
      ]
    }
  ]
}