Stats API

Read a site's traffic from your own code or another tool: totals, a daily series, breakdowns by source, page, country, device and more, and AI crawler activity. The numbers match the dashboard for the same dates and filters.

GET https://api.snowanalytics.app/api/v1/stats/aggregate
GET https://api.snowanalytics.app/api/v1/stats/timeseries
GET https://api.snowanalytics.app/api/v1/stats/breakdown
GET https://api.snowanalytics.app/api/v1/stats/crawlers

Authentication

Authorization: Bearer snw_live_your_key

The key needs the stats:read scope. Create one under API keys and tick Read stats. The scope is off by default, so keys you already use for events cannot read stats.

A key belongs to one site, so there is no site parameter. Every request reads the site the key was created for.

Date range

Send either a preset period or a custom from and to. Dates are days in the site's timezone.

ParameterValue
periodtoday, yesterday, 7d, 30d, 90d, 180d, 365d, 12m, this_week, last_week, this_month, last_month, this_year, all_time. Defaults to 30d.
from, toYYYY-MM-DD, both required together.

Rolling periods include today: 7d is today plus the previous 6 days, and 30d is today plus the previous 29.

A range ends today at the latest: a to after today reads through today, and a from after today returns 400.

Every response includes the range that was read. If your plan's history window is shorter than the range you asked for, the range is shortened and marked with "clamped": true and the earliest day you can read.

Filters

Each filter takes one exact value. Filters combine with AND.

ParameterMatches
channelA channel such as Organic Search or Direct, or one source such as google.com.
countryTwo-letter country code, such as US.
cityCity name.
browser, os, deviceBrowser, operating system, or device type.
pageThis path. Totals count its own views. Breakdowns cover the sessions that viewed it.
entry_page, exit_pageSessions that started or ended on this path.
campaignutm_campaign value.
utm_source, utm_medium, utm_content, utm_termThe matching UTM value.

A parameter sent twice, or one that is not listed on this page, returns 400. A typo never returns unfiltered numbers.

Aggregate

Totals for the range.

curl "https://api.snowanalytics.app/api/v1/stats/aggregate?period=30d&country=US" \
  -H "Authorization: Bearer snw_live_your_key"
{
  "status": "success",
  "data": {
    "site": { "domain": "example.com", "name": "Example", "timezone": "UTC" },
    "range": { "from": "2026-09-05", "to": "2026-10-04" },
    "totals": {
      "visitors": 1840,
      "sessions": 2311,
      "pageviews": 5120,
      "bounce_rate": 41.2,
      "avg_duration": 96
    }
  }
}

bounce_rate is a percentage. avg_duration is the average session length in seconds.

Timeseries

One point per day. The series starts on the first day with traffic inside the range and has no gaps after it.

curl "https://api.snowanalytics.app/api/v1/stats/timeseries?from=2026-10-01&to=2026-10-03" \
  -H "Authorization: Bearer snw_live_your_key"
{
  "status": "success",
  "data": {
    "range": { "from": "2026-10-01", "to": "2026-10-03" },
    "interval": "day",
    "series": [
      { "date": "2026-10-01", "visitors": 61, "sessions": 70, "pageviews": 152, "bounce_rate": 42.9 },
      { "date": "2026-10-02", "visitors": 0, "sessions": 0, "pageviews": 0, "bounce_rate": 0 },
      { "date": "2026-10-03", "visitors": 58, "sessions": 66, "pageviews": 140, "bounce_rate": 39.4 }
    ]
  }
}

Breakdown

Rows for one dimension, largest first.

ParameterValue
dimensionRequired. One of the dimensions below.
limitRows per page, 1 to 1000. Defaults to 100.
offsetRows to skip, for paging. Defaults to 0.

Each dimension returns the metrics that make sense for it:

DimensionMetrics
source, campaign, utm_source, utm_medium, utm_content, utm_termvisitors, sessions, bounce_rate, avg_duration
pagevisitors, pageviews
entry_pagesessions, bounce_rate
exit_pagesessions
country, city, browser, os, devicevisitors, sessions, avg_duration
channelsessions
visitor_typevisitors, in two rows named new and returning

