feat(open-knowledge): PostHog analytics for subscribe events#436
Merged
Conversation
* feat(open-knowledge): PostHog analytics for subscribe events
Capture newsletter signups in PostHog, server-side in the subscribe route, tagged
by originating surface. Lands on the privatized ok-marketing route (#2357).
- Emit newsletter_subscribed on success and newsletter_subscribe_failed (with a
bounded reason) on the 400/502/503 paths, from the ok-marketing route.
- Bounded `source` allowlist (marketing_site, resources_menu, post_update_card;
default unknown), validated with z.enum.
- Cookie-only identity via resolveDistinctId; no email/PII sent to PostHog
(Resend stays the system of record). Port track.ts into ok-marketing with an
import 'server-only' guard; reuses NEXT_PUBLIC_POSTHOG_KEY, no new dep.
- Thread `source` from all three surfaces: the marketing form and the app's
resources menu + post-update card.
- Tests: route capture (success + every failure path, source validation, and the
no-email-on-any-path guarantee) plus client body/arg assertions.
* refactor(open-knowledge): use posthog-node SDK for marketing capture
Switch the marketing app's server-side PostHog capture from a hand-rolled fetch
to the official posthog-node SDK (the documented server-side approach). Uses the
SDK's serverless pattern (flushAt:1, flushInterval:0, await shutdown()) inside
Next after() so it stays non-blocking. Same exported track API, so the route and
its tests are unchanged.
- Pin posthog-node to ^5.17.3 to match public/agents/agents-docs (no cross-tree
drift, no allowlist).
- Keep the server-only guard, cookie distinct_id reuse, and $ip/$geoip privacy
guards; the email is still never passed to PostHog.
- Add track.test.ts (mocks posthog-node + after) covering the capture shape,
privacy guards, shutdown, and no-key no-op.
Docs keeps its existing hand-rolled track.ts; standardizing both apps on
posthog-node is a separate refactor.
* refactor(open-knowledge): drop unbounded referrer from subscribe capture
Address reviewer feedback: the `referrer` property (raw Referer hostname) is
attacker-controllable and unbounded on this public cross-origin endpoint, which
contradicts the bounded-cardinality discipline deliberately applied to `source`.
Drop it from the subscribe events (and remove the now-unused referrerHostname
helper). source remains the intended attribution dimension.
Also add resolveDistinctId unit tests (cookie stitching + UUID fallbacks) that
were previously only covered in the docs app — the cookie-name format is a
silent-drift risk worth pinning.
* chore(open-knowledge): drop analytics SPEC from the public tree
The subscribe analytics is primarily about the private ok-marketing app; keep
its design decisions out of public/open-knowledge/ (belt-and-suspenders — specs/
is not in the public-mirror allowlist, so it was never exposed, but it does not
belong in the public tree).
* refactor(open-knowledge): harden subscribe capture (reviewer follow-ups)
Address non-blocking reviewer recommendations on the analytics PR:
- Cap posthog-node shutdown at 3s so a hung flush can't keep the serverless
function alive (matches the bound the docs helper used).
- Handle a thrown Resend SDK error the same as a returned { error } — a network
throw previously escaped to a 500 with no CORS headers (unreadable by the
cross-origin caller) and no failure capture; now it's a 502 + CORS +
resend_error event like any other Resend failure.
- Add capture assertions for the 503 (unavailable), unparseable-JSON, and
Resend-throw failure paths.
GitOrigin-RevId: 5e23b7817eb328a550ff8840b3e24b8d5c175a04
Contributor
There was a problem hiding this comment.
Automated approval from agents-private public-mirror-sync (run: https://github.com/inkeep/agents-private/actions/runs/28566321842). Source of truth is the monorepo; direct edits on inkeep/open-knowledge are overwritten on next sync.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.