/geo/traffic in the API.
What is captured
Every captured request is classified into one of two tracked visitor types:- AI crawler: bots fetching your pages to train models or build a search index. Each crawler carries a Purpose: Model training (collects pages for training corpora), Search index (builds the index an AI answer engine searches), or Cited in answer (fetched while an assistant was answering someone).
- AI referral: a person who clicked through to your site from an AI answer. Detection is based on the referrer host, for example chatgpt.com, perplexity.ai, gemini.google.com, claude.ai, copilot.microsoft.com, you.com, chat.deepseek.com, chat.mistral.ai, grok.com, and chat.qwen.ai.
Journeys
A journey groups the pages one agent read in a session. Two kinds exist:- Tagged journey: the agent followed a link carrying an
ntrquery parameter that your site minted. This is exact. - Fingerprinted journey: requests were matched by a heuristic: the source, a truncated IP prefix, and a 30 minute time bucket (10 minutes and the full IP for assistant browsing), hashed with a salt that rotates daily. This is an estimate.
Set up the tracker
1
Get your token
Open Traffic in the GEO sidebar. Until the first event arrives the page shows No activity yet with the full install panel: Install the package, Set your token, and Add the proxy. The token is shown in the Set your token section. The panel also has a Copy agent prompt button that copies an instruction block you can paste into a coding agent.From the API, reading the snippets needs Both return
traffic.read and issuing the token needs traffic.write:ingestUrl, snippet (the Next.js snippet), and snippets with next, nuxt, tanstack, astro, sveltekit, and netlify keys. The token endpoint adds token. The ingest routes are organization-level; pass projectId to bind the token to one project or omit it to track the whole organization. Issuing a token does not invalidate tokens issued earlier. Install the same project token on every domain the project tracks; add extra hostnames under Tracked domains in GEO settings.2
Install the package
3
Set the environment variable
Add the token as
NOTRA_GEO_TOKEN in your site’s environment variables, locally and at your hosting provider. Never hardcode or commit it.4
Add the proxy
Pick your framework. These are the snippets the dashboard generates; Use
endpoint is the origin the SDK posts to and the SDK appends /api/geo/ingest.- Next.js
- Nuxt
- TanStack Start
- Astro
- SvelteKit
- Netlify
proxy.ts
proxy.ts on Next.js 16 and middleware.ts on earlier versions. geo(request) never throws and never blocks the response.5
Deploy and wait for the first visit
The Traffic page switches from the install panel to the dashboard as soon as the first AI crawler or referral is stored.
Tracker options
Only
GET requests that look like pages are captured. Anything under /_next/, /_nuxt/, /_vercel/, /_astro/, /_app/immutable/, /static/, and any path ending in a common static extension is skipped. llms.txt and llms-full.txt are always captured. exclude entries can be a string prefix, a RegExp, or a (request, url) => boolean function.
The envelope contains the timestamp, method, URL, client IP, edge location headers when present, referer, user agent, accept and accept-language headers, and a request id. No request body, no cookies, and no other headers are read or sent. The POST uses keepalive and a 2 second timeout.
Journey tagging
@usenotra/geo/markdown exports mintJourneyId, getJourneyId, and tagMarkdownLinks so the links you hand to an agent in Markdown carry an ntr id and every follow-up request lands in the same journey. On Next.js you can instead pass tagLinks: true to createGeoProxy; the proxy then tags Markdown responses (.md, llms.txt, llms-full.txt) served to known AI agents on the way out, and html: true extends that to the anchors in HTML pages. Human visitors and search crawlers always receive the untouched origin response. Tagging needs no token.
Rotating the token
NOTRA_GEO_TOKEN everywhere before you rotate.
The Traffic page
Once events arrive the page shows three sections, each honouring the range picker:- A hero row with Crawlers, Referrals, and Total visit counts, each compared “vs. previous period”, and a daily trend chart.
- Sources: three groups — Crawlers (training and search-index bots), Cited (assistant-browse fetches while an engine answered someone), and Referrals. Columns are Source, Purpose, Visits, Markdown (visits that asked for Markdown; crawlers and cited only), Pages, and Last seen. Sources group by operator, for example OpenAI, Anthropic, Google, Perplexity, Microsoft, Meta, Instagram, Amazon, Apple, ByteDance, and Common Crawl. Instagram is its own source, not folded into Meta.
- Top pages by AI source: Page (host and path), Sources, and Visits. When a project tracks more than one domain, a domain filter narrows the table.
- Recent citations: the live event log with All visitors (AI crawler, AI referral) and All purposes (Model training, Search index, Cited in answer) filters. The domain filter on top pages also narrows this log. Live updates refresh every few seconds and can be paused.
Reading traffic from the API
All paths below are prefixed with/v1/projects/{projectId} and need traffic.read. Windowed endpoints accept days (1 to 365) or from/to (YYYY-MM-DD).
visitorTypes and categories on the log endpoint are comma-separated lists. categories accepts training-crawler, search-index, and assistant-browse.
configured. When it is false the traffic backend is not configured for the deployment and the payload is empty rather than an error.
Limits to keep in mind
User agent matching is spoofable
User agent matching is spoofable
Crawler classification relies on user agent signatures. Anyone can send a crawler’s user agent string. The Confidence value tells you how the signature was sourced; where an operator publishes IP ranges or a reverse DNS method, the signature table points at it, but Notra does not verify IPs at ingest.
A fetch is not proof of a citation
A fetch is not proof of a citation
The Cited in answer purpose means an assistant fetched the page while answering someone. It does not prove the answer quoted or linked the page.
Some agents cannot be detected
Some agents cannot be detected
Agents that cannot be honestly identified by user agent are deliberately absent from the signature table, including Pi, ChatGPT Atlas,
Google-Extended, and Applebot-Extended. Traffic from them is either discarded as human or attributed to a generic browser.Referrals depend on the referrer header
Referrals depend on the referrer header
AI referrals are recognised by referrer host. Clicks from apps that strip the referrer, or from hosts not in the list, are not counted.
Fingerprinted journeys are estimates
Fingerprinted journeys are estimates
Only journeys that followed a tagged
ntr link are exact. Fingerprinted journeys group requests by heuristic and can merge or split real sessions.Sampling reduces counts
Sampling reduces counts
If you set
sample below 1, every count in the Traffic page and API reflects the sampled fraction; Notra does not scale the numbers back up.Get the install snippets
API reference for the ingest setup route.
Agent feedback
The same SDK ships an MCP feedback tool for the agents using your product.