Skip to main content

Server analytics

The API and Nuxt/Nitro server each provide a process-local analytics client for explicit product events. Both clients use posthog-node, batch events in the background, and flush when their process shuts down.

This boundary is intentionally server-only. The application does not initialize posthog-js in the browser, capture page views, autocapture HTTP requests, or forward request and response bodies to PostHog. Product features decide whether an event is useful and own its event name, identifier, and properties.

Process boundaries​

The API constructs one analytics client in its Awilix container. It is shared infrastructure rather than a feature dependency: a future API slice should define the port it needs and adapt that port to the shared client instead of importing posthog-node directly.

Nitro constructs one client through its server plugin. The plugin adds that client to the H3 event context, so a server route can call event.context.analytics.capture(...). The context is available only while handling server requests; it is not part of Nuxt's browser runtime configuration.

An event consists of a distinctId, an event name, and optional properties:

analytics.capture({
distinctId: "user_123",
event: "booking created",
properties: { source: "api" },
});

Capturing is best-effort. A PostHog capture failure does not change an API command result or a Nitro route response. The API records a safe diagnostic message without event properties or configuration values; Nitro likewise contains the failure inside its analytics boundary.

Configuration and privacy​

Each server resolves its own private configuration:

ProcessProject tokenIngest host
APIPOSTHOG_PROJECT_TOKENPOSTHOG_HOST
Nuxt/NitroNUXT_POSTHOG_PROJECT_TOKENNUXT_POSTHOG_HOST

Hosts must be absolute HTTP or HTTPS URLs without embedded credentials. The Nuxt values are private runtime configuration, so neither is serialized into rendered HTML or the browser payload.

Production requires a complete, valid pair before either server accepts requests. Development uses a no-op client only when both values are absent; partial or invalid values are configuration errors. Tests always use the no-op client, even if variables are set, which prevents test runs from exporting events.

See Environment variables for complete setup and deployment requirements.

Shutdown​

The API closes Fastify, the SQS client, and the database before it shuts down analytics, then closes telemetry. Its shared shutdown promise means repeated close requests and partial-startup cleanup invoke the analytics shutdown once.

Nitro registers the same operation on its close hook. In both processes, the PostHog SDK shutdown flushes queued batches before the client closes. A shutdown failure is contained so the rest of the process cleanup can finish.