---
title: Analytics
description: Track which AI bots read your content and which actions agents invoke.
canonical_url: https://next-ai-ready.vercel.app/en/docs/guides/analytics
url: https://next-ai-ready.vercel.app/en/docs/guides/analytics
last_updated: 2026-06-02
updated: 2026-06-02
author: next-ai-ready team
summary: Track which AI bots read your content and which actions agents invoke.
topics: [how-to, best-practices]
---

# Analytics

`next-ai-ready` provides two hooks to track AI consumer activity without adding external dependencies.

## Setup

Next.js runs `instrumentation.ts` in **both** Node.js and Edge. Register hooks from a Node-only file via the **`next-ai-ready/hooks`** subpath (not the main package entry) so Turbopack does not pull build-time Node modules into the Edge bundle.

**`instrumentation.ts`**

```ts
export async function register() {
  if (process.env.NEXT_RUNTIME === "nodejs") {
    await import("./instrumentation-node");
  }
}
```

**`instrumentation-node.ts`**

```ts
import "server-only";
import { registerAiHooks } from "next-ai-ready/hooks";

registerAiHooks({
  onAiRequest: (info) => {
    console.log("AI request:", info.bot, info.artifact, info.path);
  },
  onInvoke: (info) => {
    console.log("Action invoked:", info.action, info.ok, info.latencyMs);
  },
});
```

`npx next-ai-ready init` scaffolds both files for you.

## `onAiRequest`

Fires when an AI bot reads a Knowledge Plane artifact. The callback receives:

| Field      | Type      | Description                                                                         |
| ---------- | --------- | ----------------------------------------------------------------------------------- |
| `bot`      | `string?` | Detected bot name (e.g. `"GPTBot"`, `"ClaudeBot"`). `undefined` if unrecognized.    |
| `path`     | `string`  | Request path (e.g. `/llms.txt`, `/docs/intro.md`).                                  |
| `artifact` | `string`  | Artifact type: `"llms-txt"`, `"page-md"`, `"page-ai-json"`, `"openapi"`, `"tools"`. |
| `ua`       | `string`  | Raw `User-Agent` header.                                                            |
| `method`   | `string`  | HTTP method.                                                                        |

Bot detection matches these user agents: `GPTBot`, `OAI-SearchBot`, `ChatGPT-User`, `PerplexityBot`, `ClaudeBot`, `anthropic-ai`, `Google-Extended`, `CCBot`, `Bytespider`, `Applebot-Extended`.

## `onInvoke`

Fires when an action is called via HTTP or MCP. The callback receives:

| Field       | Type      | Description                             |
| ----------- | --------- | --------------------------------------- |
| `action`    | `string`  | Action name (e.g. `"search_products"`). |
| `ok`        | `boolean` | Whether the invocation succeeded.       |
| `latencyMs` | `number`  | Handler execution time in milliseconds. |
| `error`     | `string?` | Error message if `ok` is `false`.       |
| `caller`    | `string?` | `"http"` or `"mcp"`.                    |

## Example: sending to an analytics service

Put your SDK calls in `instrumentation-node.ts`:

```ts
import "server-only";
import { registerAiHooks } from "next-ai-ready/hooks";

registerAiHooks({
  onAiRequest: (info) => {
    analytics.track("ai_request", {
      bot: info.bot,
      artifact: info.artifact,
      path: info.path,
    });
  },
  onInvoke: (info) => {
    analytics.track("ai_invoke", {
      action: info.action,
      ok: info.ok,
      latencyMs: info.latencyMs,
      caller: info.caller,
    });
  },
});
```

## How hooks are wired

The hooks are registered globally and called by the route handlers at request time. They run synchronously in the handler's execution context — if a hook throws, the request still completes normally (the error is swallowed).

No external dependencies are required. The hooks are designed to be a thin integration point — bring your own analytics SDK.
