---
title: Instrument your agent with the AI SDK
description: "Instrument a Node or Python agent with the Amplitude AI SDK, either by handing a prompt to your AI coding agent or by wrapping your LLM client and sessions by hand, then place agents and flushes correctly on long-lived servers."
product: general
lang: en
token_estimate: 1805
---
# Instrument your agent with the AI SDK

> For AI agents: a documentation index is available at [/docs/llms.txt](/docs/llms.txt). Append `.md` to any page URL for markdown, or send `Accept: text/markdown`.

The Amplitude AI SDK (`@amplitude/ai` for Node, `amplitude-ai` for Python) wraps your LLM client and groups each conversation into an agent session, so it emits every `[Agent]` event Agent Analytics expects. It also closes sessions, applies your privacy mode, and prices model calls for you.

Use the AI SDK when you can modify a Node or Python codebase. If your runtime can't run it, such as a browser, an edge runtime, Java, Go, or Ruby, [send agent events without the AI SDK](https://amplitude.com/docs/amplitude-ai/agent-analytics/instrument-http-api) instead. If you already export OpenTelemetry GenAI spans, [send OpenTelemetry traces](https://amplitude.com/docs/amplitude-ai/agent-analytics/instrument-opentelemetry).

Before you start, decide your [session ID and user ID](https://amplitude.com/docs/amplitude-ai/agent-analytics/sessions) and your [privacy mode](https://amplitude.com/docs/amplitude-ai/agent-analytics/privacy-modes). For the full SDK API, refer to the [Agent Analytics SDK reference](https://amplitude.com/docs/sdks/agent-analytics/sdk).

## Instrument with your AI coding agent (recommended)

Paste this prompt into your AI coding agent, such as Cursor, Claude Code, Windsurf, GitHub Copilot, or Codex. The agent installs the SDK, reads the bundled instructions file, scans your codebase, finds every LLM call site and the session lifecycle, and instruments them. It also writes a verification test.

#### Node

```text
Instrument this app with Amplitude Agent Analytics using the Node SDK.

Install the SDK:

npm install @amplitude/ai @amplitude/analytics-node

Then follow `node_modules/@amplitude/ai/amplitude-ai.md`.
```

#### Python

```text
Instrument this app with Amplitude Agent Analytics using the Python SDK.

Install the SDK:

python3 -m pip install amplitude-ai

Then run `amplitude-ai --print-guide` and follow the printed instrumentation guide.
```

Review the changes it proposes, then [verify your instrumentation](https://amplitude.com/docs/amplitude-ai/agent-analytics/verify).

## Instrument by hand

Wrap your LLM client, name an agent, and run each conversation inside a session. That pattern produces every event type Agent Analytics expects.

#### Node

```typescript
import { AmplitudeAI, OpenAI } from '@amplitude/ai';

const ai = new AmplitudeAI({ apiKey: process.env.AMPLITUDE_AI_API_KEY });
const openai = new OpenAI({ amplitude: ai, apiKey: process.env.OPENAI_API_KEY });
const agent = ai.agent('my-agent');

const session = agent.session({ userId, sessionId });
await session.run(async (s) => {
  s.trackUserMessage(message);
  return openai.chat.completions.create({ model, messages });
});
await ai.flush();
```

#### Python

```python
import os
from amplitude_ai import AmplitudeAI, patch
from openai import OpenAI

ai = AmplitudeAI(api_key=os.environ['AMPLITUDE_AI_API_KEY'])
patch(amplitude_ai=ai)
client = OpenAI(api_key=os.environ['OPENAI_API_KEY'])
agent = ai.agent('my-agent')

with agent.session(user_id=user_id, session_id=session_id) as s:
    s.track_user_message(message)
    client.chat.completions.create(model=model, messages=messages)

ai.flush()
```

The wrapped provider (`new OpenAI({ amplitude: ai })` in Node, `patch(amplitude_ai=ai)` in Python) captures `[Agent] AI Response`, including the chat text, from the completion response. Without a wrapped provider, Amplitude doesn't track that event or its message content. If you use a provider the SDK doesn't wrap, or call an unwrapped client directly, call `trackAiMessage()` (Node) or `track_ai_message()` (Python) after the completion returns. For every tracking method, refer to [Manual instrumentation](https://amplitude.com/docs/sdks/agent-analytics/sdk#manual-instrumentation) in the SDK reference.

To apply your privacy mode, set `contentMode` (Node) or `content_mode` (Python) on `AIConfig`. Refer to [Configure the SDK](https://amplitude.com/docs/sdks/agent-analytics/sdk#configure-the-sdk).

## Place agents and sessions on a long-lived server

On an HTTP server that handles many turns and users, three placement rules keep sessions grouped correctly.

### Define agents at module scope

Constructing `ai.agent(...)` inside a request handler mints a fresh `[Agent] Agent ID` on every turn and breaks session grouping. Create the agent once at module load and reuse the reference.

#### Node

```typescript
// agent.ts (module scope)
export const agent = ai.agent('support-bot');

// handler.ts
export async function POST(req: Request) {
  const { sessionId, userId, message } = await req.json();
  return agent.session({ userId, sessionId }).run(async (s) => {
    s.trackUserMessage(message);
    // ...
  });
}
```

#### Python

```python
# agent.py (module scope)
agent = ai.agent('support-bot')

# handler.py
@app.post('/chat')
async def chat(req):
    body = await req.json()
    with agent.session(user_id=body['userId'], session_id=body['sessionId']) as s:
        s.track_user_message(body['message'])
        # ...
```

### Open one session per request with a stable session ID

Call `agent.session({ sessionId })` inside each request handler, with the same `sessionId` across every turn of the same job. Turns stitch together because they share the ID, not because they share the process.

### Keep each session ID to one user

A shared or global session ID merges different users' conversations and breaks per-user analytics. Refer to [Choose a session ID](https://amplitude.com/docs/amplitude-ai/agent-analytics/sessions#choose-a-session-id).

## Close and flush sessions

A session opened with `run()` (Node) or the `session()` context manager (Python) closes when the scope exits. For sessions that span several requests, call `trackSessionEnd()` (Node) or `track_session_end()` (Python) when the job finishes. For how closing works, refer to [How sessions close](https://amplitude.com/docs/amplitude-ai/agent-analytics/sessions#how-sessions-close).

The SDK batches events in memory and ships them on an interval. For short sessions (under a minute), batching is transparent. For long-running sessions, such as tickets worked over hours, coding tasks that span a day, or background jobs, the close event can sit in the buffer. If the process restarts before it ships, the session stays open until the idle timeout closes it.

Call `ai.flush()` right after the close to make sure it lands before the process exits or restarts:

#### Node

```typescript
agent.trackSessionEnd({ sessionId: ticketId });
await ai.flush();
```

#### Python

```python
agent.track_session_end(session_id=ticket_id)
ai.flush()
```

Serverless handlers flush automatically when `session.run()` completes, so you don't need an explicit call there. For long-running servers, also call `ai.flush()` in your SIGTERM handler so buffered events across every open session ship before the process stops.

To keep sessions open longer than the 30-minute default, refer to [Configure session timeouts](https://amplitude.com/docs/amplitude-ai/agent-analytics/configure-session-timeouts).

