Skip to Content

Tracking

Every tracking export of @appfunnel-dev/sdk, generated from the SDK source. Signatures and descriptions are exact; for how these fit together, see the guides.

useTracker

hook · tracking/tracking.ts

useTracker(): { track: Tracker["track"]; }

const { track } = useTracker() — emit a custom event. Auto events (page.view, identify, purchase, …) fire on their own; this is the escape hatch for funnel-specific events (track('quiz_skipped', { step: 3 })).

attachBus

function · tracking/bus.ts

attachBus(bus: FunnelBus): () => void

Attach the bus’s public surface to window.appfunnel (client-side only). Returns a detach fn for unmount. No-op under SSR.

createBus

function · tracking/bus.ts

createBus(accessors: BusAccessors, now?: () => number): FunnelBus

Create a bus over the given read accessors. now is injectable for tests.

createConsoleTracker

function · tracking/tracking.ts

createConsoleTracker(opts?: { silent?: boolean; }): Tracker

A no-op-ish tracker that logs to the console — for tests, preview, local dev.

createPlatformTracker

function · tracking/platformTracker.ts

createPlatformTracker(cfg: PlatformTrackingConfig): Tracker

integrationEvents

function · tracking/catalog.ts

integrationEvents(): CatalogEvent[]

The events that feed integrations — the set a pixel loader subscribes to.

isIntegrationEvent

function · tracking/catalog.ts

isIntegrationEvent(name: string): boolean

True if the event is forwarded to ad/integration pixels.

isTrackableEvent

function · tracking/catalog.ts

isTrackableEvent(name: string): boolean

True if the event is persisted to analytics.

newEventId

function · tracking/tracking.ts

newEventId(): string

withBus

function · tracking/bus.ts

withBus(tracker: Tracker, bus: FunnelBus): Tracker

Wrap a Tracker so every emitted taxonomy event is mirrored to the bus (the client sink). identify() also surfaces a user.registered to the bus, so pixels see registration. The server sink (the inner tracker → CAPI) is untouched.

AppfunnelBusApi

interface · tracking/bus.ts

export interface AppfunnelBusApi extends BusAccessors { on(event: string, cb: Listener): () => void off(event: string, cb: Listener): void readonly events: BusEvent[] goTo(pageKey: string): boolean goNext(): void goPrevious(): void navigation(): NavSnapshot | null }

The public window.appfunnel surface — subscribe + read + drive the flow. It never exposes emit (no forged events) or setVariable (state stays funnel-owned).

BusAccessors

interface · tracking/bus.ts

export interface BusAccessors { getVariable: (key: string) => unknown getVariables: () => Record<string, unknown> getCurrentPageId: () => string | null getCustomerId: () => string | null getVisitorId: () => string | null }

Read accessors the bus exposes — wired to the funnel’s store + context.

BusEvent

interface · tracking/bus.ts

export interface BusEvent { event: string data: unknown ts: number }

EventMeta

interface · tracking/catalog.ts

export interface EventMeta { sources: EventSource[] tracking: boolean integrations: boolean runtime?: boolean }

FunnelBus

interface · tracking/bus.ts

export interface FunnelBus extends AppfunnelBusApi { emit(event: string, data?: unknown): void registerNavigation(nav: NavigationControl): () => void }

The internal bus: the public AppfunnelBusApi plus emit (SDK-only) and now injection. The SDK holds this; only AppfunnelBusApi reaches window.

FunnelEventDataMap

interface · tracking/tracking.ts

export interface FunnelEventDataMap { 'funnel.start': Record<string, never> 'page.view': { pageId: string; pageKey?: string; pageName?: string; isInitial?: boolean; eventId?: string } 'page.exit': { pageId: string; durationMs: number; activeMs: number } 'user.registered': { email: string; eventId?: string } 'checkout.start': { productId?: string; priceId?: string; productName?: string; surface?: string; amount?: number; currency?: string; eventId?: string } 'checkout.payment_added': { productId?: string; amount?: number; currency?: string; eventId?: string } 'checkout.failed': { category: string; declineCode?: string; productId?: string; intent?: string } 'checkout.already_purchased': { productId?: string; declineCode?: string; intent?: string } 'purchase.complete': { amount?: number; currency?: string; email?: string; eventId?: string; productId?: string } 'subscription.created': { amount?: number; currency?: string; productId?: string; eventId?: string } 'experi

PlatformTrackingConfig

interface · tracking/platformTracker.ts

export interface PlatformTrackingConfig { apiBase: string campaignId?: string | null preview?: { buildId: string token: string } | null funnelId: string visitorId?: string | null sessionId?: string | null experiment?: { id: string; variant: string; version?: number } route?: { id: string } mode?: 'test' | 'live' }

Tracker

interface · tracking/tracking.ts

export interface Tracker { getSessionId?(): string | null track<E extends KnownFunnelEvent>(event: E, data?: FunnelEventDataMap[E], userData?: Record<string, unknown>): void track(event: string, data?: Record<string, unknown>, userData?: Record<string, unknown>): void identify(email: string, eventId?: string): void setVariables?(variables: Record<string, unknown>): void setAcquisition?(acquisition: Acquisition): void }

The surface the runtime needs from a tracker. A subset of FunnelTracker, so the real one satisfies it directly; the console tracker is a trivial stub.

CatalogEvent

type · tracking/catalog.ts

export type CatalogEvent = keyof typeof EVENT_CATALOG

A catalog event name.

EventSource

type · tracking/catalog.ts

export type EventSource = 'frontend' | 'backend'

The event catalog — the single source of truth for which events exist and how each is routed (analytics vs. integrations vs. runtime-only). Pairs with the typed payloads in ./tracking.FunnelEventDataMap.

This replaces the duplication the monorepo flags (shared/events/catalog.ts is “documentation, not imported” — the taxonomy is re-declared in admin/lib/funnel/tracking.ts, each admin/lib/integrations/* EVENT_MAP, and api/src/integrations/constants). In v2 the SDK owns the taxonomy (it emits it), so the bus, the pixel loaders, and the platform all import this.

KnownFunnelEvent

type · tracking/tracking.ts

export type KnownFunnelEvent = keyof FunnelEventDataMap

EVENT_CATALOG

const · tracking/catalog.ts

EVENT_CATALOG: { readonly 'funnel.start': { readonly sources: ["frontend"]; readonly tracking: false; readonly integrations: false; readonly runtime: true; }; readonly 'experiment.exposure': { readonly sources: ["frontend"]; readonly tracking: true; readonly integrations: false; }; readonly 'page.view': { readonly sources: ["frontend"]; readonly tracking: true; readonly integrations: true; }; readonly 'page.exit': { readonly sources: ["frontend"]; readonly tracking: true; readonly integrations: false; }; readonly 'user.registered': { readonly sources: ["frontend"]; readonly tracking: true; readonly integrations: true; }; readonly 'checkout.start': { readonly sources: ["frontend"]; readonly tracking: true; readonly integrations: true; }; readonly 'checkout.payment_added': { readonly sources: ["frontend"]; readonly tracking: true; readonly integrations: true; }; readonly 'checkout.failed': { readonly sources: ["frontend"]; readonly tracking: true; readonly integrations: false; }; readonl…

Every event the system knows, with its routing metadata. Keys are the taxonomy names (a superset of FunnelEventDataMap: it also lists the backend-originated monetary events the platform pushes to the client bus for pixel firing).

Last updated on