Checkpoint Docs
Cookbooks

Enforce: Middleware Enforcement

Block AI agents in your application code with Next.js or Express middleware

Goal

Add code-level AI agent enforcement to your Next.js or Express application. By the end of this cookbook, you'll have:

  • Server-side detection on every request
  • Configurable blocking, redirecting, or challenging of detected agents
  • Session tracking with Redis (production-ready)
  • Custom response handling for blocked requests

Best for: Applications where you need fine-grained control over enforcement behavior, custom responses, or integration with existing authentication.

Prerequisites

  • A Checkpoint account with a project created
  • A Next.js 13+ or Express 4+ application
  • Node.js 16+
  • (Optional) Redis for production session storage

Time Estimate

20-25 minutes


Steps

Install the Package

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

Configure Environment Variables

  1. Go to your Checkpoint dashboard
  2. Select your project
  3. Go to Settings → API Keys
  4. Create or copy your API key
# .env.local
AGENTSHIELD_API_KEY=as_live_xxxxxxxxxxxx
CHECKPOINT_PROJECT_ID=proj_abc123def456

# For production session storage
REDIS_URL=redis://localhost:6379

Set Up Basic Enforcement

Create 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!,
  onBlock: 'block', // Enable enforcement
});

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

This blocks all detected AI agents with a default 403 response.

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

const app = express();

app.use(
  createEnhancedAgentShieldMiddleware({
    projectId: process.env.CHECKPOINT_PROJECT_ID!,
    mode: 'enforce', // Enable enforcement (not just 'detect')
  })
);

app.get('/', (req, res) => {
  res.json({ message: 'Only humans allowed!' });
});

app.listen(3000);

Customize Enforcement Behavior

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

export default withAgentShield({
  apiKey: process.env.AGENTSHIELD_API_KEY!,

  // Custom blocking behavior
  onBlock: (detection, request) => {
    // Option 1: Block with custom response
    if (detection.detectionClass === 'ai_agent') {
      return new NextResponse(
        JSON.stringify({
          error: 'AI agent access is not permitted',
          agent: detection.agentName,
        }),
        {
          status: 403,
          headers: { 'Content-Type': 'application/json' },
        }
      );
    }

    // Option 2: Redirect bots to a notice page
    if (detection.detectionClass === 'bot') {
      return NextResponse.redirect(new URL('/bot-notice', request.url));
    }

    // Option 3: Allow with warning header
    const response = NextResponse.next();
    response.headers.set('X-Agent-Warning', 'Detected as automated traffic');
    return response;
  },

  // Only block high-confidence detections
  confidenceThreshold: 70,

  // Allow specific agents
  allowList: ['Googlebot', 'Bingbot'],
});

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

const app = express();

app.use(
  createEnhancedAgentShieldMiddleware({
    projectId: process.env.CHECKPOINT_PROJECT_ID!,
    mode: 'enforce',

    // Custom enforcement logic
    onBlock: (detection, req, res) => {
      // Block AI agents
      if (detection.detectionClass === 'ai_agent') {
        return res.status(403).json({
          error: 'AI agent access denied',
          agent: detection.agentName,
          confidence: detection.confidence,
        });
      }

      // Redirect unknown bots
      if (
        detection.detectionClass === 'bot' &&
        !['Googlebot', 'Bingbot'].includes(detection.agentName || '')
      ) {
        return res.redirect(302, '/bot-notice');
      }

      // Allow everything else
      return null; // Continue to next middleware
    },

    // Only enforce above threshold
    confidenceThreshold: 70,
  })
);

app.get('/bot-notice', (req, res) => {
  res.send('Bot traffic detected. Please contact support if you believe this is an error.');
});

app.get('/', (req, res) => {
  res.json({ message: 'Welcome, human!' });
});

app.listen(3000);

Add Production Session Storage

For production, use Redis to persist detection sessions:

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

export default createEnhancedAgentShieldMiddleware({
  projectId: process.env.CHECKPOINT_PROJECT_ID!,

  // Redis storage for production
  storage: {
    type: 'redis',
    url: process.env.REDIS_URL,
    keyPrefix: 'agentshield:', // Optional: namespace keys
  },

  onDetection: (event) => {
    console.log(`Detection: ${event.detectionClass} (${event.confidence}%)`);
  },
});
// app.ts
import express from 'express';
import { createEnhancedAgentShieldMiddleware } from '@kya-os/agentshield-express';

const app = express();

app.use(
  createEnhancedAgentShieldMiddleware({
    projectId: process.env.CHECKPOINT_PROJECT_ID!,
    mode: 'enforce',

    // Redis storage for production
    storage: {
      type: 'redis',
      url: process.env.REDIS_URL,
      keyPrefix: 'agentshield:',
    },

    onDetection: (event) => {
      console.log(`Detection: ${event.detectionClass} (${event.confidence}%)`);
    },
  })
);

