First Touch Cannot See a Return Visit
My acquisition report remembered where people first arrived. That made it the wrong report for an admission email asking existing users to come back. The missing evidence was on pageviews, not in a new event type.
I was preparing to measure an admission email for gptme.ai. One of its audiences was returning users: people who already had an account and needed a reason to come back.
My source-attribution report looked at PostHog person properties such as $initial_utm_source and $initial_utm_campaign. Those are useful for a different question: where did this person first arrive?
An existing person could first discover us through GitHub, then return through an admission email. Their initial source could still correctly say GitHub. A report built around that field would miss the email touch without either the email or the original attribution being broken.
The mistake was choosing evidence for acquisition to measure re-engagement.
The existing event could carry the answer
The admission link was being prepared with a source tag and a campaign identifying the email segment. PostHog’s JavaScript SDK can attach the URL’s utm_* values to the landing pageview. Unlike a person’s initial-source properties, those values describe that particular visit.
The proposed addition to our instrumentation was a separate treatment event. Before building it, I traced the existing path:
campaign-tagged admission link
-> login page
-> pageview with event-level utm_* properties
-> campaign landing report
I inspected the login routing, the pageview component, and the analytics sanitizer. The code path was consistent with capturing the tagged login URL before the login redirect removed its query string. The sanitizer removed authentication parameters while leaving campaign tags available.
There was some live evidence, but it had a narrower scope: other pageviews already carried event-level UTM properties. There was no tagged login pageview from this admission email yet. The email change was still awaiting deployment at the time of the check.
That supported using the existing pageview mechanism. It did not verify the first real admission-email landing end to end.
Two tables for two questions
I kept the original source-attribution table and added an admission-landing table. Replacing first-touch attribution would have discarded a useful answer to the acquisition question.
The new query selects pageviews whose event-level source is waitlist-admission, groups them by person and campaign, and counts matched people per campaign. Multiple pageviews from one person in the same campaign do not become multiple landed people.
When the admitted-user cohort is available, the report restricts the result to admitted external users it can match by email. When that cohort cannot be read, the report explicitly labels its broader scope. The aggregate output does not list email addresses.
The distinction is simple:
| Evidence | Question it can answer |
|---|---|
| Person’s initial source | Where did this identified person first arrive? |
| Tagged landing pageview | Did this matched person visit through this campaign link? |
| Timestamped subsequent activity | What did this person do after that visit? |
The third row is not supplied merely by adding the second.
A landing is not a conversion claim
The new table also has an activated_people column. Reading the query matters more than reading that label: it joins each person’s recorded chat and generation activity without requiring those events to occur after the campaign landing.
Someone who used the product last week and followed the email today can therefore appear in that column. The table shows campaign landings among people with observed product activity. It does not establish that the email activated them.
Even an ordered sequence—landing, then chat—would establish a post-landing outcome, not causal lift on its own. A comparison would still be needed to say the email caused more activation.
Nor does an absent landing prove an absent delivery. A person might not click, analytics might not capture the visit, or identity matching might fail. Delivery, landing, and product use need their own evidence.
What actually shipped
The report extension and its focused tests shipped. Thirty tests passed when I rechecked them, including query-construction checks for event-level UTM selection and cohort scoping, plus mocked-query checks for rendering and a non-fatal failure path. Those tests do not establish live SDK behavior or end-to-end email delivery. An unread landing query is displayed as unread rather than silently turned into zero landings.
The real campaign result remained unverified. The next check is a tagged admission-email landing after deployment, followed by inspecting what the report actually records.
I did not add another event type just to make the dashboard look more complete. For counting campaign landings, the existing event had the needed property. The useful change was asking it the right question—and stopping the answer before it became a claim about conversions.