Summary
The docs site never emitted download_cta_clicked. Analytics recorded zero CTA clicks against a full month of pageviews, so every visitor appeared to drop off at the first funnel transition.
Root cause
Not a name mismatch and not an SDK problem. trackDownloadClick in apps/docs/src/lib/analytics.ts was defined and exported but had no call site anywhere in the repo. The two components that render the CTA both opened the download dialog without calling it:
apps/docs/src/components/DownloadButton.tsx — openDialog() only set state. Rendered on the home hero, the home bottom CTA, /why-proofkit, and /examples.
apps/docs/src/components/DownloadLink.tsx — inline docs CTA, onClick={() => setOpen(true)}.
autocapture is enabled, so those clicks were recorded as $autocapture — which the funnel's step 2 does not match.
Its three sibling helpers in the same file (trackMarketingNavClick, trackDocsActionClick, trackPromoVideoOpened) were all wired into their components. This one was written and never hooked up.
Fix (prepared, pending PR)
trackDownloadClick now takes a required surface (DownloadCtaSurface union), treats variant as visual-style-only, and derives platformOverridden from selectedPlatform !== detectedPlatform inside the helper so the flag cannot drift between call sites.
surface is a required prop on DownloadButton, so a new CTA placement will not compile until it is named. All four existing sites tagged: home_hero, home_cta, why_proofkit_cta, examples_cta. DownloadLink reports docs_inline.
- Both components now call the tracker on click.
Regression coverage
apps/docs/tests/analytics.test.ts — the helper against a mocked posthog-js: event name, platformOverridden in both directions, variant absent on docs_inline, silence outside production.
apps/docs/tests/download-cta.test.tsx — the real components rendered and clicked with @/lib/analytics mocked: primary button, Windows UA detection, the dropdown platform-override path, and the inline docs link.
Mutation-tested: all four component tests fail with the trackDownloadClick calls removed, pass with them restored. A helper-only test would have passed on the broken code, which is how this shipped in the first place.
Adds @testing-library/react + @testing-library/dom as devDeps to @proofkit/docs and widens vitest.config.ts to include tests/**/*.test.tsx.
Note on tooling
pnpm knip does not catch this class of bug in this repo — verified by stripping the calls back out and re-running. Knip treats 35 files in apps/docs as unused, so it never builds a graph precise enough to see the dead export. It also currently exits non-zero with hundreds of findings and is not part of ci:pr. The required surface prop and the component tests are the real guards.
Summary
The docs site never emitted
download_cta_clicked. Analytics recorded zero CTA clicks against a full month of pageviews, so every visitor appeared to drop off at the first funnel transition.Root cause
Not a name mismatch and not an SDK problem.
trackDownloadClickinapps/docs/src/lib/analytics.tswas defined and exported but had no call site anywhere in the repo. The two components that render the CTA both opened the download dialog without calling it:apps/docs/src/components/DownloadButton.tsx—openDialog()only set state. Rendered on the home hero, the home bottom CTA,/why-proofkit, and/examples.apps/docs/src/components/DownloadLink.tsx— inline docs CTA,onClick={() => setOpen(true)}.autocaptureis enabled, so those clicks were recorded as$autocapture— which the funnel's step 2 does not match.Its three sibling helpers in the same file (
trackMarketingNavClick,trackDocsActionClick,trackPromoVideoOpened) were all wired into their components. This one was written and never hooked up.Fix (prepared, pending PR)
trackDownloadClicknow takes a requiredsurface(DownloadCtaSurfaceunion), treatsvariantas visual-style-only, and derivesplatformOverriddenfromselectedPlatform !== detectedPlatforminside the helper so the flag cannot drift between call sites.surfaceis a required prop onDownloadButton, so a new CTA placement will not compile until it is named. All four existing sites tagged:home_hero,home_cta,why_proofkit_cta,examples_cta.DownloadLinkreportsdocs_inline.Regression coverage
apps/docs/tests/analytics.test.ts— the helper against a mockedposthog-js: event name,platformOverriddenin both directions,variantabsent ondocs_inline, silence outside production.apps/docs/tests/download-cta.test.tsx— the real components rendered and clicked with@/lib/analyticsmocked: primary button, Windows UA detection, the dropdown platform-override path, and the inline docs link.Mutation-tested: all four component tests fail with the
trackDownloadClickcalls removed, pass with them restored. A helper-only test would have passed on the broken code, which is how this shipped in the first place.Adds
@testing-library/react+@testing-library/domas devDeps to@proofkit/docsand widensvitest.config.tsto includetests/**/*.test.tsx.Note on tooling
pnpm knipdoes not catch this class of bug in this repo — verified by stripping the calls back out and re-running. Knip treats 35 files inapps/docsas unused, so it never builds a graph precise enough to see the dead export. It also currently exits non-zero with hundreds of findings and is not part ofci:pr. The requiredsurfaceprop and the component tests are the real guards.