@usesapient/agent-tracker
v0.1.1
Published
Track AI coding agents visiting your site. Works with Next.js, Vercel, Cloudflare, Express.
Maintainers
Readme
@sapient/agent-tracker
Track AI coding agents visiting your documentation. Works with Next.js, Vercel, Cloudflare, and Express.
Installation
npm install @sapient/agent-trackerQuick Start
Next.js
// middleware.ts
import { withAgentTracking } from "@sapient/agent-tracker/next";
export default withAgentTracking({ apiKey: "sap_..." });
export const config = {
matcher: ["/((?!api|_next|admin).*)"],
};Vercel (Remix, SvelteKit, Astro, Nuxt)
// middleware.ts
import { withAgentTracking } from "@sapient/agent-tracker/vercel";
export default withAgentTracking({ apiKey: "sap_..." });
export const config = {
matcher: "/((?!_next|api|favicon.ico|assets|.*\\..*).)",
};Cloudflare Pages
// functions/_middleware.ts
import { onRequest as withTracking } from "@sapient/agent-tracker/cloudflare";
export const onRequest = withTracking({ apiKey: "sap_..." });Cloudflare Workers
import { withAgentTracking } from "@sapient/agent-tracker/cloudflare";
const handler = {
async fetch(request, env, ctx) {
return new Response("Hello!");
},
};
export default {
fetch: withAgentTracking({ apiKey: "sap_..." }, handler.fetch),
};Express
import express from "express";
import { withAgentTracking } from "@sapient/agent-tracker/express";
const app = express();
app.use(withAgentTracking({ apiKey: "sap_..." }));Configuration
interface SapientConfig {
/** Your Sapient API key (starts with sap_). Required. */
apiKey: string;
/** Override the track endpoint (for self-hosting). */
endpoint?: string;
}Environment Variables
Instead of passing apiKey directly, you can set:
SAPIENT_API_KEY=sap_...
# or
SAPIENT_TRACKING_KEY=sap_...Then initialize without config:
// Next.js
import { withAgentTracking } from "@sapient/agent-tracker/next";
export default withAgentTracking({} as any); // reads from envWrapping Existing Middleware
All platform wrappers accept an optional second argument to wrap existing middleware:
Next.js
import { withAgentTracking } from "@sapient/agent-tracker/next";
import { NextResponse } from "next/server";
function myMiddleware(request) {
// your existing logic
return NextResponse.next();
}
export default withAgentTracking({ apiKey: "sap_..." }, myMiddleware);Express
// Tracking middleware runs before your routes
app.use(withAgentTracking({ apiKey: "sap_..." }));
app.use(yourOtherMiddleware);How It Works
The middleware intercepts requests and:
- Filters non-page requests — Only tracks requests with
Accept: text/htmlorAccept: text/markdown - Classifies visitors — Detects AI coding agents (Claude Code, Codex, OpenCode) by their unique headers
- Sends async — Tracking is non-blocking via
waitUntil()or fire-and-forget - Auto-creates sites — Sites are automatically registered when first event is received
What Gets Tracked
| Field | Source |
|-------|--------|
| host | Request hostname |
| path | Request pathname |
| user_agent | User-Agent header |
| accept | Accept header |
| country | Geo header (platform-specific) |
Detection Logic
AI coding agents are identified by requesting text/markdown in their Accept header — browsers never do this.
| Agent | Detection |
|-------|-----------|
| Claude Code | axios in UA + text/markdown |
| Codex | chatgpt-user in UA + text/markdown |
| OpenCode | Quality weights in Accept (q=0.9) |
API Reference
Core Functions
import { trackVisit, init } from "@sapient/agent-tracker";
// Initialize globally (optional - can pass config per-call)
init({ apiKey: "sap_..." });
// Track a visit manually
const result = await trackVisit({
host: "docs.example.com",
path: "/getting-started",
userAgent: "...",
accept: "text/html,text/markdown",
country: "US",
});
// => { ok: true, category: "coding-agent", agent: "claude-code" }Platform Exports
Each platform export includes:
// Next.js
import { withAgentTracking, trackVisit, init } from "@sapient/agent-tracker/next";
// Vercel
import { withAgentTracking, trackRequest, trackVisit, init } from "@sapient/agent-tracker/vercel";
// Cloudflare
import { withAgentTracking, onRequest, trackRequest, trackVisit, init } from "@sapient/agent-tracker/cloudflare";
// Express
import { withAgentTracking, trackVisit, init } from "@sapient/agent-tracker/express";Types
import type { SapientConfig, TrackOptions, TrackResult } from "@sapient/agent-tracker";
interface TrackResult {
ok: boolean;
category?: "coding-agent" | "browsing-agent" | "bot" | "human";
agent?: string;
skipped?: string; // "not-page-view" if filtered
error?: string;
}Performance
- Non-blocking — Uses
waitUntil()on edge platforms, fire-and-forget on Express - Timeout — 2.5s max, silently fails on timeout
- Filtered early — Asset requests (images, CSS, JS) are skipped before any network call
License
MIT
