Checkpoint Docs
Cookbooks

Detect: Middleware Detection

Add server-side AI agent detection to Next.js or Express applications

Goal

Add server-side AI agent detection to your Next.js or Express application using Checkpoint middleware. By the end of this cookbook, you'll have:

  • Server-side detection running on every request
  • Detection data flowing to your dashboard
  • Access to detection results in your route handlers
  • Foundation ready for enforcement (blocking) when you're ready

Best for: Applications that need server-side detection without blocking, or as a stepping stone to enforcement.

Prerequisites

  • A Checkpoint account with a project created
  • A Next.js 13+ or Express 4+ application
  • Node.js 16+

Time Estimate

20 minutes


Steps

Install the Middleware Package

npm install @kya-os/agentshield-nextjs
npm install @kya-os/agentshield-express

Get Your API Key

  1. Log into your Checkpoint dashboard
  2. Select your project
  3. Go to Settings → API Keys
  4. Click Create API Key
  5. Copy the key (it starts with as_)

Add it to your environment:

# .env.local
AGENTSHIELD_API_KEY=as_live_xxxxxxxxxxxx
CHECKPOINT_PROJECT_ID=proj_abc123def456

Never commit API keys to source control. Use environment variables or a secrets manager.

Configure the Middleware

Create or update middleware.ts in your project root:

// middleware.ts
import { withAgentShield } from '@kya-os/agentshield-nextjs/api-middleware';

export default withAgentShield({
  apiKey: process.env.AGENTSHIELD_API_KEY!,
  // No onBlock — detection only, no enforcement
});

export const config = {
  matcher: [
    // Match all paths except static assets
    '/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
  ],
};

This runs detection on every request but doesn't block anything.

Add the middleware to your Express app:

// app.ts or server.ts
import express from 'express';
import { createEnhancedAgentShieldMiddleware } from '@kya-os/agentshield-express';

const app = express();

// Add detection middleware
app.use(
  createEnhancedAgentShieldMiddleware({
    projectId: process.env.CHECKPOINT_PROJECT_ID!,
    mode: 'detect', // Detection only, no blocking
    onDetection: (event) => {
      console.log(`Detected ${event.detectionClass} with ${event.confidence}% confidence`);
    },
  })
);

// Your routes
app.get('/', (req, res) => {
  // Access detection data via req.agentShield
  const detection = req.agentShield;

  res.json({
    message: 'Hello!',
    visitor: {
      class: detection?.detectionClass,
      confidence: detection?.confidence,
    },
  });
});

app.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});

Access Detection Data in Routes

Detection data is available in request headers:

// app/api/protected/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) {
  // Detection class is added to headers by middleware
  const detectionClass = request.headers.get('kya-class');
  const confidence = request.headers.get('kya-confidence');
  const agentName = request.headers.get('kya-agent-name');

  return NextResponse.json({
    message: 'API response',
    detection: {
      class: detectionClass,
      confidence: confidence ? parseInt(confidence, 10) : null,
      agentName: agentName || null,
    },
  });
}
// pages/api/protected.ts
import type { NextApiRequest, NextApiResponse } from 'next';

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  // Detection class is added to headers by middleware
  const detectionClass = req.headers['kya-class'];
  const confidence = req.headers['kya-confidence'];

  res.json({
    message: 'API response',
    detection: {
      class: detectionClass,
      confidence: confidence ? parseInt(String(confidence), 10) : null,
    },
  });
}

Detection is available on the request object:

// routes/api.ts
import express from 'express';

const router = express.Router();

router.get('/data', (req, res) => {
  const detection = req.agentShield;

  // Log AI agents for monitoring
  if (detection?.detectionClass === 'ai_agent') {
    console.log(`AI Agent ${detection.agentName} accessing /api/data`);
  }

  res.json({
    data: 'your data here',
    detection: {
      class: detection?.detectionClass,
      confidence: detection?.confidence,
      agentName: detection?.agentName,
    },
  });
});

export default router;

Add Logging and Monitoring

Create a detection handler to log activity:

// middleware.ts
import { withAgentShield } from '@kya-os/agentshield-nextjs/api-middleware';

export default withAgentShield({
  apiKey: process.env.AGENTSHIELD_API_KEY!,
  onDetection: async (detection, request) => {
    // Log AI agents
    if (detection.detectionClass === 'ai_agent') {
      console.log(
        JSON.stringify({
          event: 'ai_agent_detected',
          agent: detection.agentName,
          confidence: detection.confidence,
          path: request.nextUrl.pathname,
          timestamp: new Date().toISOString(),
        })
      );
    }

    // Send to your analytics/monitoring
    // await logToDatadog(detection);
    // await sendToSlack(detection);
  },
});

export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};
// middleware/detection-logger.ts
import { createEnhancedAgentShieldMiddleware } from '@kya-os/agentshield-express';

export const detectionMiddleware = createEnhancedAgentShieldMiddleware({
  projectId: process.env.CHECKPOINT_PROJECT_ID!,
  mode: 'detect',
  onDetection: (event) => {
    // Structured logging
    console.log(
      JSON.stringify({
        event: 'agent_detection',
        class: event.detectionClass,
        confidence: event.confidence,
        agentName: event.agentName,
        path: event.request.path,
        ip: event.request.ip,
        userAgent: event.request.headers['user-agent'],
        timestamp: new Date().toISOString(),
      })
    );

    // Alert on high-confidence AI agents
    if (event.detectionClass === 'ai_agent' && event.confidence > 80) {
      // alertOps(`High-confidence AI agent: ${event.agentName}`);
    }
  },
});

Test the Integration

Test as a normal user:

curl http://localhost:3000/api/protected
# Should return detection.class: "human"

Test as an AI agent:

curl -H "User-Agent: Mozilla/5.0 (compatible; GPTBot/1.0; +https://openai.com/gptbot)" \
  http://localhost:3000/api/protected
# Should return detection.class: "ai_agent"

Test as a bot:

curl -H "User-Agent: Googlebot/2.1" \
  http://localhost:3000/api/protected
# Should return detection.class: "bot"

Verify It's Working

Dashboard Check

  1. Visit your Checkpoint dashboard
  2. Select your project
  3. Go to Analytics
  4. You should see detections from your test requests

Log Check

If you added logging, check your console:

{
  "event": "agent_detection",
  "class": "ai_agent",
  "confidence": 85,
  "agentName": "ChatGPT",
  "path": "/api/protected",
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Troubleshooting

Middleware Not Running

SymptomCauseFix
No detection headersMiddleware not loadedCheck middleware.ts is in project root
Detection always nullMatcher not matchingReview config.matcher patterns
"API key invalid" errorWrong keyCopy key from dashboard again

Detection Always "incomplete_data"

This means not enough signals for confident classification:

  • Check headers — Ensure User-Agent is present
  • Check IP — Some detection signals use IP geolocation
  • Wait for more data — First requests may have limited signals

Performance Issues

If detection is adding latency:

  1. Use Redis storage for session caching
  2. Review the matcher to exclude unnecessary routes
  3. Check API key rate limits in your dashboard

What You Learned

  • How to add server-side detection to Next.js and Express
  • How to access detection data in your routes
  • How to log and monitor detections
  • How to test with different user agents

Next Steps

Ready to start blocking detected agents? See:

GoalNext Cookbook
Block AI agentsMiddleware Enforcement
DNS-level blockingGateway Setup
Configure policiesPolicy Configuration