# Hugging Face AI Observability installation - Docs 1. 1 ## Install dependencies Required **Full working examples** See the complete [Node.js](https://github.com/PostHog/posthog-js/tree/main/examples/example-ai-hugging-face) and [Python](https://github.com/PostHog/posthog-python/tree/master/examples/example-ai-hugging-face) examples on GitHub. If you're using the PostHog SDK wrapper instead of OpenTelemetry, see the [Node.js wrapper](https://github.com/PostHog/posthog-js/tree/e08ff1be/examples/example-ai-hugging-face) and [Python wrapper](https://github.com/PostHog/posthog-python/tree/7223c52/examples/example-ai-hugging-face) examples. Install the OpenTelemetry SDK, the OpenAI instrumentation, and the OpenAI SDK. PostHog AI ### Python ```bash pip install openai opentelemetry-sdk "posthog[otel]" opentelemetry-instrumentation-openai-v2 ``` ### Node ```bash npm install openai @posthog/ai @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/instrumentation-openai ``` 2. 2 ## Set up OpenTelemetry tracing Required Configure OpenTelemetry to auto-instrument OpenAI SDK calls and export traces to PostHog. PostHog converts `gen_ai.*` spans into `$ai_generation` events automatically. PostHog AI ### Python ```python from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.resources import Resource, SERVICE_NAME from posthog.ai.otel import PostHogSpanProcessor from opentelemetry.instrumentation.openai_v2 import OpenAIInstrumentor resource = Resource(attributes={ SERVICE_NAME: "my-app", "posthog.distinct_id": "user_123", # optional: identifies the user in PostHog "foo": "bar", # custom properties are passed through }) provider = TracerProvider(resource=resource) provider.add_span_processor( PostHogSpanProcessor( api_key="", host="https://us.i.posthog.com", ) ) trace.set_tracer_provider(provider) OpenAIInstrumentor().instrument() ``` ### Node ```typescript import { NodeSDK } from '@opentelemetry/sdk-node' import { resourceFromAttributes } from '@opentelemetry/resources' import { PostHogSpanProcessor } from '@posthog/ai/otel' import { OpenAIInstrumentation } from '@opentelemetry/instrumentation-openai' const sdk = new NodeSDK({ resource: resourceFromAttributes({ 'service.name': 'my-app', 'posthog.distinct_id': 'user_123', // optional: identifies the user in PostHog foo: 'bar', // custom properties are passed through }), spanProcessors: [ new PostHogSpanProcessor({ apiKey: '', host: 'https://us.i.posthog.com', }), ], instrumentations: [new OpenAIInstrumentation()], }) sdk.start() ``` 3. 3 ## Call Hugging Face Required Now, when you use the OpenAI SDK to call Hugging Face, PostHog automatically captures `$ai_generation` events via the OpenTelemetry instrumentation. PostHog AI ### Python ```python import openai client = openai.OpenAI( base_url="https://router.huggingface.co/v1/", api_key="", ) response = client.chat.completions.create( model="meta-llama/Llama-3.3-70B-Instruct", max_completion_tokens=1024, messages=[ {"role": "user", "content": "Tell me a fun fact about hedgehogs"} ], ) print(response.choices[0].message.content) ``` ### Node ```typescript import OpenAI from 'openai' const client = new OpenAI({ baseURL: 'https://router.huggingface.co/v1/', apiKey: '', }) const response = await client.chat.completions.create({ model: 'meta-llama/Llama-3.3-70B-Instruct', max_completion_tokens: 1024, messages: [{ role: 'user', content: 'Tell me a fun fact about hedgehogs' }], }) console.log(response.choices[0].message.content) ``` > **Note:** If you want to capture LLM events anonymously, omit the `posthog.distinct_id` resource attribute. See our docs on [anonymous vs identified events](/docs/data/anonymous-vs-identified-events.md) to learn more. 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