Adapters

PostHog Adapter

Send logs to PostHog as events for product analytics, session replay correlation, and wide event querying.

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:

server/plugins/evlog-drain.ts
import { createPostHogDrain } from 'evlog/posthog'

Quick Start

1. Get your PostHog project API key

  1. Log in to your PostHog dashboard
  2. Go to Settings > Project > Project API Key
  3. Copy the key (starts with phc_)

2. Set environment variables

.env
NUXT_POSTHOG_API_KEY=phc_your-project-api-key

3. Create the drain plugin

server/plugins/evlog-drain.ts
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):

  1. Overrides passed to createPostHogDrain()
  2. Runtime config at runtimeConfig.evlog.posthog
  3. Runtime config at runtimeConfig.posthog
  4. Environment variables (NUXT_POSTHOG_* or POSTHOG_*)

Environment Variables

VariableDescription
NUXT_POSTHOG_API_KEYProject API key (starts with phc_)
NUXT_POSTHOG_HOSTPostHog 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:

nuxt.config.ts
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:

server/plugins/evlog-drain.ts
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

OptionTypeDefaultDescription
apiKeystring-Project API key (required)
hoststringhttps://us.i.posthog.comPostHog host URL
eventNamestringevlog_wide_eventPostHog event name
distinctIdstringevent.serviceOverride distinct_id for all events
timeoutnumber5000Request timeout in milliseconds

Regions

PostHog offers US and EU cloud hosting. Set the host to match your region:

RegionHost
US (default)https://us.i.posthog.com
EUhttps://eu.i.posthog.com
Self-hostedYour instance URL
.env
# 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 FieldPostHog Field
servicedistinct_id (default)
timestamptimestamp
levelproperties.level
serviceproperties.service
environmentproperties.environment
All other fieldsproperties.*

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:

server/plugins/evlog-drain.ts
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:

server/plugins/evlog-drain.ts
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:

  1. Go to Events and filter by evlog_wide_event
  2. Use Insights to build dashboards on your wide event properties
  3. 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.

  1. Check the server console for [evlog/posthog] error messages
  2. Verify your API key is correct and starts with phc_
  3. Confirm your host matches 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:

.env
NUXT_POSTHOG_HOST=https://eu.i.posthog.com

Direct API Usage

For advanced use cases, you can use the lower-level functions:

server/utils/posthog.ts
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

Copyright © 2026