Analytics & page ratings
Drop in any of 16 analytics platforms from config, and capture page-rating feedback as events.
Aardvark ships native support for the same analytics platforms as Mintlify. Add a block
under integrations: with your platform’s id or key and Aardvark injects that vendor’s
official <script> on every page — no template editing. Platform keys and legacy fields
remain Mintlify-compatible, while vendor-current additions are available too. In particular,
Plausible now prefers its per-site scriptId; an existing Mintlify-style domain block
continues to work unchanged.
integrations:
ga4:
measurementId: "G-XXXXXXXXXX" # Google Analytics 4
plausible:
scriptId: "pa-XXXXXXXXXXXX" # copy from Plausible's Site Installation snippet
posthog:
apiKey: "phc_XXXXXXXX"
A block whose required field is empty (e.g. measurementId: "") is treated as off — leave it
empty to keep that platform silent, and set it to your real id to switch it on. (This sample
site wires a real GA4 id so its live demo records analytics — see integrations.analytics in
aardvark.config.yaml.) If you set a block but misspell its required field, the build prints a
one-line warning so the mistake isn’t silent.
Not a secret. Every analytics id ships in the page’s HTML by design, so committing it is
fine. For per-deploy values, a build-time env var is still cleaner — see the AARDVARK_KEY
note under the AI assistant for that pattern.
Not a secret. Every analytics id ships in the page’s HTML by design, so committing it is
fine. For per-deploy values, a build-time env var is still cleaner — see the AARDVARK_KEY
note under the AI assistant for that pattern.
Supported platforms
Each platform is a block under integrations:. Set the required field(s) and you’re done.
| Platform | Config key | Required | Notes |
|---|---|---|---|
| Google Analytics 4 | ga4 |
measurementId |
Also accepts the legacy analytics.measurementId key |
| Google Tag Manager | gtm |
tagId |
Injects the head loader and the <noscript> fallback |
| Plausible | plausible |
scriptId (id alias) |
Preferred current per-site tracker; optional scriptSrc replaces only its loader URL. Legacy domain + optional src remains supported unchanged |
| Fathom | fathom |
siteId |
|
| PostHog | posthog |
apiKey |
Optional apiHost (default https://us.i.posthog.com; use https://eu.i.posthog.com or a proxy) |
| Mixpanel | mixpanel |
projectToken |
Tracks pageviews by default. Session Replay and heatmaps ship on by default (the vendor’s current recommendation) — optional recordSessionsPercent (integer 0–100, default 100 = every session) caps how much replay is recorded (use 0 to record no sessions) and recordHeatmapData (true/false, default true) toggles heatmaps; setting either empty/invalid warns and turns just that feature off |
| Amplitude | amplitude |
apiKey |
Browser SDK 2 with autocapture + remote config; network-request capture is left off so request URLs/bodies aren’t sent to Amplitude. Session Replay ships on by default — optional sessionReplaySampleRate (0–1, default 1 = every session) caps how much is recorded (use 0 to load the plugin but record nothing; omit the key for the full-rate default — leaving it empty/null warns rather than recording everything) |
| Microsoft Clarity | clarity |
projectId |
|
| Heap | heap |
appId |
|
| Hotjar | hotjar |
hjid, hjsv |
hjsv is the snippet version (defaults to 6) |
| LogRocket | logrocket |
appId |
|
| Pirsch | pirsch |
id |
The site’s identification code |
| Segment | segment |
key |
The source write key; emits Segment’s current browser snippet protocol (5.2.1) |
| Clearbit | clearbit |
publicApiKey |
Now HubSpot Breeze Intelligence |
| Hightouch | hightouch |
writeKey |
Optional apiHost (default us-east-1.hightouch-events.com) |
| Adobe Analytics | adobe |
launchUrl |
The full Adobe Launch / AEP Tags embed URL |
A fuller example mixing several:
integrations:
fathom:
siteId: "ABCDEFGH"
hotjar:
hjid: 1234567
hjsv: 6
segment:
key: "wk_live_XXXXXXXX"
posthog:
apiKey: "phc_XXXXXXXX"
apiHost: "https://eu.i.posthog.com" # optional override
plausible:
scriptId: "pa-XXXXXXXXXXXX"
scriptSrc: "/js/plausible.js" # optional custom loader URL
Plausible’s current snippet uses a unique script id for each site. Copy the id from the
https://plausible.io/js/<scriptId>.js URL shown under Site Installation; Aardvark emits
that async loader plus Plausible’s queue and plausible.init() shim. id is accepted as a
short alias. If both scriptId and domain are present during a migration, scriptId wins.
The current mode’s override is named scriptSrc deliberately: legacy src commonly points at
the old script.js, which cannot replace the new per-site loader. A legacy src alongside
scriptId is ignored with a build warning so a partial migration cannot silently mix protocols.
scriptSrc changes only where the JavaScript is loaded from; it does not change Plausible’s event
endpoint, so it must not be treated as complete proxy configuration.
Existing sites do not have to migrate immediately. The older domain-based form remains a
legacy compatibility path and keeps emitting the previous defer/data-domain snippet:
integrations:
plausible:
domain: "docs.example.com"
src: "https://plausible.example.com/js/script.js" # optional legacy self-host
Migrating from Mintlify? Copy the analytics/integration entries from your docs.json
straight into integrations: (YAML instead of JSON). The legacy keys and fields stay compatible,
with two name fixes Mintlify itself uses: Segment’s field is key, Hightouch’s is writeKey.
A Plausible domain block still works; switch it to the per-site scriptId when you are ready
to adopt Plausible’s current tracker.
Mintlify’s cookies and telemetry entries aren’t analytics platforms — telemetry is
Mintlify-internal, and for a cookie-consent banner use a custom snippet.
Migrating from Mintlify? Copy the analytics/integration entries from your docs.json
straight into integrations: (YAML instead of JSON). The legacy keys and fields stay compatible,
with two name fixes Mintlify itself uses: Segment’s field is key, Hightouch’s is writeKey.
A Plausible domain block still works; switch it to the per-site scriptId when you are ready
to adopt Plausible’s current tracker.
Mintlify’s cookies and telemetry entries aren’t analytics platforms — telemetry is
Mintlify-internal, and for a cookie-consent banner use a custom snippet.
Which parts of a page readers reach
The events above tell you a page was opened and how it was rated. To see which sections of it readers actually got to — and which install commands were copied, which CTAs were clicked — turn on Content Reach (Business and Enterprise). It records section visibility using your page’s own heading anchors, with no cookies, no coordinates, and no visitor identity.
Anything else? Inject any snippet
For a tracker not in the table above — or any other third-party tag — paste its snippet into
integrations.custom. The head value is emitted verbatim into every page’s <head>, and
body just before the closing </body>:
integrations:
custom:
head: |
<script defer src="https://cdn.example-analytics.com/tag.js"
data-site="my-site"></script>
body: |
<noscript><img src="https://example-analytics.com/noscript.gif"></noscript>
This content is injected raw (it isn’t escaped — that’s the point), so treat it like the
theme template: only put trusted markup there. It’s injected after the built-in integrations
(the analytics platforms above), so a custom snippet can reference them.
Google Analytics
GA4 is the one platform with deeper integration: the page-rating and reader-survey widgets
below record their results as gtag events, so they light up automatically once GA is
configured (under either ga4.measurementId or the legacy analytics.measurementId).
integrations:
ga4:
measurementId: "G-XXXXXXXXXX"
Aardvark injects the standard gtag.js snippet. An empty id disables it; this sample site sets
a real id, so GA is active here.
Page ratings
The default theme adds a “Was this page helpful?” widget at the bottom of every
page — the built-in PageFeedback island. A visitor picks a star rating (they can
adjust it — the value they settle on is what’s recorded); the widget thanks them and
reveals an optional comment box (a Mantine Textarea + a Submit button). Two
Google Analytics events fire, each once per page:
// once, after the reader settles on a star (re-picks within ~600ms are debounced)
gtag('event', 'page_rating', {
event_label: location.pathname, // which page was rated
value: 4, // the chosen number of stars (1–5)
});
// when the optional comment is submitted
gtag('event', 'page_rating_comment', {
event_label: location.pathname, // which page the comment is about
comment: 'the search box was hard to find', // capped at ~100 chars
value: 4, // the star rating they gave
});
The widget always renders; the events only fire when Analytics is configured (so
gtag exists). The page URL rides in its own event_label param so it’s always
captured in full, and the comment is a separate comment param — GA4 caps each
parameter value at ~100 characters, so the box stops accepting input at 100 (with a
live counter) and the value is trimmed defensively before sending.
The reader can change their pick before it’s recorded — re-picks are debounced, so a
3 → 5 correction sends a single page_rating with the final 5; once recorded, the
stars lock so the visible rating always matches what was sent.
To customize the wiring — send the events elsewhere (your own endpoint, PostHog, …),
change the copy, or restyle the box — drop a snippets/PageFeedback.jsx into your
project; a project snippet of that name overrides the built-in island. To drop the
widget entirely, set pageFeedback: false in aardvark.config.yaml. (The standalone
{% rating %} component is still available for star ratings
anywhere in your content.)
Privacy: the comment is free-form text sent to Google Analytics, so the widget
shows a “Please don’t include personal information.” notice under the box by default
(and comments only leave the browser when Analytics is configured). If you operate
under GDPR/CCPA or similar and need an explicit disclosure, a privacy-policy link, or
consent before capture, change the commentNotice string or gate the widget via
snippets/PageFeedback.jsx.
Privacy: the comment is free-form text sent to Google Analytics, so the widget
shows a “Please don’t include personal information.” notice under the box by default
(and comments only leave the browser when Analytics is configured). If you operate
under GDPR/CCPA or similar and need an explicit disclosure, a privacy-policy link, or
consent before capture, change the commentNotice string or gate the widget via
snippets/PageFeedback.jsx.
GA4 setup: comment and event_label are custom event parameters — GA4
collects them (visible in DebugView and the BigQuery export) but won’t show them in
standard reports or Explore until you register each as a custom dimension (Admin →
Custom definitions → Custom dimensions, scope: Event, parameter names comment
and event_label). Without that, comments are still captured but never appear in the
GA4 UI. value is built in and needs no setup.
GA4 setup: comment and event_label are custom event parameters — GA4
collects them (visible in DebugView and the BigQuery export) but won’t show them in
standard reports or Explore until you register each as a custom dimension (Admin →
Custom definitions → Custom dimensions, scope: Event, parameter names comment
and event_label). Without that, comments are still captured but never appear in the
GA4 UI. value is built in and needs no setup.
Note: GA4 treats value as its built-in (monetary) metric. We reuse it for the
star count — it records and averages fine in reports, but if that collides with your
own use of value, rename it to a custom parameter in snippets/PageFeedback.jsx.
Note: GA4 treats value as its built-in (monetary) metric. We reuse it for the
star count — it records and averages fine in reports, but if that collides with your
own use of value, rename it to a custom parameter in snippets/PageFeedback.jsx.
Upgrading? The page-feedback widget changed from a 👍/👎 pair to a 1–5 star
rating, and the page_rating event payload changed with it — the old
{ rating: 'up'|'down', value: 1|0, page_path } is now
{ event_label: <path>, value: 1–5 }. Update any GA dashboards, custom dimensions,
or alerts that filtered on rating, value == 1, or page_path. The
page_rating_comment event is new.
Upgrading? The page-feedback widget changed from a 👍/👎 pair to a 1–5 star
rating, and the page_rating event payload changed with it — the old
{ rating: 'up'|'down', value: 1|0, page_path } is now
{ event_label: <path>, value: 1–5 }. Update any GA dashboards, custom dimensions,
or alerts that filtered on rating, value == 1, or page_path. The
page_rating_comment event is new.