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
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, events will fail silently. 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