# Eve AI observability installation - Docs

1.  1

    ## Install dependencies

    Required

    Install PostHog AI, its OpenTelemetry peer dependencies, and Vercel's OpenTelemetry package.

    ```bash
    npm install @posthog/ai @opentelemetry/api @opentelemetry/exporter-trace-otlp-http @opentelemetry/sdk-trace-base @vercel/otel
    ```

    > **Version note:** This example uses `projectToken`, which is available in `@posthog/ai` 7.19.6 and later. Earlier 7.x versions use `apiKey`.

2.  2

    ## Set environment variables

    Required

    Set your PostHog project token and host in your Eve project's environment.

    ```bash
    POSTHOG_PROJECT_TOKEN=<ph_project_token>
    POSTHOG_HOST=https://us.i.posthog.com
    ```

3.  3

    ## Add Eve instrumentation

    Required

    Create `agent/instrumentation.ts`. Eve discovers this file and starts the exporter when your agent server starts. The optional `events` handler uses [Eve runtime context](https://eve.dev/docs/guides/instrumentation#runtime-context) to identify spans with the user who started the session, falling back to the caller for the current turn.

    ```typescript
    import { trace } from '@opentelemetry/api'
    import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
    import { PostHogTraceExporter } from '@posthog/ai/otel'
    import { registerOTel } from '@vercel/otel'
    import { defineInstrumentation } from 'eve/instrumentation'
    export default defineInstrumentation({
      setup: ({ agentName }) =>
        registerOTel({
          serviceName: agentName,
          spanProcessors: [
            new SimpleSpanProcessor(
              new PostHogTraceExporter({
                projectToken: process.env.POSTHOG_PROJECT_TOKEN!,
                host: process.env.POSTHOG_HOST,
              })
            ),
          ],
        }),
      // Optional: Link Eve and AI SDK spans to a PostHog user.
      events: {
        'step.started'(input) {
          const distinctId =
            input.session.auth.initiator?.principalId ??
            input.session.auth.current?.principalId
          if (!distinctId) {
            return undefined
          }
          trace.getActiveSpan()?.setAttribute('posthog.distinct_id', distinctId)
          return { runtimeContext: { posthog_distinct_id: distinctId } }
        },
      },
    })
    ```

    **How this works**

    Eve emits Vercel AI SDK OpenTelemetry spans. `PostHogTraceExporter` sends the AI spans to PostHog's OTLP ingestion endpoint. `SimpleSpanProcessor` starts exporting each span when it ends instead of waiting for a background batch, so export does not depend on a background timer in Vercel Workflow. PostHog keeps the trace hierarchy, identifies the framework as Eve, and groups turns using `eve.session.id`.

    > **Note:** To capture LLM events anonymously, omit the `events` handler. See our docs on [anonymous vs identified events](/docs/data/anonymous-vs-identified-events.md) to learn more.

    > **Data capture:** Eve records full message history and model outputs by default. Set `recordInputs: false` or `recordOutputs: false` in `defineInstrumentation` if you do not want that data included in exported spans.

    You can expect captured `$ai_generation` events to have the following properties:

    | Property | Description |
    | --- | --- |
    | $ai_model | The specific model, like gpt-5-mini or claude-4-sonnet |
    | $ai_latency | The latency of the LLM call in seconds |
    | $ai_time_to_first_token | Time to first token in seconds (streaming only) |
    | $ai_tools | Tools and functions available to the LLM |
    | $ai_input | List of messages sent to the LLM |
    | $ai_input_tokens | The number of tokens in the input (often found in response.usage) |
    | $ai_output_choices | List of response choices from the LLM |
    | $ai_output_tokens | The number of tokens in the output (often found in response.usage) |
    | $ai_total_cost_usd | The total cost in USD (input + output) |
    | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties |

4.  ## Verify traces and generations

    Recommended

    *Confirm LLM events are being sent to PostHog*

    Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs.

    ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png)

    [Check for LLM events in PostHog](https://app.posthog.com/ai-observability/generations)

5.  4

    ## Next steps

    Recommended

    Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform.

    | Resource | Description |
    | --- | --- |
    | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. |
    | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. |
    | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. |
    | [Spans](/docs/ai-observability/spans.md) | Review spans and their role in representing individual operations. |
    | [Anaylze LLM performance](/docs/ai-observability/dashboard.md) | Learn how to create dashboards to analyze LLM performance. |

### Community questions

Ask a question

### Was this page useful?

HelpfulCould be better