Checkpoint Docs
IntegrationsExpress

Express Observability & Storage

Session tracking and Redis event storage for the Express middleware

Overview

This page covers observability for the Express integration: storage adapters for persisting detection events (createStorageAdapter — Memory or Redis), and session tracking across requests (withSessionTracking). Both are composable primitives you wire into the one middleware factory, withCheckpoint, through its onResult callback — there is no separate "enhanced" middleware to install.

Looking for createEnhancedAgentShieldMiddleware? It was removed from @kya-os/checkpoint-express in 1.3.0. The storage and session-tracking capabilities it used to bundle are the composable exports documented on this page.

For the full middleware reference (config options, response headers, response shape) covering Next.js, Express, and .NET, see Middleware Enforcement.

Setup

Record detection events from onResult. Construct a storage adapter with the async createStorageAdapter factory (Upstash Redis for production):

import express from 'express';
import { randomUUID } from 'node:crypto';
import { withCheckpoint, createStorageAdapter } from '@kya-os/checkpoint-express';

const app = express();
app.use(express.json());

const storage = await createStorageAdapter({
  type: 'redis',
  ttl: 86400, // 24 hours (default)
  redis: {
    url: process.env.REDIS_URL!,
    token: process.env.REDIS_TOKEN!,
  },
});

app.use(
  withCheckpoint({
    tenantHost: 'your.tenant.example',
    apiKey: process.env.CHECKPOINT_API_KEY,
    onResult: async (result, req) => {
      await storage.storeEvent({
        eventId: randomUUID(),
        sessionId: req.headers['x-request-id']?.toString() ?? randomUUID(),
        timestamp: new Date().toISOString(),
        agentType: result.detectionDetail.detectionClass.type,
        agentName: result.detectionDetail.detectedAgent?.name ?? 'unknown',
        confidence: result.detectionDetail.confidence,
        path: req.path,
        method: req.method,
        userAgent: req.headers['user-agent'],
        detectionReasons: result.detectionDetail.reasons,
        verificationMethod: result.detectionDetail.verificationMethod,
      });
    },
  })
);

app.listen(3000);

Errors thrown inside onResult are swallowed so an observability failure can't break the verdict path.

Storage Adapters

@kya-os/checkpoint-express exports MemoryStorageAdapter, RedisStorageAdapter, and the async createStorageAdapter factory.

Memory

For development and single-instance deployments. Data is lost on restart. This is the default — createStorageAdapter() with no argument (or { type: 'memory' }) returns a MemoryStorageAdapter.

import { createStorageAdapter } from '@kya-os/checkpoint-express';

const storage = await createStorageAdapter(); // in-memory

Redis

For production. Persists events and sessions across restarts and instances via Upstash Redis.

import { createStorageAdapter } from '@kya-os/checkpoint-express';

const storage = await createStorageAdapter({
  type: 'redis',
  ttl: 86400, // 24 hours (default)
  redis: {
    url: process.env.REDIS_URL!,
    token: process.env.REDIS_TOKEN!,
  },
});

Memory storage is not suitable for production — data is lost on restart and not shared across instances. Use Redis for production deployments.

Custom Adapter

Implement the StorageAdapter interface and pass it as { type: 'custom', custom: myAdapter }:

import type { StorageAdapter } from '@kya-os/checkpoint-express';

const myAdapter: StorageAdapter = {
  storeEvent: async (event) => {
    /* persist an AgentDetectionEvent */
  },
  storeSession: async (session) => {
    /* upsert an AgentSession */
  },
  getEvents: async (sessionId, limit) => {
    return [];
  },
  getSession: async (sessionId) => {
    return null;
  },
  getRecentEvents: async (limit) => {
    return [];
  },
  getActiveSessions: async (limit) => {
    return [];
  },
  cleanup: async (before) => {
    /* optional */
  },
};

Session Tracking

For cookie/header-based session continuity, wrap the middleware with withSessionTracking. When enabled, a returning agent's session is attached to req.agentShield on subsequent requests:

import { withCheckpoint, withSessionTracking } from '@kya-os/checkpoint-express';

const checkpoint = withCheckpoint({ tenantHost: 'your.tenant.example' });

app.use(withSessionTracking(checkpoint, { enabled: true }));

The package also exports the ExpressSessionTracker class directly if you need finer control over check / track.

req.agentShield is populated only when session tracking is wired via withSessionTracking. Plain withCheckpoint attaches nothing to req — read the verdict from the onResult callback.

Response Headers

The engine path sets X-Checkpoint-* headers and a __checkpoint_verdict cookie (byte-identical to the Next.js sibling package). In observe mode it adds X-Checkpoint-Would-Have-Been.

When session tracking is wired, ExpressSessionTracker additionally emits kya-session, kya-session-agent, and kya-session-id (and withSessionTracking sets kya-detected / kya-agent on a continued session).

Next Steps