Analytics
Track how users interact with your documentation using PostHog. Doccupine captures page views in two layers out of the box - in the browser and on the server - so readers running ad blockers are still counted. Browser traffic is proxied through your own domain rather than going to PostHog directly.
analytics.json
Place an analytics.json at your project root (the same directory where you execute npx doccupine).
{
"provider": "posthog",
"posthog": {
"key": "phc_your_project_api_key",
"host": "https://us.i.posthog.com"
}
}Fields
- provider: The analytics provider to use. Currently only
"posthog"is supported. - posthog.key: Your PostHog project API key. You can find this in your PostHog project settings under "Project API Key". This is a public identifier - it is safe to commit to version control.
- posthog.host: The PostHog ingestion endpoint. Use
https://us.i.posthog.comfor US Cloud orhttps://eu.i.posthog.comfor EU Cloud. If you self-host PostHog, use your instance URL.
The PostHog project API key is a public identifier used to send events. It is not a secret and is safe to include in your repository.
What gets tracked
When analytics.json is configured, Doccupine enables two layers of tracking:
Client-side
- Page views: Captured on client-side (soft) navigations using Next.js router hooks. The initial page load is counted by the server instead, so one view is never counted twice.
- Page leave: Automatically captured when a user navigates away from a page.
Server-side
- Page views: Captured in middleware on document requests - the initial load of a page. Requests behind client-side navigations carry an
RSCheader and are skipped, because the browser already counts those. - Request metadata: URL, pathname, host, referrer, and user agent are sent with each event.
- Smart filtering: API routes, internal Next.js routes, and prefetch requests are automatically excluded.
- Ad-blocked readers: because this half runs on your server, readers who block PostHog in the browser are still counted.
Privacy proxy
Doccupine routes browser analytics traffic through your documentation domain using Next.js rewrites. Instead of the browser talking to PostHog directly (which ad blockers intercept), requests go through /ingest on your own domain and are proxied on.
This means:
- No third-party domains appear in the browser's network requests.
- Ad blockers are less likely to interfere with tracking.
- Your users' browsing data stays within your domain boundary before reaching PostHog.
The proxy destinations are derived automatically from the host field in your configuration.
The proxy covers browser traffic only. Server-side page views are sent from your server straight to PostHog - that is exactly what lets them survive an ad blocker.
Cookies
An analytics-enabled site sets two first-party cookies:
ph_<key>_posthog- set by posthog-js, holding its anonymous distinct id and session.dcp_anon_id- httpOnly, one year, set by the server so an ad-blocked reader (who never receives the posthog-js cookie) counts as one person instead of a new person on every request.
Both hold nothing but a random identifier. Whether they require a consent notice under GDPR/ePrivacy depends on your jurisdiction and what you do with the data; that call is yours.
Getting a PostHog key
- Sign up at posthog.com (free tier available).
- Create a new project.
- Go to Project Settings and copy the Project API Key.
- Paste it into your
analytics.jsonas theposthog.keyvalue.
Behavior
- Placement: Put
analytics.jsonin the project root alongsideconfig.jsonandtheme.json. - Hot reload: Changes to
analytics.jsonare picked up automatically in watch mode. The layout, middleware, and Next.js config are regenerated. - Graceful degradation: If
analytics.jsonis missing, empty, or has an invalid configuration, no tracking code runs. Your site works exactly the same without it. - Dev server restart: After adding or removing
analytics.jsonfor the first time, you may need to restart the Next.js dev server for proxy rewrites to take effect.
After adding analytics.json for the first time, restart the dev server so the proxy rewrites are picked up by Next.js.
Regions
PostHog offers two cloud regions. Set the host field accordingly:
| Region | Host |
|---|---|
| US Cloud | https://us.i.posthog.com |
| EU Cloud | https://eu.i.posthog.com |
If you omit the host field, it defaults to the US Cloud endpoint.
Example
Minimal configuration (US Cloud)
{
"provider": "posthog",
"posthog": {
"key": "phc_your_project_api_key"
}
}EU Cloud
{
"provider": "posthog",
"posthog": {
"key": "phc_your_project_api_key",
"host": "https://eu.i.posthog.com"
}
}Tips
- Start simple: Add the config with just your key and verify events appear in your PostHog dashboard before customizing further.
- Check your dashboard: After deploying, visit your PostHog project to confirm page view events are flowing in.
- Production only: Consider adding
analytics.jsononly in your production/deployment setup to avoid tracking local development traffic.