Skip to main content

AI

Referrals

People who arrived from an assistant's answer, and the page they landed on.

GET/sites/{siteId}/ai/referrals
Referrals
curl --request GET \
  --url 'https://truestat.io/api/v1/sites/{siteId}/ai/referrals' \
  --header 'Authorization: Bearer <token>'
{
  "data": [
    {
      "path": "/tools/instagram-handle-checker",
      "views": 4,
      "source": "chatgpt.com",
      "visitors": 2
    }
  ],
  "meta": {
    "page": {
      "limit": 100,
      "offset": 0,
      "has_more": false
    },
    "range": {
      "to": "2026-09-16T13:40:00.000Z",
      "tz": "UTC",
      "from": "2026-09-09T13:40:00.000Z",
      "clamped": false
    },
    "site_id": "6fed8980-a119-4a9c-a4d4-53e448ef9f9e"
  }
}

The people who came to your site from ChatGPT, Perplexity and their neighbours — and the page each one landed on.

The one endpoint here that counts people

Everything else under /ai/ counts machines. This counts visitors, and they are ordinary visitors: they appear in your overview totals, in /breakdowns/path, and in your goals if they convert. Nothing here is a separate universe of traffic.

What this endpoint adds is the pairing. source is the assistant that sent them and path is where they landed, so a row says this assistant pointed somebody at this page and they went.

That is as close to a citation report as the web allows. Assistants do not publish who they cite. A referral is the visible half: somebody saw your page named in an answer and clicked.

Reading the numbers honestly

Referral counts from assistants are small, and they are small for structural reasons rather than because something is broken:

  • An answer often satisfies the question. The reader never needs the source.

  • Some assistants strip the referrer, so the visit arrives unattributed and lands under direct traffic instead.

  • Citation is not guaranteed even when your page was used.

So treat this as a floor, not a total. It undercounts, and the honest version of that statement is worth more than a bigger number arrived at by guessing.

The trend is usually the useful part: which pages start getting cited after you rewrite them, and which assistants send people at all.

Compare it with what was crawled

Put this next to pages crawled. Heavy crawling with no referrals means your pages are being read into models rather than recommended to readers; referrals from a page nothing crawls recently means an older fetch is still being cited.

visitors counts distinct people and views counts their page views, so views is the larger number when somebody reads more than one page.

Authorizations

Authorizationstringheaderrequired

An API key from Settings → API keys. Scopes available: analytics:read, sites:read, sites:write, settings:read, settings:write, goals:read, goals:write, funnels:read, funnels:write, notes:read, notes:write, alerts:read, alerts:write, team:read, team:write, revenue:read, revenue:write.

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Path parameters

siteIdstring (uuid)pathrequired
The site's id, from `GET /sites`. A site that is not yours and a site that does not exist both answer 403, so this cannot be used to discover other people's ids.

Query parameters

periodenum<string>query
A named window, resolved in `tz`. Cannot be combined with `from`/`to` — a request carrying both is refused rather than guessed at.
options:todayyesterdaylast24hlast7dlast30dlast12mmonthyearall
fromstring (date-time)query
Start of the window, ISO 8601 with an offset. Must be given together with `to`.
tostring (date-time)query
End of the window. Must be given together with `from`.
tzstringquerydefault: UTC
IANA timezone for day boundaries. `period=today&tz=Europe/Istanbul` means the reader's today, not the server's. Defaults to UTC.
botsenum<string>querydefault: excluded
Whether crawler traffic is counted. Excluded by default — the `/ai/*` endpoints report it separately and always include it.
options:excludedincluded
limitintegerquerydefault: 100
Rows per page, 1 to 1000.
offsetintegerquerydefault: 0
Rows to skip.
filter_pathstringquery
Narrow the result to one `path`.
filter_path_patternstringquery
Narrow the result to one `path_pattern`.
filter_hostnamestringquery
Narrow the result to one `hostname`.
filter_entry_pathstringquery
Narrow the result to one `entry_path`.
filter_exit_linkstringquery
Narrow the result to one `exit_link`.
filter_file_downloadstringquery
Narrow the result to one `file_download`.
filter_goalstringquery
Narrow the result to one `goal`.
filter_browserstringquery
Narrow the result to one `browser`.
filter_osstringquery
Narrow the result to one `os`.
filter_devicestringquery
Narrow the result to one `device`.
filter_countrystringquery
Narrow the result to one `country`.
filter_regionstringquery
Narrow the result to one `region`.
filter_citystringquery
Narrow the result to one `city`.
filter_referrerstringquery
Narrow the result to one `referrer`.
filter_channelstringquery
Narrow the result to one `channel`.
filter_utm_sourcestringquery
Narrow the result to one `utm_source`.
filter_utm_mediumstringquery
Narrow the result to one `utm_medium`.
filter_utm_campaignstringquery
Narrow the result to one `utm_campaign`.
filter_gad_campaign_idstringquery
Narrow the result to one `gad_campaign_id`.
filter_utm_termstringquery
Narrow the result to one `utm_term`.
filter_bot_kindstringquery
Narrow the result to one `bot_kind`.

Response

application/json

The answer.

dataunknown
See the example.
metaobject