Docs › Developers
Forward bots from your server
Many AI crawlers only fetch your HTML and never run the script. Let your server forward them, without IP addresses, to see them too.
Why
Many AI crawlers, such as GPTBot, ClaudeBot and CCBot, only fetch the HTML and never load the script, so a JavaScript tracker never sees them. Let your own server forward those requests and they show up on the Bots and AI tabs too.
What Nvivio receives: which bot, which page, and optionally the country and network. Never an IP address. Requests from people are not stored. Once your server sends the first bot, the script only counts bots that pretend to be a browser, so nothing is counted twice.
Set it up
- Open Settings › Bots via your server (
/app/<your-domain>/settings#server-bots). - Make a key. You see it once; only its hash is stored.
- Copy the code for Cloudflare, Next.js, WordPress or another server. Your site code and key are already filled in.
- The status switches to “It works” by itself when the first bot arrives.
On WordPress with a page cache, cached pages never reach PHP: use the Cloudflare version instead.
Every example checks the user agent first, forwards pages only (no images or files), sends no IP address and does not wait for the answer, so your pages are never slower.
Example: Cloudflare Worker
Put this Worker on the route of your site (for example example.com/*). It also works for sites behind Cloudflare’s page cache.
// Nvivio: forward bots that only fetch the HTML (never an IP address).
const NVIVIO = { site: 'NV-XXXXXXX', key: 'YOUR_KEY' };
const BOT = /^(?!Mozilla\/5\.0 \()|bot|crawl|spider|scrap|slurp|fetch|http|preview|compatible|agent|headless|phantom|lighthouse|monitor|uptime|archive|cardyb|siteimprove|sitebulb|screaming|seobility|megaindex|hetrix|freshping|datadog|newrelic|vkshare/i;
const PAGE = /(^|\/)[^.\/]*$|\.(html?|php)$/i;
export default {
async fetch(request, env, ctx) {
const response = await fetch(request);
const ua = request.headers.get('user-agent') ?? '';
if (request.method === 'GET' && PAGE.test(new URL(request.url).pathname) && BOT.test(ua)) {
ctx.waitUntil(fetch('https://nviv.io/b', {
method: 'POST',
headers: { 'content-type': 'application/json', authorization: `Bearer ${NVIVIO.key}` },
body: JSON.stringify({ s: NVIVIO.site, u: request.url, a: ua, c: request.cf?.country, o: request.cf?.asOrganization })
}));
}
return response;
}
};
The dashboard gives you the same code with your site code and key filled in, and the versions for Next.js (middleware) and WordPress (a small plugin).
Build your own
Send a POST to https://nviv.io/b:
POST https://nviv.io/b
Authorization: Bearer nvb_…
Content-Type: application/json
{"s": "NV-XXXXXXX", "u": "https://example.com/pricing", "a": "<user agent>", "c": "BE", "o": "<network>"}
| Field | Meaning |
|---|---|
s |
Your site code. |
u |
The full address of the page. |
a |
The user agent of the request. |
c |
Optional: the two-letter country code. |
o |
Optional: the name of the network. |
Add "test": true to check the connection without counting anything. Like every error from Nvivio, an error answer has an error and a fix.
API for the key: GET, POST and DELETE /v1/sites/{site}/bot-key.