Next.js Integration
Edge-optimized AI agent detection for Next.js applications
Overview
The Checkpoint Next.js integration provides AI agent detection and enforcement for Next.js applications. With edge runtime optimization and full App Router support, it delivers protection with minimal performance impact.
- Edge Runtime Compatible — Runs at the edge for ultra-low latency
- < 2ms overhead — Minimal impact on response times
- Enforce or Observe modes — Active enforcement or log-only dry runs
- Route Matching — Fine-grained control over protected paths
- Policy Engine — Local policy evaluation with configurable rules
- TypeScript — Full type definitions included
Prerequisites
- A Checkpoint project — get your Project ID and API key from Installations in the dashboard.
- A Next.js app (App Router or Pages Router).
Installation
npm install @kya-os/checkpoint-nextjsQuick Setup
Next.js 16: middleware.ts → proxy.ts
proxy.ts and export a proxy function (a default export also works); middleware.ts exporting middleware still works but is deprecated. The Checkpoint setup below is identical either way — only the file name and export name change. One caveat: proxy.ts runs on the Node.js runtime only, so if you want Checkpoint on the Edge runtime (lowest latency), keep the file as middleware.ts. On Next.js 15 and earlier, use middleware.ts.1. Create Middleware
Create middleware.ts in your project root:
import { withCheckpointApi } from '@kya-os/checkpoint-nextjs/api-middleware';
export default withCheckpointApi({
apiKey: process.env.CHECKPOINT_API_KEY,
});
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
],
};2. Add Environment Variables
# .env.local
CHECKPOINT_API_KEY=your_api_key_here3. Verify It's Running
Enforcement happens in the middleware, before your pages and route handlers run — blocked or challenged requests never reach your code, so handlers don't need their own detection checks. To confirm the middleware is active, inspect the response headers it stamps:
curl -sI https://your-site.example/ -A "GPTBot/1.0" | grep -i -e '^kya-' -e '^x-checkpoint'See Response Headers below for what to expect in the output.
1. Create Middleware
Create middleware.ts in your project root:
import { withCheckpointApi } from '@kya-os/checkpoint-nextjs/api-middleware';
export default withCheckpointApi({
apiKey: process.env.CHECKPOINT_API_KEY,
});
export const config = {
matcher: '/:path*',
};2. API Route Protection
API routes matched by the matcher are protected by the middleware itself — a request that your policy blocks is answered with the verdict (403, redirect, or challenge) before pages/api/* handlers execute. Your handlers stay unchanged:
// pages/api/protected.ts
import type { NextApiRequest, NextApiResponse } from 'next';
export default function handler(req: NextApiRequest, res: NextApiResponse) {
// Only requests your policy allows ever reach this point.
res.status(200).json({ data: 'Protected data' });
}Tune what gets blocked in your dashboard policy, not in handler code.
Local Engine Middleware
The package ships two deployment shapes. withCheckpointApi (above) dispatches to the Checkpoint SaaS gateway over HTTPS. withCheckpoint runs the detection engine in-process (WASM) — lowest latency, deterministic verdicts, no per-request network hop:
// middleware.ts
import { withCheckpoint } from '@kya-os/checkpoint-nextjs';
export default withCheckpoint({
tenantHost: 'your.tenant.example',
apiKey: process.env.CHECKPOINT_API_KEY, // optional — enables dashboard reporting
projectId: process.env.CHECKPOINT_PROJECT_ID, // optional — enforces your deployed Cedar policy
});
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)'],
};The legacy createEnhancedAgentShieldMiddleware and withAgentShield exports are deprecated
migration stubs — createEnhancedAgentShieldMiddleware throws at runtime. Use withCheckpoint
(local engine) or withCheckpointApi (SaaS gateway) instead.
See Middleware Enforcement for the full config reference for both shapes.
Configuration
import { withCheckpointApi } from '@kya-os/checkpoint-nextjs/api-middleware';
export default withCheckpointApi({
apiKey: process.env.CHECKPOINT_API_KEY, // or set the CHECKPOINT_API_KEY env var
// Optional
onBlock: 'block', // 'block' | 'redirect' | 'challenge' — default: dashboard policy
redirectUrl: '/for-ai', // target when onBlock is 'redirect'
useEdge: true, // edge detection (~30–50ms, catches non-JS clients) — default: true
timeout: 5000, // request timeout in ms
});See Middleware Enforcement for the complete option tables for withCheckpointApi and withCheckpoint.
Environment Variables
# .env.local
CHECKPOINT_API_KEY=your_api_key_hereEnforce vs Observe Mode
| Mode | Behavior |
|---|---|
observe | Classifies every request and stamps X-Checkpoint-Would-Have-Been headers. All traffic passes through. |
enforce | Classifies requests and applies the policy verdict (block, redirect, or challenge for consent/identity). Default. |
On the local-engine shape, start with withCheckpoint({ enforcementMode: 'observe', ... }) to understand your traffic, review the would-have-been decisions in the dashboard, then switch to enforce when ready. On the SaaS shape (withCheckpointApi), enforcement follows your dashboard policy — deploy the policy in observe mode instead.
Response Headers
The SaaS shape (withCheckpointApi) sets KYA-* headers (KYA-Detected, KYA-Confidence, KYA-Agent on allowed agent traffic; KYA-Action / KYA-Reason on enforcement). The local-engine shape (withCheckpoint) sets X-Checkpoint-* headers and a __checkpoint_verdict cookie, adding X-Checkpoint-Would-Have-Been in observe mode.
See Middleware Enforcement for the full header list shared with Express and .NET.
Client-Side Detection
This package is server-side middleware — it does not ship client-side detection hooks. (The legacy useAgentDetection hook was removed along with the AgentDetector class it wrapped.) For client-side detection — conditionally rendering content, tracking agent visits from the browser — use the JavaScript Beacon or the Marketing Pixel alongside the middleware.
Edge Runtime
Checkpoint middleware runs on the Next.js Edge Runtime. withCheckpointApi dispatches to the Checkpoint edge over HTTPS, and route handlers behind it need no detection code of their own — enforcement has already happened by the time they run:
// app/api/protected/route.ts
export const runtime = 'edge';
export async function GET() {
// Only requests your policy allows ever reach this point.
return new Response('Protected data');
}Content Security Policy
If your site uses CSP headers and you're also using the Pixel, add the Checkpoint domain:
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'Content-Security-Policy',
value: [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' https://kya.vouched.id",
"connect-src 'self' https://kya.vouched.id",
].join('; '),
},
],
},
];
},
};Troubleshooting
Middleware not running
- Ensure
middleware.tsis in the project root (not insideapp/orsrc/) - Check the
matcherconfiguration - Verify the file exports a default function
Detection not working
- Verify
CHECKPOINT_API_KEYis set — without it, detections never reach the dashboard - Check for API calls to
kya.vouched.id(SaaS shape) in your server logs - Enable
debug: truefor detailed logs
Performance issues
- Prefer
withCheckpoint(in-process WASM engine) — no per-request network hop - Keep
useEdge: trueonwithCheckpointApifor the lower-latency edge path - Scope the
matcherso static assets and health checks bypass the middleware
Next Steps
- Middleware Enforcement — Complete middleware documentation with all features
- Policies — Configure enforcement rules
- Gateway — DNS-based enforcement (no code changes)
- Express Integration — Server-side middleware for Express
- Choose Your Integration — Compare all integration options
