Skip to main content
GUIDE · POSTHOG7 min read

PostHog + TrackLayer: open-source product analytics + ad CAPI

A practical operating model for teams that want PostHog to stay strong on product analytics, feature flags, and session recordings while TrackLayer turns the same high-value actions into canonical server-side conversions for ad platforms, CRM, and warehouse downstreams.

Context

PostHog's role

PostHog is valuable because it keeps product analytics close to the team that ships the product. It is open-source, has a serious self-hosted option for teams that need tighter control over data residency or internal networking, and it covers the product analytics workflow well: event analysis, funnels, retention, session recordings, experimentation, and feature flags. That makes it a strong home for behavioral detail that ad platforms should never be asked to interpret directly.

TrackLayer fits beside PostHog, not in place of it. Once a user action becomes commercially meaningful, the main job is no longer replay analysis or feature adoption. The job becomes canonical naming, deduplication, identity continuity, consent-aware routing, revenue parity, and delivery into Meta, Google, TikTok, CRM systems, and warehouses. PostHog keeps the rich behavioral truth. TrackLayer turns the conversion-grade subset into a stable activation contract.

Build

Setup

Step 1

Decide which events belong in both systems

Do not start by mirroring every UI interaction. Pick the small set that matters to product and growth at the same time: `sign_up`, `lead`, `start_trial`, `begin_checkout`, `purchase`, `refund`, and a few qualification milestones. Give each one a canonical event name, one timestamp rule, and one event ID format. PostHog can still receive a richer product stream, but the shared lane should stay narrow and stable.

Canonical event
event: purchase
event_id: ord_20491_purchase
occurred_at: 2026-04-24T10:15:30Z
user_id: cust_481
anonymous_id: anon_91b2
value: 129.95
currency: EUR
Step 2

Send product events into PostHog through `/capture`

PostHog should keep receiving the product event stream through its `/capture` ingestion endpoint. Use a stable `distinct_id`, explicit event names, and properties that are useful for analysis later. When the same action is important to TrackLayer, include a reusable event ID in the PostHog properties so tracing across systems stays straightforward.

POST https://us.i.posthog.com/capture/
Content-Type: application/json

{
  "api_key": "POSTHOG_PROJECT_API_KEY",
  "event": "Purchase Completed",
  "distinct_id": "cust_481",
  "properties": {
    "$insert_id": "ord_20491_purchase",
    "order_id": "ord_20491",
    "value": 129.95,
    "currency": "EUR",
    "plan": "pro"
  },
  "timestamp": "2026-04-24T10:15:30Z"
}
Step 3

Identify users at the same handoff moment

PostHog identity gets messy when anonymous browsing and authenticated activity are not joined at the same time TrackLayer receives its stronger identity anchors. On signup, login, or lead form completion, call PostHog identify with the user ID and traits you actually trust. Then send the same user ID, anonymous ID, and hashed identifiers into TrackLayer so later server-side purchases or renewals still connect to the same person.

posthog.identify("cust_481", {
  email: "buyer@example.com",
  plan: "pro",
  company_id: "acct_44",
});

TrackLayer identity hints
user_id → cust_481
anonymous_id → anon_91b2
email_sha256 → 9d7c...e31a
Step 4

Forward the same canonical event into TrackLayer

TrackLayer should receive the same business action from your backend, event gateway, or queue. That keeps value, currency, timestamps, and identifiers aligned with what PostHog saw. From there TrackLayer can map the canonical event into Meta CAPI, Google Ads enhanced conversions, TikTok Events API, Klaviyo, or warehouse destinations without every upstream service learning destination-specific payloads.

await fetch("https://api.tracklayer.io/v1/events", {
  method: "POST",
  headers: {
    "content-type": "application/json",
    authorization: "Bearer TRACKLAYER_API_KEY",
  },
  body: JSON.stringify({
    event: "purchase",
    event_id: "ord_20491_purchase",
    occurred_at: "2026-04-24T10:15:30Z",
    user_id: "cust_481",
    anonymous_id: "anon_91b2",
    order_id: "ord_20491",
    value: 129.95,
    currency: "EUR",
  }),
});
Step 5

Validate one trace before broad rollout

Pick one test user and trace one event end to end. In PostHog, verify the event appears with the expected `distinct_id`, event name, replay context, and revenue fields. In TrackLayer, verify the same event ID resolves to one canonical action, the identity graph attaches correctly, and one downstream ad platform accepts the conversion. Only widen the shared event set after that path is stable.

Validation path
App/backend → PostHog /capture
App/backend → PostHog identify
App/backend → TrackLayer canonical event
TrackLayer → Meta CAPI or Google Ads

Checks
1. Same event_id in both systems
2. Same value and currency
3. Same identity anchors
4. One accepted downstream conversion
Mapping

