@the-grid-data/analytics
v0.3.0
Published
Shared Grid analytics emitter — emitGridEvent + bot/AI matchers + viewer-role resolver + sampling. Single source of truth for the unified PostHog telemetry contract across every Grid surface.
Readme
@the-grid-data/analytics
The single shared emitter for The Grid's unified PostHog telemetry contract. Every Grid surface — Discovery, Directory subdomains, the Network portal, admin, reports, GridMCP — emits the same six events with the same property shape through this package, so analytics are consistent across surfaces and cross-surface joins (impression → click → view) work.
The six-event contract at a glance
| Event | When | Emitted from |
|---|---|---|
| category_page_viewed | A category/list page renders | client |
| profile_impression | A result card is ≥50% visible for ≥500ms | client (./react) |
| category_result_clicked | A result card is clicked | client |
| profile_viewed | A profile page is served | server (adblocker-immune) |
| profile_lens_displayed | A lens (profile/product/asset/contract) shows | client |
| profile_url_clicked | An outbound profile URL is clicked | client |
Every event carries a 16-field shared property contract (profile + surface
identity, lens, viewer role, session, bot/AI classification, referrer
source, versioning). buildGridEventPayload assembles and validates it:
null is a valid value, missing is rejected. The funnel joins on
list_instance_id (impression ↔ click ↔ view) and session_id.
Install
pnpm add @the-grid-data/analytics
# peer deps — install the ones your runtime uses:
pnpm add posthog-js # browser emits
pnpm add posthog-node # server emitsReact (for ./react and ./next/client) is also an optional peer.
Subpath map
| Import | What it is | Deps |
|---|---|---|
| . / ./core | Pure contract: types, enums, payload builder, bot/AI matchers, viewer-role resolver, sampling, list_instance_id helpers | none |
| ./client | emitGridEvent bound to a posthog-js instance you provide | posthog-js |
| ./server | emitGridEvent bound to a posthog-node client you provide | posthog-node |
| ./react | useImpressionObserver + ListContextProvider (impression primitive) | react |
| ./next | Next.js server helpers: createRelayRewrites, emitServerProfileViewed, deriveSessionId, request guards | posthog-node (lazy) |
| ./next/client | Next.js browser helpers: createGridPosthog, useGridPosthog, GridAnalyticsProvider | posthog-js, react |
core is dependency-free by design and safe to import anywhere; the
bindings never call posthog.init or read env. The ./next layer is the
opinionated exception: it owns instance creation and reads the canonical
env var so a new app wires up in four mechanical steps.
Quickstart (Next.js)
Set
NEXT_PUBLIC_GRID_ANALYTICS_POSTHOG_KEY(the PostHog project write key — public-safe). Helpers warn once and no-op when it is unset.Proxy browser ingest through a first-party path (
next.config.ts):
import { createRelayRewrites } from '@the-grid-data/analytics/next';
nextConfig.skipTrailingSlashRedirect = true;
nextConfig.rewrites = async () => ({
beforeFiles: createRelayRewrites({ region: 'eu' }),
});- Mount the browser instance and emit client events:
'use client';
import { useGridPosthog } from '@the-grid-data/analytics/next/client';
import { emitGridEvent } from '@the-grid-data/analytics/client';
import { GRID_EVENTS } from '@the-grid-data/analytics';
const posthog = useGridPosthog({ persistenceName: 'ph_grid_myapp' });
// once ready (non-null):
emitGridEvent(posthog, GRID_EVENTS.CATEGORY_PAGE_VIEWED, { shared, props });- Emit the server-side
profile_viewedfrom middleware:
import { emitServerProfileViewed } from '@the-grid-data/analytics/next';
export function middleware(request: NextRequest, event: NextFetchEvent) {
emitServerProfileViewed(request, event, {
surface: 'myapp',
surfaceSlug: slug,
profileSlug,
});
}- Wire lists with
ListContextProvider+useImpressionObserver(./react) and hand thelist_instance_idacross clicks withwithListContext.
The full wiring guide — client/server event routing, the named-instance
and persistence incantations, proxy traps, prefetch/bot guards, session-id
conventions, sampling, and the release flow — is in
docs/INTEGRATION.md (shipped in this package).
License
MIT
