PostHog Adapter
PostHog is an open-source product analytics platform. The evlog PostHog adapter sends your wide events as PostHog events, letting you query server-side logs alongside your product analytics, session replays, and feature flags.
Installation
The PostHog adapter comes bundled with evlog:
import { createPostHogDrain } from 'evlog/posthog'
Quick Start
1. Get your PostHog project API key
- Log in to your PostHog dashboard
- Go to Settings > Project > Project API Key
- Copy the key (starts with
phc_)
2. Set environment variables
NUXT_POSTHOG_API_KEY=phc_your-project-api-key
3. Create the drain plugin
import { createPostHogDrain } from 'evlog/posthog'
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:drain', createPostHogDrain())
})
That's it! Your wide events will now appear in PostHog as evlog_wide_event events.
Configuration
The adapter reads configuration from multiple sources (highest priority first):
- Overrides passed to
createPostHogDrain() - Runtime config at
runtimeConfig.evlog.posthog - Runtime config at
runtimeConfig.posthog - Environment variables (
NUXT_POSTHOG_*orPOSTHOG_*)
Environment Variables
| Variable | Description |
|---|---|
NUXT_POSTHOG_API_KEY | Project API key (starts with phc_) |
NUXT_POSTHOG_HOST | PostHog host URL (for EU or self-hosted) |
You can also use POSTHOG_API_KEY and POSTHOG_HOST as fallbacks.
Runtime Config
Configure via nuxt.config.ts for type-safe configuration:
export default defineNuxtConfig({
runtimeConfig: {
posthog: {
apiKey: '', // Set via NUXT_POSTHOG_API_KEY
host: '', // Set via NUXT_POSTHOG_HOST
},
},
})
Override Options
Pass options directly to override any configuration:
import { createPostHogDrain } from 'evlog/posthog'
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:drain', createPostHogDrain({
eventName: 'server_request',
distinctId: 'my-backend-service',
timeout: 10000,
}))
})
Full Configuration Reference
| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | - | Project API key (required) |
host | string | https://us.i.posthog.com | PostHog host URL |
eventName | string | evlog_wide_event | PostHog event name |
distinctId | string | event.service | Override distinct_id for all events |
timeout | number | 5000 | Request timeout in milliseconds |
Regions
PostHog offers US and EU cloud hosting. Set the host to match your region:
| Region | Host |
|---|---|
| US (default) | https://us.i.posthog.com |
| EU | https://eu.i.posthog.com |
| Self-hosted | Your instance URL |
# EU region
NUXT_POSTHOG_API_KEY=phc_xxx
NUXT_POSTHOG_HOST=https://eu.i.posthog.com
Event Format
evlog maps wide events to PostHog events:
| evlog Field | PostHog Field |
|---|---|
service | distinct_id (default) |
timestamp | timestamp |
level | properties.level |
service | properties.service |
environment | properties.environment |
| All other fields | properties.* |
The event name defaults to evlog_wide_event but can be customized via the eventName option.
Custom Event Name
Use a custom event name to differentiate log types in PostHog:
import { createPostHogDrain } from 'evlog/posthog'
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:drain', createPostHogDrain({
eventName: 'server_wide_event',
}))
})
Custom Distinct ID
By default, distinct_id is set to the event's service name. Override it to correlate with your users:
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:drain', async (ctx) => {
const posthogDrain = createPostHogDrain({
// Use the user ID from the wide event if available
distinctId: ctx.event.userId as string ?? ctx.event.service,
})
await posthogDrain(ctx)
})
})
Querying Logs in PostHog
Once your events are flowing, you can query them in PostHog:
- Go to Events and filter by
evlog_wide_event - Use Insights to build dashboards on your wide event properties
- Create Cohorts based on server-side behavior (e.g., users who triggered errors)
Example queries you can build:
- Error rate by endpoint (
properties.path,properties.level = error) - Slow requests over time (
properties.duration > 1000) - Request volume by service (
properties.service)
Troubleshooting
Missing apiKey error
[evlog/posthog] Missing apiKey. Set NUXT_POSTHOG_API_KEY/POSTHOG_API_KEY env var or pass to createPostHogDrain()
Make sure your environment variable is set and the server was restarted after adding it.
Events not appearing
PostHog processes events asynchronously. There may be a short delay (typically under 1 minute) before events appear in the dashboard.
- Check the server console for
[evlog/posthog]error messages - Verify your API key is correct and starts with
phc_ - Confirm your
hostmatches your PostHog region (US vs EU)
Wrong region
If you're on PostHog EU but using the default US host, event delivery will fail and the adapter will log errors (for example under [evlog/posthog]) to your server console. Set the correct host:
NUXT_POSTHOG_HOST=https://eu.i.posthog.com
Direct API Usage
For advanced use cases, you can use the lower-level functions:
import { sendToPostHog, sendBatchToPostHog, toPostHogEvent } from 'evlog/posthog'
// Send a single event
await sendToPostHog(event, {
apiKey: 'phc_xxx',
})
// Send multiple events in one request
await sendBatchToPostHog(events, {
apiKey: 'phc_xxx',
})
// Convert event to PostHog format (for inspection)
const posthogEvent = toPostHogEvent(event, { apiKey: 'phc_xxx' })
Next Steps
- Axiom Adapter - Send logs to Axiom
- OTLP Adapter - Send logs via OpenTelemetry Protocol
- Custom Adapters - Build your own adapter
- Best Practices - Security and production tips