What it does

Top referring hosts. Attribution metric — counts direct browser visits only ('user' class). AI-mediated traffic (Claude/ChatGPT fetching on a user's behalf) is excluded because the AI sets its own host as referrer or strips it; including it would inflate 'direct' or 'claude.ai' without telling you where the human attention actually came from. Counted once per session (field `sessions`), from the host the session entered on — not once per pageview, so don't compare it against pageview counts. percentage_of_total is a percentage of all referred sessions: 58.3 means 58.3%. group_by: channel groups the same entries into channels (search, social, …) instead, see group_by. Each row also has bounce_rate (ratio 0–1 of the row's sessions with exactly one pageview and no custom event; the engagement beacon does not count) and avg_session_duration_seconds (first to last event, over the row's sessions with more than one event; null when there is none).

Example prompts

Ask:

"Where is mysite.com traffic coming from this week?"
"Top referrers for the last 30 days, anything new?"
"Show me my top 20 referrers."

A typical response:

Top referrers for mysite.com (last 7 days):

  news.ycombinator.com   1,847 sessions
  twitter.com              612 sessions
  reddit.com               487 sessions
  bluesky.app              312 sessions
  dev.to                   258 sessions
  google.com (organic)     244 sessions
  perplexity.ai            147 sessions  (AI-mediated human)
  chatgpt.com              124 sessions  (AI-mediated human)
  duckduckgo.com            89 sessions
  linkedin.com              71 sessions

Returns an array of { referrer_host, sessions } objects. Counted once per session, from the source the session entered on — not once per pageview.

Attribution metric: counts direct browser visits only (the user traffic class). AI-mediated traffic (ai_user_action, i.e. Claude or ChatGPT fetching on a user's behalf) is excluded from this list, because the AI sets its own host as the referrer or strips it. Including it would inflate "direct" or "claude.ai" without telling you where the human attention actually came from. Use traffic_class_breakdown to see the AI-mediated share separately.

The "AI-mediated human" lines above (perplexity.ai, chatgpt.com) ARE included here. Those are humans clicking through from those services in their browser, not the AI fetching for them. That distinction matters for understanding AI's role in your acquisition funnel.

Arguments

Name Type Required Description / Default
site_id string required Site identifier from list_sites (8-character base32, e.g. 'wjxayhdd').
period string optional Time window. Keywords: today, yesterday, last_N_days (N from 1 to 730: today plus the N-1 days before, e.g. last_7_days, last_28_days), last_24_hours, this_week, last_week (weeks start on Monday), this_month, last_month, this_year, last_year, last_12_months. Or a custom date range YYYY-MM-DD..YYYY-MM-DD (inclusive). Days follow the site's timezone (list_sites; echoed as `timezone` in every response).
default: last_7_days
limit integer optional Maximum number of rows to return. Capped at 1000 server-side.
default: 10
group_by string
enum: host, channel
optional host (default): one row per referring host; sessions without a referrer are left out. channel: one row per channel (search, ai_assistant, social, email, paid, campaign, referral, direct), decided by the session's entry. utm_medium wins over the host (utm_medium=email on a Gmail link is email; paid comes only from utm_medium such as cpc), then the referring host; no referrer and no utm is direct, utm tags without a referrer are campaign, unknown hosts are referral. direct is included, so percentage_of_total is a percentage of ALL entry sessions. Each row has top_hosts: its three most frequent entry hosts (utm_source values for rows without a host, [] for direct). conversion_event works per channel.
default: host
conversion_event string optional Optional custom event name (case-sensitive, from list_events) to treat as the conversion. Each row then gains conversion_base (units in that row), converted (how many of them fired the event anywhere in the period) and conversion_rate (ratio 0–1: 0.05 means 5%; null when no unit is attributed to the row: it has no browser sessions/visitors at all, e.g. purely server-ingested traffic, or — on privacy_mode=all sites in top_referrers/top_sources/top_entry_pages — the row was never any visitor's first entry in the period, even though it has sessions). The response gains a site-wide `conversion` block: conversion_base (units in the period), converted (how many fired the event), conversion_rate (ratio 0–1: 0.05 means 5%), `unit` and a `note` to relay. Use it to compare conversion rates between rows — absolute counts alone favour whatever row has the most traffic. The unit depends on the site's privacy_mode: 'session' on strict and balanced sites (no identity survives UTC midnight there, so only conversions within one visit count), 'visitor' on privacy_mode=all sites (first-party cookie, so a visitor who arrives Monday and converts Thursday counts as converted, if both days are inside the period). The auto-tracked 'pageview' and 'engagement' are rejected — pick one of the site's own events. Revenue: if the event carries a numeric `revenue` property (optional `currency`, e.g. mcpa('track', 'purchase', { revenue: 149, currency: 'EUR' })), each row gains revenue (sum over the conversion events of the units in that row; like conversion_base, not additive across rows where a unit appears in several) and revenue_per_unit (revenue / conversion_base), and the block gains revenue_total (over the converted units), currency (null when none was sent) and revenue_events (events with a numeric value; other values are ignored). Values are as reported by the site, not verified; negative values (refunds) are summed as sent. Only three-letter currency codes count as a currency; other values are unspecified. With two or more codes nothing is converted or added across codes: revenue_total, revenue_events and the rows' revenue cover the dominant code (most distinct converting units; itself visitor-influenced) plus values without a code, and the block adds revenue_by_currency listing each code with its own count. Not available with conversion_path.
conversion_path string optional Optional goal page, the alternative to conversion_event (pass one, not both): a unit counts as converted if it has a pageview on this path anywhere in the period, so no custom event is needed and it works on past data. '/thank-you' matches that path exactly (a trailing slash on either side is ignored); a trailing * matches by prefix ('/checkout/success*'). Must start with '/'. Matched case-sensitively against the stored path, which has no query string and stores credential-like segments (long random tokens, UUIDs) as [redacted], so a goal containing one never matches. Only pageviews count: an engagement beacon or custom event on that page does not. Fields, unit (session, or visitor on privacy_mode=all sites) and the `conversion` block are as for conversion_event; the block names `path` and `match` (exact or prefix) instead of `event`. Filters narrow the units; the goal pageview counts anywhere in the period.
filters object optional Optional segment filter. All given keys must match (AND; no OR, no negation); an empty string means not set. Keys: path (exact) or path_prefix; device_type, browser, os (exact, case-sensitive); referrer_host, utm_source, utm_medium, utm_campaign (exact); channel (search, ai_assistant, social, email, paid, campaign, referral, direct; as top_referrers group_by: channel assigns it). path/path_prefix match rows: pageviews count rows on matching paths, sessions/visitors count those with at least one matching row, and bounce_rate/avg_session_duration_seconds use all rows of those sessions. referrer_host, utm_* and channel match the session's entry (its first pageview in the period) and then select every row of the matching sessions, in every privacy mode. In top_entry_pages, top_referrers, top_sources and get_overview's top_source, path/path_prefix also test the entry: path_prefix '/blog/' there means sessions that entered on /blog/. Source and device filters make every number browser-only: server-side-ingested rows (including AI-mediated ai_user_action) have no session and no device fields, so they never match; the response then adds a `filter_note`. In get_overview, bot_share is null under any key other than path/path_prefix. With conversion_event the filter narrows the units; the conversion itself still counts anywhere in the period. The applied filters are echoed back as `filters`.

How to call it directly

If you're integrating from your own code rather than a chat client, this is the JSON-RPC payload:

curl -X POST https://mcp-analytics.com/mcp \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "top_referrers",
    "arguments": {
      "site_id": "abc12345"
    }
  }
}'

Token comes from /settings after you sign up. Replace any required arguments above.

Related tools

  • add_site: Register a new site.
  • top_movers: What changed between two periods: the rows of one dimension that grew or shrank the most, in one call instead of diffing two list calls.
  • get_timeseries: Time-bucketed metric over a period.
  • compare_periods: Compare a metric between two periods.
  • list_events: All event names with counts (includes 'pageview' and custom events).