> ## Documentation Index
> Fetch the complete documentation index at: https://lightsage.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Detect AI agent visits with agent tracking middleware

> Install Lightsage's lightweight middleware on Next.js, Vercel, Cloudflare, Express, Astro, or Netlify to detect coding agent visits to your docs in real time.

When a coding agent reads your documentation, it leaves no trace in a standard analytics tool. Google Analytics records human sessions. Your CDN logs record IP addresses. Neither tells you that Claude Code spent the last hour reading your authentication reference — or that Cursor crawled your quick start but never reached your error handling guide.

Lightsage's agent tracking middleware sits in front of your application and identifies AI agent traffic by user agent signature. It adds zero latency to user-facing requests and sends agent visit events to your Lightsage dashboard in real time. The following agents are detected:

* **Coding agents:** Claude Code, OpenCode, Cursor, GitHub Copilot, OpenAI Codex, Gemini CLI, OpenClaw, Hermes, Pi, Kilo
* **Answer engines and crawlers:** ChatGPT, Google AI, Perplexity, and their associated crawlers

## Getting your API key

Find your `LIGHTSAGE_API_KEY` in your [Lightsage account settings](https://app.lightsage.com/settings/api). Store it as an environment variable — never commit it to source control.

## Installation

<CodeGroup>
  ```typescript Next.js (middleware.ts) theme={null}
  // middleware.ts — place this in your project root
  import { withAgentTracking } from '@lightsage/agent-tracker/next';

  export default withAgentTracking({
    apiKey: process.env.LIGHTSAGE_API_KEY,
  });

  export const config = {
    matcher: ['/((?!api|_next|admin).*)'],
  };
  ```

  ```typescript Vercel (middleware.ts) theme={null}
  // Vercel uses the same Next.js middleware format.
  // Place middleware.ts in your project root.
  import { withAgentTracking } from '@lightsage/agent-tracker/next';

  export default withAgentTracking({
    apiKey: process.env.LIGHTSAGE_API_KEY,
  });

  export const config = {
    // Exclude Vercel internals and your API routes
    matcher: ['/((?!api|_next|_vercel|admin).*)'],
  };
  ```

  ```typescript Cloudflare Workers theme={null}
  // worker.ts
  import { createAgentTracker } from '@lightsage/agent-tracker/cloudflare';

  const tracker = createAgentTracker({
    apiKey: env.LIGHTSAGE_API_KEY,
  });

  export default {
    async fetch(request: Request, env: Env): Promise<Response> {
      // Track the request before forwarding
      await tracker.track(request);

      // Continue with your normal handler
      return fetch(request);
    },
  };
  ```

  ```typescript Express.js theme={null}
  // app.ts
  import express from 'express';
  import { agentTrackingMiddleware } from '@lightsage/agent-tracker/express';

  const app = express();

  // Add before your route handlers
  app.use(
    agentTrackingMiddleware({
      apiKey: process.env.LIGHTSAGE_API_KEY,
      // Optional: exclude paths you don't want tracked
      exclude: ['/api', '/admin', '/health'],
    })
  );

  app.get('/', (req, res) => {
    res.send('Hello world');
  });

  app.listen(3000);
  ```

  ```typescript Netlify Edge Functions theme={null}
  // netlify/edge-functions/agent-tracking.ts
  import { trackAgentRequest } from '@lightsage/agent-tracker/netlify';

  export default async (request: Request) => {
    await trackAgentRequest(request, {
      apiKey: Deno.env.get('LIGHTSAGE_API_KEY'),
    });

    // Return undefined to continue to the next handler
    return;
  };

  export const config = {
    path: '/*',
    excludedPath: ['/api/*', '/admin/*'],
  };
  ```
</CodeGroup>

## Installing the package

<Tabs>
  <Tab title="npm">
    ```bash theme={null}
    npm install @lightsage/agent-tracker
    ```
  </Tab>

  <Tab title="pnpm">
    ```bash theme={null}
    pnpm add @lightsage/agent-tracker
    ```
  </Tab>

  <Tab title="yarn">
    ```bash theme={null}
    yarn add @lightsage/agent-tracker
    ```
  </Tab>
</Tabs>

## The matcher config

For Next.js and Vercel, the `matcher` config controls which routes the middleware runs on. The pattern `/((?!api|_next|admin).*)` means: run on all routes except those starting with `api/`, `_next/`, or `admin/`.

You should exclude:

* **`api/`** — your own API routes (you don't need to track server-to-server calls as agent visits)
* **`_next/`** — Next.js static assets and build artifacts
* **`admin/`** — internal tooling that agents shouldn't be visiting anyway

If you have additional paths to exclude — for example, a staging environment path or internal health check endpoint — add them to the exclusion list:

```typescript theme={null}
export const config = {
  matcher: ['/((?!api|_next|admin|staging|health).*)'],
};
```

## What you see in the dashboard

Once the middleware is deployed and agents begin visiting your site, the Lightsage dashboard shows:

* **Agent identity** — which coding agent made the visit (Claude Code, Cursor, etc.)
* **Pages visited** — which documentation pages the agent read, in order
* **Visit frequency** — how often each agent crawls your docs
* **First seen / last seen** — when an agent first discovered your docs and when it most recently visited
* **Correlation with recommendations** — Lightsage links agent visit patterns to your prompt tracking data so you can see whether agents that crawl your docs more frequently also recommend you more often

<Info>
  The first agent visits may appear in your dashboard within minutes of deploying the middleware, depending on how actively the agents currently crawl your domain. If you see no visits within 48 hours, verify that your robots.txt is not blocking AI crawlers. See [Optimize your API for AI coding agent discovery](/docs/guides/optimize-for-agents) for the robots.txt configuration.
</Info>

## Performance impact

The middleware runs on your edge infrastructure and uses a fire-and-forget pattern for the tracking event — it does not add latency to the response path for any visitor, human or agent. The identification logic is a user-agent string lookup, which completes in microseconds.

<Tip>
  For Cloudflare Workers and Netlify Edge Functions, use `event.waitUntil()` or the equivalent platform primitive to ensure the tracking event completes even after the response is returned, without blocking the response itself.
</Tip>

## Next steps

Agent visit tracking gives you the web-crawl half of the picture. To track what agents recommend when developers ask implementation questions, see [How to track coding agent recommendations for your API](/docs/guides/track-coding-agents).

To connect recognized AI acquisition sources to sign-up, demo, checkout, and activation events, see [Measure agent-attributed growth](/docs/agent-analytics/attributed-growth).

To improve the quality of what agents find when they visit your docs, see [Optimize your API for AI coding agent discovery](/docs/guides/optimize-for-agents).