app.listen(3000);

Memory storage (default) is fine for development but resets on restart and doesn't share across instances. Use Redis for production.

Protect Specific Routes

Instead of global middleware, protect only specific routes:

Middleware approach — match specific paths:

// middleware.ts
export const config = {
  matcher: [
    '/api/:path*', // All API routes
    '/dashboard/:path*', // Dashboard routes
    '/checkout/:path*', // Checkout flow
  ],
};

Route handler approach — per-endpoint protection:

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

export const POST = withAgentShield(
  async (req) => {
    // Only executes if not blocked
    return Response.json({ secret: 'data' });
  },
  {
    apiKey: process.env.AGENTSHIELD_API_KEY!,
    onBlock: 'block',
  }
);
// app.ts
import express from 'express';
import { createEnhancedAgentShieldMiddleware } from '@kya-os/agentshield-express';

const app = express();

// Create reusable middleware instances
const detectOnly = createEnhancedAgentShieldMiddleware({
  projectId: process.env.CHECKPOINT_PROJECT_ID!,
  mode: 'detect',
});

const enforceStrict = createEnhancedAgentShieldMiddleware({
  projectId: process.env.CHECKPOINT_PROJECT_ID!,
  mode: 'enforce',
  confidenceThreshold: 60,
});

// Public routes — detect only
app.get('/', detectOnly, (req, res) => {
  res.json({ message: 'Welcome!' });
});

// Sensitive routes — enforce
app.use('/api', enforceStrict);
app.get('/api/data', (req, res) => {
  res.json({ sensitive: 'data' });
});

// Payment routes — strict enforcement
app.use('/checkout', enforceStrict);

app.listen(3000);

Test Your Enforcement

Test as a human:

curl http://localhost:3000/api/data
# Should return 200 OK with data

Test as ChatGPT (should be blocked):

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

Test as Googlebot (if allowed):

curl -H "User-Agent: Googlebot/2.1 (+http://www.google.com/bot.html)" \
  http://localhost:3000/api/data
# Should return 200 OK (if Googlebot is in allowList)

Check your dashboard → Analytics to see the blocked requests.


Advanced Patterns

Allow Verified AI Agents

Block unverified agents but allow those with valid cryptographic signatures:

// middleware.ts
export default withAgentShield({
  apiKey: process.env.AGENTSHIELD_API_KEY!,
  onBlock: (detection, request) => {
    // Allow agents with verified signatures
    if (detection.signatureVerified) {
      return null; // Allow through
    }

    // Block unverified AI agents
    if (detection.detectionClass === 'ai_agent') {
      return new NextResponse('Unverified agent denied', { status: 403 });
    }

    return null;
  },
});

Rate Limiting by Agent Type

// Express example with rate limiting
import rateLimit from 'express-rate-limit';

const humanLimiter = rateLimit({ windowMs: 60000, max: 100 });
const botLimiter = rateLimit({ windowMs: 60000, max: 10 });

app.use((req, res, next) => {
  const detection = req.agentShield;

  if (detection?.detectionClass === 'bot') {
    return botLimiter(req, res, next);
  }

  return humanLimiter(req, res, next);
});

Logging Blocked Requests

onBlock: (detection, request) => {
  // Log to your monitoring system
  console.log(
    JSON.stringify({
      event: 'agent_blocked',
      class: detection.detectionClass,
      agent: detection.agentName,
      confidence: detection.confidence,
      path: request.nextUrl?.pathname,
      timestamp: new Date().toISOString(),
    })
  );

  return new NextResponse('Access denied', { status: 403 });
};

Troubleshooting

All Requests Being Blocked

SymptomCauseFix
Humans blockedConfidence too lowIncrease confidenceThreshold to 70+
API calls blockedMissing allowListAdd legitimate clients to allowList
Internal traffic blockedInternal services flaggedExclude internal routes from matcher

Blocking Not Working

  • Check mode — Must be 'enforce', not 'detect'
  • Check onBlock — Must return a Response, not null
  • Check matcher — Route must be included in matcher

Performance Issues

  • Use Redis — Memory storage doesn't scale
  • Cache detection results — Reduce API calls
  • Narrow the matcher — Only protect necessary routes

What You Learned

  • How to set up enforcement middleware in Next.js and Express
  • How to customize blocking behavior (block, redirect, challenge)
  • How to configure production-ready session storage
  • How to protect specific routes instead of global enforcement
  • Advanced patterns for verified agents and rate limiting

Next Steps

GoalNext Cookbook
DNS-level enforcementGateway Setup
Configure policiesPolicy Configuration
Authorize agentsGovern Overview