On the UTM dimensions, traffic without that tag is one row named (none). channel groups the site's top 200 sources, the same way the dashboard's Channels chart does.

curl "https://api.snowanalytics.app/api/v1/stats/breakdown?dimension=page&period=7d&limit=2" \
  -H "Authorization: Bearer snw_live_your_key"
{
  "status": "success",
  "data": {
    "range": { "from": "2026-09-28", "to": "2026-10-04" },
    "dimension": "page",
    "limit": 2,
    "offset": 0,
    "has_more": true,
    "rows": [
      { "name": "/", "visitors": 412, "pageviews": 590 },
      { "name": "/pricing", "visitors": 138, "pageviews": 171 }
    ]
  }
}

To read every row, raise offset by limit until has_more is false.

Crawlers

AI crawler requests to the site: who fetched, what for, and which pages. This is the data behind the dashboard's AI crawlers section, so the site needs crawler tracking installed.

It takes the date range parameters only. Crawler requests carry no country, device or source, so a filter returns 400 instead of being ignored.

curl "https://api.snowanalytics.app/api/v1/stats/crawlers?period=7d" \
  -H "Authorization: Bearer snw_live_your_key"
{
  "status": "success",
  "data": {
    "range": { "from": "2026-09-28", "to": "2026-10-04" },
    "installed": true,
    "installed_at": "2026-09-09T10:12:44.000Z",
    "totals": {
      "hits": 8412,
      "verified_hits": 7950,
      "markdown_hits": 240,
      "html_hits": 8172,
      "agents": 34,
      "providers": 16,
      "answer_fetches": 1203
    },
    "previous": { "hits": 7011, "verified_hits": 6600, "markdown_hits": 180, "html_hits": 6831 },
    "series": [
      { "date": "2026-09-28", "hits": 1010, "verified_hits": 960, "markdown_hits": 31, "html_hits": 979 }
    ],
    "categories": [
      { "category": "training", "hits": 4300, "verified_hits": 4100 }
    ],
    "providers": [
      { "provider": "OpenAI", "hits": 2140, "verified_hits": 2140 }
    ],
    "agents": [
      { "agent": "GPTBot", "provider": "OpenAI", "category": "training", "hits": 1500, "verified_hits": 1500, "markdown_hits": 0, "html_hits": 1500 }
    ],
    "daily_by_agent": [
      { "date": "2026-09-28", "agent": "GPTBot", "hits": 210, "verified_hits": 210, "markdown_hits": 0, "html_hits": 210 }
    ],
    "pages": [
      { "path": "/pricing", "provider": "OpenAI", "category": "training", "hits": 96, "verified_hits": 96 }
    ],
    "ai_referrals": { "sessions": 28, "visitors": 24, "previous_sessions": 19 }
  }
}
FieldMeaning
installedWhether the site has ever reported a crawler request. false means crawler tracking is not set up, not that the range was quiet.
totals, previousCounts for the range and for the equal-length range before it. previous covers whole days, even while today is still running.
seriesOne point per day in the range, zeros included.
categories, providersRequests by what the crawler was fetching for, and by operator.
agentsOne row per crawler user agent, with its operator in provider. An agent that fetches for more than one purpose is listed under the busiest.
daily_by_agentOne row per day and agent. Days with no requests are left out.
pagesThe most requested paths, one row per path, provider and category. Capped at the 400 busiest rows.
ai_referralsPeople who arrived from an AI assistant in the same range.

category is what the crawler was fetching for: answer_fetch, search_index, training, ai_crawler or markdown_client. verified_hits counts requests whose identity was verified.

Responses

StatusMeaning
200 OK{ "status": "success", "data": … }
400 Bad RequestA parameter is unknown, repeated, or invalid. The message names it.
401 UnauthorizedMissing or invalid API key.
403 ForbiddenThe key lacks the stats:read scope, or the site is locked until its subscription is restored.
429 Too Many RequestsRate limit exceeded.
500 Internal Server ErrorThe numbers could not be read. Nothing was cached, so retry.

Errors use the same envelope as the other authenticated endpoints:

{ "status": "error", "error": { "code": 400, "message": "Unknown parameter: contry" } }

Results are cached for up to 30 seconds.

On this page