Event mapping

Keep the cross-system vocabulary intentionally small. PostHog can keep descriptive product event names, but the actions that leave your analytics stack should map into a stable TrackLayer canonical set so downstream conversion APIs and warehouse models read the same event contract.

Source actionPostHog eventTrackLayer canonicalTypical downstream event
Product ViewedProduct Viewedview_contentViewContent / product view
Product AddedProduct Addedadd_to_cartAddToCart
Checkout StartedCheckout Startedbegin_checkoutInitiateCheckout
Lead SubmittedLead SubmittedleadQualified lead / offline conversion
Signed UpSigned Upsign_upCompleteRegistration
Trial StartedTrial Startedstart_trialTrial conversion
Purchase CompletedPurchase CompletedpurchasePurchase
Debugging

Session recording bridge

A strong pattern is to let PostHog keep the replay, then pass the replay locator into TrackLayer events. That can be a PostHog session ID, a direct recording URL, or both. When a purchase fails to route, a lead is malformed, or a conversion does not match downstream, operators can open the TrackLayer event log and jump straight into the exact user session that produced it. This shortens the path from conversion failure to root cause because payload inspection and user replay stay connected.

The implementation is simple: capture the current PostHog session identifier in your app or backend context, then attach `posthog_session_id` and optionally `posthog_replay_url` to the TrackLayer payload. Keep it as metadata rather than a canonical business field. That way TrackLayer can expose it in logs, warehouse exports, and support views without forcing replay data into every downstream destination schema.

{
  "event": "purchase",
  "event_id": "ord_20491_purchase",
  "posthog_session_id": "01961a87-6db8-7f2e-b1af-1aa4b88f0e72",
  "posthog_replay_url": "https://eu.posthog.com/project/123/replay/01961a87-6db8-7f2e-b1af-1aa4b88f0e72"
}
Audiences

Cohort sync pattern

PostHog cohorts are useful for behavioral questions such as users who activated but did not purchase, churn-risk accounts, or accounts that adopted a premium feature. TrackLayer should not try to replicate the full cohort engine. Instead, treat PostHog as the cohort source and export cohort membership snapshots or trait flags into TrackLayer on a schedule. TrackLayer can then use those flags to govern audience forwarding into ad and CRM destinations.

The pattern that scales is one-way enrichment, not constant bidirectional syncing. PostHog computes the behavioral cohort. TrackLayer receives a compact trait like `posthog_cohort_power_users=true` or `posthog_cohort_checkout_abandoners=true` with a timestamp. That is enough for server-side audience activation while leaving the more complex cohort logic in the product analytics system where it belongs.

Infrastructure

Self-hosted PostHog

Self-hosting PostHog changes the networking conversation. Your emitters may need private DNS, internal TLS trust, VPC peering, or egress allowlists before they can reach the PostHog `/capture` endpoint reliably. If TrackLayer stays cloud-hosted, you now have two delivery paths with different trust boundaries: one internal for product analytics and one external for activation. Treat them separately rather than assuming the same retry, timeout, and firewall rules should apply to both.

The practical requirement is predictability. Make sure the service that emits events can resolve and reach your PostHog host, can tolerate brief replay or ingestion latency, and can still forward the canonical event to TrackLayer even if PostHog is degraded. Queueing helps here. So does keeping the TrackLayer payload thin. Self-hosting can be a strong choice, but only if event delivery paths are explicit and observable.

FAQ

Common questions

Does TrackLayer replace PostHog?

No. PostHog should keep the product analytics job: funnels, paths, recordings, retention, experiments, and feature flag analysis. TrackLayer should own the canonical activation stream used for server-side conversion APIs, identity-aware delivery, and downstream revenue routing.

Should every PostHog event go to TrackLayer?

Usually no. Most clicks, page events, and UI instrumentation are valuable in PostHog but create noise in paid media and CRM systems. Send the events that mark business milestones or optimization signals, not the entire product telemetry stream.

What should I use for deduplication?

Use one stable event ID per business action. In PostHog that can live in `$insert_id` or another explicit property. In TrackLayer it should be the canonical `event_id` that survives retries, backfills, and downstream fan-out.

Can I self-host PostHog and still use TrackLayer cloud delivery?

Yes. That is a common split. Keep PostHog inside your network or region for product analytics, then allow the smaller TrackLayer-bound event stream to leave the environment through a controlled egress path. The main requirement is stable network reachability from your emitters to both systems.

Next reads

Related implementation guides

We use essential cookies to keep the site secure and functional. Analytics and third-party tags run only with your consent. See our Cookie Policy.

We use essential cookies to keep the site secure and functional. Analytics and third-party tags run only with your consent. See our Cookie Policy.