Capturing large AI events
Contents
Large event capture is in public beta, available in posthog-python 7.39+ and posthog-node 5.49+ (with @posthog/ai 8.8+). We'd love to hear your feedback as we roll it out.
AI events can get big – a single generation can carry megabytes of prompt context or base64-encoded media, more than regular event capture accepts. To handle this, PostHog sends AI events like $ai_generation and $ai_embedding through a dedicated ingestion path that accepts events up to 8MB.
During the beta, this path is opt-in. How you opt in depends on how you capture AI events today.
Using the SDK integrations
By default, our SDK integrations redact base64 media and may truncate very long strings before capture. To capture everything in full, pass a single flag when creating your PostHog client:
With the flag on, nothing is truncated or redacted. The one exception is privacy mode: when it's enabled, input and output content is still stripped, flag or no flag.
Calling capture_ai directly
If you build AI events yourself instead of using the integrations, call capture_ai (Python) or captureAi (Node) instead of capture. It takes the same arguments as capture and returns the captured event's UUID.
Send content as your provider produced it, including base64 and data URIs – there's no need to reshape payloads. capture_ai captures exactly what you pass it, without truncating or redacting anything. Privacy mode doesn't apply here, so leave out any content you don't want stored.
In serverless and other short-lived environments, use the awaitable variant in Node so the event is delivered before the runtime exits:
In Python, call posthog.flush() before exit (or enable sync_mode), just like with capture.
Other platforms
Not on Python or Node? Build events with manual capture and point your capture requests at the dedicated AI endpoint instead of the regular one – same request format, different path:
Sending over OpenTelemetry
If you send AI traces with OpenTelemetry, your spans arrive over OTLP at a dedicated path:
Two size limits apply on this path, and they fail in different ways:
- 4MB per export. PostHog rejects an OTLP export body over 4MB (measured after decompression for gzipped exports) with HTTP 413 and ingests none of its spans. Your collector logs the failure but does not retry it, per the OTLP spec, so the whole export is lost. This cap is lower than the per-event ceiling, so a batch of spans can exceed it before any single span does.
- 8MB per event. Each span becomes one AI event, held to the same 8MB ceiling as the other paths. A span whose converted event exceeds the ceiling is dropped, but the rest of the export is ingested and the request still returns success. A failure response would only make your collector retry a span that can never fit. The only signal is a
MessageSizeTooLargeingestion warning: your application gets no error, and the span is lost silently.
To stay under the 4MB export cap, add the batch processor to your collector and lower both of its batch size settings, so it splits large batches into smaller exports:
Set both values: the collector refuses to start if send_batch_max_size is below send_batch_size, which defaults to 8192. Both settings count spans rather than bytes, so a batch of a few very large spans can pass the count and still exceed 4MB. Pick values that match your span sizes. Keep send_batch_max_size at or below 100: the endpoint also rejects any export containing more than 100 AI spans. For a single span that is too large on its own, capture it with capture_ai instead.
Limits
Events up to 8MB are accepted for now. The SDKs drop larger events before sending and log an error instead. The limit will increase as the beta continues.
Over OpenTelemetry, a lower 4MB per-export cap also applies: an export over it is rejected with HTTP 413, while a span whose event exceeds 8MB is dropped without an application error.