@kya-os/checkpoint-nextjs
v1.10.0
Published
Checkpoint Next.js middleware for AI agent detection (formerly @kya-os/agentshield-nextjs)
Readme
@kya-os/checkpoint-nextjs
Next.js middleware for Checkpoint AI agent detection and enforcement.
Features
- 🚀 Next.js Middleware: Edge-compatible middleware for all routes
- 🧩 Two Deployment Shapes: In-process WASM engine or SaaS gateway
- 🎯 Flexible Actions: Block, redirect, or challenge detected agents
- 🛡️ Edge Runtime: Optimized for Vercel Edge Functions
- 📊 Dashboard Reporting: Detections land in your Checkpoint dashboard
Two deployment shapes
This package ships two complementary middleware factories. Pick the one that fits your runtime; both are first-class and supported.
| Shape | Factory | Where verification runs | Use when |
| ---------------- | ------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Local engine | withCheckpoint | In-process, via WASM (kya-os-engine) | You want the lowest possible latency, deterministic verdicts, no network round-trip per request, and your runtime can load the WASM artifact (Vercel Node, Vercel Edge with the bundled artifact, Cloudflare Workers with nodejs_compat). This is the canonical Phase D output. |
| SaaS gateway | withCheckpointApi | Cloudflare DNS gateway (https://detect.checkpoint-gateway.ai) | You want centralized policy + dashboard rules without a redeploy, you're on a runtime where the WASM artifact won't load (bare-Edge, browser embedding), or you want a single HTTPS hop with cached verdicts. Trades ~30–50ms of edge latency for zero local engine state. |
Both factories return a Next.js middleware function — the request/response contract is identical. You can run both side-by-side in the same app on different routes if your policy demands it.
// middleware.ts — local engine
import { withCheckpoint } from '@kya-os/checkpoint-nextjs';
export default withCheckpoint({ tenantHost: 'demo.example' });
// middleware.ts — SaaS gateway
import { withCheckpointApi } from '@kya-os/checkpoint-nextjs';
export default withCheckpointApi({
apiKey: process.env.CHECKPOINT_API_KEY!,
onBlock: 'redirect',
redirectUrl: '/blocked',
});Pre-Phase-D the SaaS-gateway factory shipped as
withAgentShield; the name is preserved as a@deprecatedalias for one release. Same forAgentShieldClient/AgentShieldClientConfig→CheckpointApiClient/CheckpointApiClientConfig. New code should import theCheckpoint*names.
Installation
npm install @kya-os/checkpoint-nextjsQuick Start
Client-IP trust policy
Client-IP resolution defaults to the direct framework or socket peer. For a Next.js deployment behind Vercel, select the Vercel profile explicitly:
withCheckpoint({
tenantHost: 'your.tenant.example',
clientIpPolicy: { platform: 'vercel' },
});Forwarding headers are normalized and are not trusted by the middleware without a matching deployment profile. See the client-IP resolution runbook for the profile matrix and proxy-chain guidance.
Middleware Setup
Create middleware.js (or middleware.ts) in your project root:
import { withCheckpointApi } from '@kya-os/checkpoint-nextjs';
export default withCheckpointApi({
apiKey: process.env.CHECKPOINT_API_KEY,
});
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};Enforcement happens in the middleware, before your pages and route handlers run: blocked or challenged requests never reach your code. Tune what gets blocked in your Checkpoint dashboard policy.
Client-Side Detection
This package is server-side middleware; it does not ship client-side React
hooks. (The legacy useAgentDetection hook was removed along with the
AgentDetector class it wrapped.) For client-side detection, such as
conditionally rendering content or tracking agent visits from the browser,
use the JavaScript Beacon or the
Marketing Pixel alongside the
middleware.
Middleware Configuration
The SaaS-gateway shape (withCheckpointApi) accepts:
import { withCheckpointApi } from '@kya-os/checkpoint-nextjs';
export default withCheckpointApi({
// API key (or set the CHECKPOINT_API_KEY env var)
apiKey: process.env.CHECKPOINT_API_KEY,
// Action when an agent should be blocked: 'block' | 'redirect' | 'challenge'
// Default: uses the policy from your dashboard
onBlock: 'block',
// Target when onBlock is 'redirect'
redirectUrl: '/blocked',
// Skip enforcement for paths (glob patterns)
skipPaths: ['/api/webhooks', '/health'],
// Custom blocked response
blockedResponse: {
status: 403,
message: 'Access denied',
},
// Edge detection: lower latency, catches non-JS clients. Default: true
useEdge: true,
// Request timeout in ms. Default: 5000
timeout: 5000,
// Fail open (allow) on API errors. Default: true
failOpen: true,
// Observability callback when an agent is detected
onAgentDetected: async (request, decision) => {
console.log('Agent detected:', decision.reason);
},
// Enable debug logging
debug: false,
});The local-engine shape (withCheckpoint) takes a CheckpointConfig instead:
tenantHost (required), plus optional enforcementMode ('enforce' |
'observe'), apiKey (enables dashboard reporting), projectId (enforces
your deployed dashboard policy in-process), and more. See the
middleware docs for the
full option tables for both shapes.
Actions
Block Agents
export default withCheckpointApi({
apiKey: process.env.CHECKPOINT_API_KEY,
onBlock: 'block',
blockedResponse: {
status: 403,
message: 'Automated access not allowed',
headers: {
'Content-Type': 'application/json',
'X-Robots-Tag': 'noindex',
},
},
});Redirect Agents
export default withCheckpointApi({
apiKey: process.env.CHECKPOINT_API_KEY,
onBlock: 'redirect',
redirectUrl: '/blocked',
});By default a redirect verdict is delivered as an HTTP 401 "instruct"
envelope with a link header pointing the agent at the redirect URL, which
LLM fetchers surface as a clickable link. Set redirectMode: 'http' for a
legacy 302 response (only useful when your traffic is real browsers).
Custom Logic
customBlockedResponse runs when the verdict is a block; whatever it
returns becomes the response:
import { NextResponse } from 'next/server';
export default withCheckpointApi({
apiKey: process.env.CHECKPOINT_API_KEY,
customBlockedResponse: async (request, decision) => {
if (decision.confidence > 0.9) {
// High confidence: hard block
return NextResponse.json({ error: 'Blocked' }, { status: 403 });
}
// Lower confidence: send to a verification page instead
return NextResponse.redirect(new URL('/verify', request.url));
},
});API Routes Integration
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 your route handlers execute. Handlers need no
detection code of their own:
// app/api/protected/route.js
import { NextResponse } from 'next/server';
export async function GET() {
// Only requests your policy allows ever reach this point.
return NextResponse.json({ data: 'Protected content' });
}Advanced Usage
Path-Specific Configuration
Use includePaths and skipPaths (glob patterns) to scope enforcement
without touching the matcher:
import { withCheckpointApi } from '@kya-os/checkpoint-nextjs';
export default withCheckpointApi({
apiKey: process.env.CHECKPOINT_API_KEY,
// Only enforce on these paths (overrides dashboard policy)
includePaths: ['/api/*', '/admin/*'],
// Never enforce on webhooks or health checks
skipPaths: ['/api/webhooks', '/health'],
});TypeScript Support
Full TypeScript support with proper types:
import type { NextRequest } from 'next/server';
import {
withCheckpointApi,
type CheckpointApiMiddlewareConfig,
type EnforcementDecision,
} from '@kya-os/checkpoint-nextjs';
const config: CheckpointApiMiddlewareConfig = {
onBlock: 'block',
onAgentDetected: async (request: NextRequest, decision: EnforcementDecision) => {
// Fully typed parameters
console.log(decision.confidence);
},
};
export default withCheckpointApi(config);Examples
E-commerce Protection
// Protect product pages from scrapers
import { withCheckpointApi } from '@kya-os/checkpoint-nextjs';
export default withCheckpointApi({
apiKey: process.env.CHECKPOINT_API_KEY,
onBlock: 'redirect',
redirectUrl: '/captcha',
skipPaths: ['/api/webhooks', '/health'],
});
export const config = {
matcher: ['/products/:path*', '/search/:path*'],
};Content Publishing
// Allow search engines through, block other agents
import { NextResponse } from 'next/server';
import { withCheckpointApi } from '@kya-os/checkpoint-nextjs';
export default withCheckpointApi({
apiKey: process.env.CHECKPOINT_API_KEY,
customBlockedResponse: async (request, decision) => {
const userAgent = request.headers.get('user-agent') || '';
// Let known search engines continue even when the policy blocks
if (/googlebot|bingbot|slurp/i.test(userAgent)) {
return NextResponse.next();
}
return NextResponse.json(
{ error: 'Bot access restricted', reason: decision.reason },
{ status: 403 }
);
},
});License
MIT OR Apache-2.0
Browser integrity
For opt-in classification, signed posture and scoped consent step-up, see the browser integrity rollout runbook.
