Skip to content

feat(cdp): put the run id on every email engagement event - #123804

Closed
Silthus wants to merge 2 commits into
PostHog:masterfrom
Silthus:feat/email-engagement-run-id
Closed

Silthus wants to merge 2 commits into
PostHog:masterfrom
Silthus:feat/email-engagement-run-id

Conversation

@Silthus

@Silthus Silthus commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Problem

  • A team can't join an email's sent, opened and clicked events to one send. The events name the workflow and the email step, but not the run.
  • A send from code returns a message_id, and no engagement event carries it.
  • So "which page did this recipient open after clicking", or a funnel per send, needs a guess by person and time.

Warning

🟡 Merge risk: medium · one-way door: events captured before a revert keep the property (merge-risk rubric)

  • The change adds one property to engagement events on the CDP email path. The worst case is a wrong run id on a property no query reads yet. It reaches the teams with engagement capture on.
  • Delivery code doesn't change: the property comes from an id the send already holds, after the send. No stored, queued or signed format changes, so old and new pods can run side by side.

Changes

  • Each email event of a send now carries $workflow_run_id: sent and failed at send time, plus opened, clicked, bounced and the rest from tracking.
  • $workflows_email_unsubscribed and $workflows_email_tracking_consent_updated don't carry it. The preferences page emits them, and its token holds only the team and the recipient.
  • $workflow_run_id is the name $workflows_conversion already uses, so a query joins a run's sends, engagement and conversions on one key.
  • A send from code already returns its run ID as message_id, so code senders can join on it too.
  • A run with two email steps shares one run ID. $workflow_action_id tells them apart.
  • Nothing else changes. Only the events of teams with engagement capture on get the new property.

How did you test this code?

Test rationale: two assertions, one per place that builds these events.

  • email.service.test.ts: the existing $workflows_email_sent capture test now also checks $workflow_run_id.
  • email-tracking.service.test.ts: a new test clicks a signed link and checks the captured $workflows_email_link_clicked event. No existing test checked the properties of a tracked engagement event.
  • Both assertions failed before the change and pass after it, run locally against the dev Postgres.
  • Live run on a local dev stack: two workflows (one created before the stack restart, one after) sent emails to maildev. A curl click on the tracked link and a pixel load followed. In ClickHouse, sent, opened and link_clicked each carried $workflow_run_id equal to the run id from the CDP log.
  • Not run: a real SES send. The SES webhook path reads the same invocationId from the signed header and builds the event in the same trackMetric call.

Release status

  • No feature flag controls this change

Docs update

The engagement events docs can list $workflow_run_id once this ships. That follows with the link tagging change, which builds on it.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: Claude Code, Claude Opus 5.5

  • Michael asked for the missing link in email tracking data: primitives that others query, with no UI. This is the first piece. A second PR tags tracked links with the run ID, so the landing page view joins to its session replay.
  • $workflow_run_id was chosen over $message_id because a workflow run can send more than one email.
  • Skills: /writing-tests, /writing-pr-descriptions, merge-risk.
  • A cross-model review panel found no code defects. Its description findings are fixed above, and a test spy now gets restored.
  • No duplicate: gh pr list --search "workflow_run_id email" found no open PR.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@trunk-io

trunk-io Bot commented Oct 27, 2026

Copy link
Copy Markdown

Merging to master in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Silthus

Silthus commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #123902, which puts the same run id on more email events.

@Silthus Silthus closed this Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant