diff --git a/ANALYTICS.md b/ANALYTICS.md
new file mode 100644
index 0000000..c1985b3
--- /dev/null
+++ b/ANALYTICS.md
@@ -0,0 +1,54 @@
+# Analytics on docs.openadapt.ai
+
+This documentation site uses privacy-safe, build-time analytics. This file lives
+at the repository root (not under `docs/`) so it does not affect the published
+site or `mkdocs build --strict` navigation.
+
+## What is tracked
+
+The site reports into two destinations that share one event taxonomy across all
+OpenAdapt web properties:
+
+- **PostHog** (product analytics), and
+- **Google Analytics 4** (Material's native integration).
+
+Tracked events:
+
+| Event | Properties | Notes |
+| --- | --- | --- |
+| `$pageview` | (automatic) | PostHog fires this via Material's `location$` observable so it works under `navigation.instant`. GA pageviews are handled natively by Material. |
+| `docs_search` | `query_length` | Only the LENGTH of the search query is captured, never the raw text. Debounced by ~800ms. |
+| `outbound_click` | `destination`, `href` | `destination` is one of `app`, `download`, or `github`. `href` is host + path only, with the query string stripped. |
+
+Search and pageview events are also emitted to Google Analytics where Material's
+native integration does not already cover them.
+
+## Shared project
+
+Both destinations are shared with the marketing site. PostHog reuses the same
+project (via the same env var names below), so all OpenAdapt properties report
+together.
+
+## Environment variables (set at BUILD time)
+
+Analytics is a static build, so keys are read when `mkdocs build` runs, not at
+page-serve time. Set these in the docs deploy/CI environment:
+
+- `NEXT_PUBLIC_POSTHOG_KEY`: PostHog project key. Reuse the SAME key as the
+ marketing site so everything lands in one PostHog project. When this is unset,
+ no PostHog script is emitted into the built HTML at all (a hard no-op).
+- `NEXT_PUBLIC_POSTHOG_HOST`: PostHog API host. Defaults to
+ `https://us.i.posthog.com`.
+- `GOOGLE_ANALYTICS_KEY`: GA4 measurement ID. Optional; defaults to the existing
+ `G-CJ01Y19XJN`. GA measurement IDs are public (non-secret).
+
+## Privacy properties
+
+- **No PHI or PII.** These are public documentation pages only.
+- **Do-Not-Track is respected.** When the browser sends a Do-Not-Track signal,
+ PostHog is never loaded or initialized.
+- **Conservative capture.** Search records only `query_length` (never the raw
+ query), and outbound links record only host + path (never the query string).
+- **PostHog `person_profiles: 'identified_only'`** so anonymous visitors do not
+ create person profiles.
+- **No secrets committed.** Keys are provided only through build-time env vars.
diff --git a/mkdocs.yml b/mkdocs.yml
index 228c019..fbccea9 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -19,6 +19,9 @@ copyright: >-
theme:
name: material
+ # Register the local overrides directory so overrides/main.html can inject the
+ # PostHog snippet and shared analytics event layer via the extrahead block.
+ custom_dir: overrides
logo: assets/logo.svg
favicon: assets/favicon.ico
# Match the public site's local system stacks and avoid a third-party font
@@ -85,6 +88,19 @@ markdown_extensions:
extra:
generator: false
+ # Analytics. See ANALYTICS.md (repo root) for the full data-handling notes.
+ # Google Analytics is env-driven; the fallback keeps the existing measurement
+ # ID working when GOOGLE_ANALYTICS_KEY is unset. GA measurement IDs are public
+ # (non-secret), so committing the fallback is fine.
+ analytics:
+ provider: google
+ property: !ENV [GOOGLE_ANALYTICS_KEY, "G-CJ01Y19XJN"]
+ # PostHog is read at BUILD time. When NEXT_PUBLIC_POSTHOG_KEY is unset (local
+ # builds and CI), posthog_key is "" and overrides/main.html emits no PostHog
+ # script at all. Reuses the same env var names and host as the marketing site
+ # so every property reports into one PostHog project.
+ posthog_key: !ENV [NEXT_PUBLIC_POSTHOG_KEY, ""]
+ posthog_host: !ENV [NEXT_PUBLIC_POSTHOG_HOST, "https://us.i.posthog.com"]
social:
- icon: fontawesome/brands/github
link: https://github.com/OpenAdaptAI
diff --git a/overrides/main.html b/overrides/main.html
new file mode 100644
index 0000000..18af438
--- /dev/null
+++ b/overrides/main.html
@@ -0,0 +1,130 @@
+{% extends "base.html" %}
+
+{#
+ Privacy-safe analytics for docs.openadapt.ai.
+
+ Google Analytics is wired through Material's native `extra.analytics` block
+ (see mkdocs.yml), which already handles pageviews and the built-in `search`
+ event, including under `navigation.instant`. This partial adds PostHog and a
+ small shared-taxonomy event layer on top.
+
+ The PostHog script is emitted only when NEXT_PUBLIC_POSTHOG_KEY is present at
+ BUILD time (mkdocs `!ENV` substitution). When the key is unset (local builds
+ and CI), the entire PostHog block is absent from the generated HTML: a hard
+ no-op, not a disabled runtime path.
+#}
+{% block extrahead %}
+ {{ super() }}
+
+ {% if config.extra.posthog_key %}
+
+
+ {% endif %}
+
+
+
+{% endblock %}