npm.io
1.4.0 • Published 2d ago

@foglift/tracker

Licence
MIT
Version
1.4.0
Deps
0
Size
87 kB
Vulns
0
Weekly
0

@foglift/tracker

Track AI crawler visits and AI engine referrals to your website. See which AI engines (ChatGPT, Claude, Perplexity, Gemini, Copilot) are crawling your content and sending you human visitors.

  • Two signals, one install. UA-detected bot visits + Referer/utm_source-detected human visits from AI engines.
  • Zero customer install friction. One-line middleware in Next.js, Express, or plain Node.
  • Cookieless. No fingerprinting. Only the visit's path, the matched UA category, and the matched referrer host or UTM marker are sent to Foglift.
  • Fire-and-forget. Reporting never blocks your request lifecycle.

Install

npm install @foglift/tracker

Copy your workspace ID from Foglift's AI Traffic install panel. It is a publishable identifier, not a secret, and works on every plan. Existing API-key installs remain supported.

Quickstart — Next.js

// middleware.ts
import { trackAITraffic } from "@foglift/tracker/nextjs";

export const middleware = trackAITraffic({
  siteToken: "YOUR_WORKSPACE_ID",
});

export const config = {
  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};

That's it. Within ~5 seconds of a real ChatGPT/Claude/Perplexity user clicking through to your site, a row lands in your dashboard at https://foglift.io/dashboard/crawlers.

Composing with an existing middleware
import { trackAITraffic } from "@foglift/tracker/nextjs";
import { auth } from "./auth-middleware";

export const middleware = trackAITraffic({
  siteToken: "YOUR_WORKSPACE_ID",
  next: auth,
});

Quickstart — Express

import express from "express";
import { trackAITraffic } from "@foglift/tracker/express";

const app = express();
app.use(trackAITraffic({ siteToken: "YOUR_WORKSPACE_ID" }));

Quickstart — plain Node (any framework)

import http from "node:http";
import { createAITrafficTracker } from "@foglift/tracker/node";

const tracker = createAITrafficTracker({ siteToken: "YOUR_WORKSPACE_ID" });

http
  .createServer((req, res) => {
    tracker.track(req);
    res.end("ok");
  })
  .listen(3000);

Quickstart — Cloudflare Workers

import { trackAITrafficWorker } from "@foglift/tracker/cloudflare";

export default {
  fetch: trackAITrafficWorker({ siteToken: "YOUR_WORKSPACE_ID" }),
};

Every server adapter derives the hostname from the request and sends it with the publishable token. Foglift accepts the event only when that hostname belongs to the workspace.

What gets reported

trackAITraffic emits one of two visit shapes per matching request, then drops the call. Nothing is reported if neither the UA, Referer, nor supported utm_source matches — the vast majority of your traffic is invisible to Foglift.

API-key compatibility and multi-brand attribution

Existing API-key installs continue to work. Multi-brand API-key accounts should pass the selected Foglift brand UUID as brandId:

trackAITraffic({
  apiKey: process.env.FOGLIFT_API_KEY!,
  brandId: process.env.FOGLIFT_BRAND_ID,
});

The SDK serializes brandId as brand_id in the reporting payload. Single-brand accounts can omit it.

Crawler visits (UA wins over Referer)

When the User-Agent matches a known AI-related agent, the visit is reported as source: "crawler" with its matched name, engine, and documented role: training, indexing, user_fetch, mixed, or owner_requested. mixed is reserved for agents whose documented uses cross categories; owner_requested identifies a crawl initiated by a site owner to build an agent. A user_fetch means the matched agent is documented for end-user answers; it is citation-proximate, not proof of citation. User-Agent strings can be spoofed, so verify vendor IP ranges before treating an individual request as authoritative.

When the User-Agent looks human but the Referer header points at one of the canonical AI search hostnames, the visit is reported as source: "referrer". If the Referer host is absent or non-AI, the tracker falls back to utm_source values commonly used by AI engines, such as chatgpt, openai, perplexity, claude, anthropic, gemini, bard, and copilot. Referer-host matches always win, so a request with both signals is reported once.

Engine Hostname(s) tracked
ChatGPT chatgpt.com, chat.openai.com
Claude claude.ai
Perplexity perplexity.ai, www.perplexity.ai
Gemini gemini.google.com
Copilot copilot.microsoft.com
NotebookLM notebooklm.google.com

Google AI Overview disambiguation (parsing udm=/ved= on google.com referrers) is intentionally out of scope for v1.2.0 — google.com referrers stay classified as organic search by your host application. Tracked for v1.3.

Privacy

  • No cookies, no fingerprinting. The tracker reads the request's User-Agent, Referer header, and path — nothing else.
  • No PII. The Referer is parsed for hostname only; query parameters are discarded before reporting.
  • HTTPS reporting. Visits are posted to https://foglift.io/api/v1/crawler-analytics with a hostname-bound publishable workspace ID. Legacy API-key installs continue to use the X-API-Key header.
  • Fire-and-forget. A failed report logs (only when debug: true) and never throws.

Migrating

Migrating to v1.4.0

New installs should use siteToken. Existing apiKey and optional brandId configuration remains backward compatible, so upgrading does not require an immediate configuration change.

trackAITraffic({ siteToken: "YOUR_WORKSPACE_ID" });
From v1.1.0

If you're upgrading from @foglift/tracker@1.1.0, the trackAICrawlers export still works and now additionally reports referrer visits — no code change required, you get the new signal for free. The export will warn in v1.3 and be removed in v2.0; switch to trackAITraffic at your convenience.

// v1.1.0 (still works, additive in v1.2.0)
import { trackAICrawlers } from "@foglift/tracker/nextjs";

// v1.2.0 — preferred
import { trackAITraffic } from "@foglift/tracker/nextjs";

The crawler-visit payload shape is byte-identical to v1.1.0 (with one additive source: "crawler" field) — receiver-side aggregation is unchanged for existing crawler customers.

Debugging

trackAITraffic({
  apiKey: process.env.FOGLIFT_API_KEY!,
  debug: true,
});

In debug mode, failed reports log to console.warn with the HTTP status and error message. Disable in production.

Manual classification helpers

If you'd rather drive the classification yourself (e.g. you already have a custom analytics pipeline), the detectors are exported as pure functions:

import { detectAICrawler, detectAIReferrer } from "@foglift/tracker";

detectAICrawler("Mozilla/5.0 (compatible; PerplexityBot/1.0)");
//=> { crawler: "PerplexityBot", engine: "Perplexity" }

detectAIReferrer("https://chatgpt.com/c/abc123");
//=> { source: "chatgpt.com", engine: "ChatGPT" }

Both return null on no-match.

Keywords