Intro1 / 12

State of the conversion tracking

Today I’m going to talk about the state of all the conversion tracking.

Will discuss what we have in place, how we got here, and what the goal is going forward. With the CDP.

How we got here

  • Cursor Pre Merge
  • Cursor Merges, Grok Bot Launches
  • New challenge discovered

CDP

  • Goal
  • Why CDP
  • How

Current state

  • Product surface CDP implementation, what each surface tracks
  • Implementation tracker
  • The gap: signups, progress over time
  • Current attribution: how we measure today, and the role of Conceptual

Going forward

  • Click-based attribution: how we build it
How we got here2 / 12

Cursor Pre Merge

I joined right around the time the merge happened and when we launched Grok Bot.

Up until that point this is what was in place:

GTM + Server Side GTM Tracking responsible for

  • Loading Pixels (the base page view ones) across the networks we were running ads on (TikTok, Google, Facebook, LinkedIn, Reddit, Snapchat)
  • Instrumenting GA4

Allan’s PLTV Models

  • One row per converting entity (an individual subscriber, a team, or a sales lead), fired once, on the entity’s first paid, non-refunded, non-trial charge — a Stripe paid invoice, or an Apple/Google (and for X Subs, PayPal/X Money) first paid day — across Cursor, Grok, and X Subs.
  • The value is the predicted 3-year revenue for that entity from its cohort’s retention curve, net of store/payment fees on self-serve rows.
  • Leads carry a sales expected-contract value extended to 3 years by renewal rate. Each entity is frozen on first materialization and never re-sent, restated, or re-valued.

Conceptual external vendor

We sent our subscriptions through Hightouch to Conceptual’s platform, and Conceptual dispatches those with their enrichment process to the ad networks, and in the ad networks we optimize for those.

Hightouch

The sole focus was around web and so all the above is strictly talking about the web context.

The main event that we were/still today are optimizing for is PLTV for subscriptions.

Notes

How we got here3 / 12

Cursor Merges, Grok Bot Launches

My understanding is that with the merge we basically took over paid media across the board, and we went all in on Grok Bot.

Set up on the “xAI side”

  • Grok.com (no GA4)
  • X.ai (no GA4)
  • Both of these had Mixpanel in place we learned later
  • And they did have MMP correctly set up for Grok mobile app managed by external agency Twigeo.

For Web the following was changed

  • Switched ad accounts for certain platforms, made changes in Hightouch accordingly
  • We included the Grok subscriptions in PLTV (Allan’s work)
  • Continued to optimize for those events

Mobile

  • We instrumented MMP AppsFlyer across both mobile apps
  • Sent the following conversions to AppsFlyer
  • Exported AppsFlyer device data into Databricks
  • Set up a dedicated sync from Hightouch back into AppsFlyer for PLTV events specifically with the necessary AppsFlyer device information
  • Set up PLTV tracking to ad networks from the MMP so those can be used for mobile optimization campaigns.

Conversions sent to AppsFlyer

Grok app (iOS, Android)
af_complete_registration af_login af_initiated_checkout af_start_trial af_subscribe / af_purchase sent_3_chat_messages sent_5_chat_messages rate_limit_hit
Grok Bot app (iOS, Android)
af_complete_registration af_login af_initiated_checkout af_start_trial af_subscribe af_purchase af_grok_linked onboarding_completed bot_created first_agent_response integration_added usage_limit_hit
From Hightouch, S2S
plg_<tier>_pltv_36m per Cursor, Grok and X Subs tier, slg_contract_value_36m_lead; af_revenue = the PLTV value, keyed on appsflyer_id

Conceptual

  • We decided to move away from Conceptual’s tracking to own our own infrastructure and not rely on third party for something this critical
  • So we replaced the dispatches to Conceptual and used our own internal enrichment relying on GA4 on the cursor subscriptions
  • Having suboptimal enrichment
How we got here4 / 12

New challenge discovered

We send traffic to X.ai

For mobile

We send subscriptions back to AppsFlyer, we let AppsFlyer figure out the matching and match parameters.

For web

Still sending PLTV, however enrichment parameters are suboptimal, because we capture all of the attribution parameters we need inside of x.ai and we currently don’t have a way to stitch this back to the PLTV user that signs up.

Thought long and hard of doing hacky workarounds to accomplish this.

Now:

And this is where we decided to prioritize the CDP as this would solve for these things at once and give a more scalable approach going forward.
CDP5 / 12

Goal

Zooming out a little bit, our goal that I believe everybody is aligned on is:

  • Optimize marketing campaigns for actions that take place across all platforms
    • Track events
      • Track those in platform as is (front or backend)
      • Track ‘special’ events. Events that exist in Databricks or an external source and need enriching. Example Subscription PLTV (Stripe + app merchant data enriched by Allan’s PLTV models)
    • Enrich those events with match parameters needed by ad networks (Crucial !!)
    • Attach consent status towards each of the events
  • Click-through based attribution models which means:
    • Marketing touchpoints (visits) with utm/referrer info attached to single user profiles
    • Every single event we want to track attached to single user profiles
    • Distribute those touchpoints across the event or action we care about
    • Weight channels and analyze performance
    • Possibly assign the events we are looking at back to click dates for paid media, attach spend impressions clicks to that so we have our own built
  • Lifecycle marketing for events
  • Enrich CRM with attribution data
  • Standardization
    • Have all of the above fully standardized so that in the future if there is need for optimizing towards a new event or having attribution for a new event the only bottleneck should be engineering to implement it correctly in the source. Once that’s done if this system is implemented properly those requests should and will be turned around very quickly.
Every single conversion event
source event+identity resolution+match parameters+a Hightouch sync
Every attribution model for event
what’s listed above
Every audience
a new model+enrichment+Hightouch sync
CDP6 / 12

Why CDP

Source tracking

Centralize and enforce a clear taxonomy on how events get instrumented across all product surfaces

Enrichment

Centralize and enforce how enrichment models get built both for attribution and conversion tracking

Destination delivery

Send to the destinations either in real time or through reverse ETL

CDP7 / 12

How

The whole point is:
  1. one single user who lands on x.ai with utm’s must be recognized as the same user by the time he signs up for an account wherever he does this.
  2. that same user if he starts using different products must also be able to be recognized as such.
  3. Cross device once a user creates an account is easy. That user will sign up with their user_id

Many touchpoints, one user, one value sent back to the ad networks

Cross device: web to app

Current state8 / 12

Product Surface CDP implementation

The seven surfaces that are instrumented today, grouped by where the Hightouch call is made. Click a surface to see what we track there, whether each event is actually landing, and what travels with every event.

Event names and context from each surface’s spec in the Hightouch Implementation Tracker. Landing status is what Hightouch delivered to Databricks, Oct 7 to Oct 14 UTC: green is landing as of Oct 14 with the week’s volume, amber is seen this week but stopped, gray is nothing landed yet.
Current state9 / 12

Implementation tracker

From the Hightouch Implementation Tracker in Notion. Spec is whether engineering has a written spec; Status is the build.

7
surfaces spec’d and in QA: Grok web, backend, mobile
1
in progress: cursor.com
1
live in production: xAI subscription egress (since Sep 30)
8
V2 / not started
PlatformProductTypeSpecStatusDRI
x.ai (cross domain)GrokwebDoneQAJordi Villa & Pedro Ribeiro
grok.comGrokwebDoneQAJordi Villa & Pedro Ribeiro
console.x.aiGrokwebDoneQAJordi & Adam
X AI Backend (Auth)GrokbackendDoneQALouis Gouirand
X AI Subscription ConsolidatedGrokbackendDoneQA live in prodSanjib Prabhunandan
Grok iOS & Android (native)GrokmobileDoneQAAdam Śliwakowski
Grok Bot iOS & Android (RN)GrokmobileDoneQAAdam Śliwakowski
cursor.comCursorwebDoneIn progressAdeola & Matthew
Source: Hightouch Sources table in Notion, as of Oct 13. Eight more surfaces (Cursor web app, Cursor auth, Cursor desktop and mobile, Bug Bot, Grok Bot and Grok Build desktop, Grok Build CLI) are V2 and not shown.
Current state10 / 12

The gap: signups

Backend Signed Up (xAI auth service → Hightouch) against Mixpanel’s signup event, distinct users per UTC day, since the backend source went live. Captured means the Mixpanel signup’s user id also has a Signed Up event; every number on this page uses that definition.

Capture rate, headline numbers

22.1%
captured on Oct 1, first full day
31.2%
Oct 7, after the OneTrust change
28.3%
Oct 13, latest full day
52.4%
after the Oct 14 14:00 UTC Signed Up fix (15:00 to 20:00 UTC, the last hours Hightouch had loaded)

Signups per day, thousands of distinct users

Mixpanel signupsof which captured by Hightouch backend Signed Up
X: UTC day. Oct 14 is split at the 14:00 UTC Signed Up fix: before is 00:00 to 15:00 (includes the hour the fix landed in), after is 15:00 to 20:00, the last hour Hightouch had loaded. Y: distinct users, thousands.

Signed Up as % of Mixpanel signups

Signed Up / Mixpanel signups
X: October day, UTC. The last two points are Oct 14 before the fix (to 15:00, 27.6%) and after it (15:00 to 20:00, 52.4%). Y: share of Mixpanel signups that also produced a backend Signed Up event.

Oct 7

OneTrust change: opt-out regions load the SDK and fire on first paint. Capture moves from ~21% to ~31%.

Oct 12 to 13

Mixpanel consent-gated. Mixpanel’s own count drops from 166 k to 91 k and Signed Up drops with it. The ratio slips from 31% to 28%; the absolute capture halves.

Oct 14, 14:00 UTC

Signed Up fix on the web path. Capture goes from ~25% to ~50% within the hour, with no change in Mixpanel volume.

Where the rest is

  • accounts.x.ai has no browser source, so a signup that never had an x.ai or grok.com cookie carries no anonymous_id
  • App sign-in sheets are not stitched yet
  • Cursor side: cursor.com SDK in progress; Cursor auth Signed Up is V2

Where every Mixpanel signup went after the Signed Up fix

Oct 14, 15:00 to 20:00 UTC. Every Mixpanel signup is sorted by where it came from, then checked for a Signed Up event. The first bar is everything that has one, from any origin. Each bar below is one origin’s misses, so the bars add up to 100%. Hover or tap a segment for the sub-bucket.

17,434
Mixpanel signups
8,688
also have a Hightouch Signed Up event
49.8%
captured
8,746
missed
Origin uses the first account page view’s referrer within 2 days before signup. Country and bot flag come from the auth DB. “Identified” means the user appears in Hightouch web identify. Queried Oct 14 20:10 UTC.

Signups per source, after the fix

Oct 14 15:00 to 20:00 UTC, the same window as the waterfall above. Distinct users per source. Accounts created is the auth DB; Mixpanel is the web account flow; each Hightouch source is its own registration event.

Accounts created (auth DB)MixpanelHightouch Signed Up (web)Grok iOSGrok AndroidGrok Bot iOSGrok Bot Android
Hatched part of a bar is accounts migrated from X: 65 k of the 158 k accounts created, 8.9 k of the 25.8 k Grok iOS registrations. They have no web signup, so the gap report excludes them from both sides.

Read across the sources

Accounts created, excluding X migrations92,270
All Hightouch sources, deduplicated, excluding X migrations55,721
Hightouch share of accounts created60.4%
Mixpanel (web account flow)19,927
Hightouch Signed Up, also in Mixpanel10,451
Web capture, Signed Up / Mixpanel52.4%
Bot-flagged accounts in the window2,097
Grok Android went live Oct 13 20:38 UTC and is still ramping with the app version; AppsFlyer sees roughly 100 k Android registrations a day.
Current state11 / 12

Current attribution: how we measure today

Click-through based attribution: so technically we could stitch subscriptions through user_id

x.ai → grok.com

OK

x.ai / bot → mobile / desktop → web

Grok link checking: technically the sign up happens on accounts.x.ai which would survive the device cookie set by the grok bot visit. Just need to validate the accuracy of this implementation since we inherited this, but can definitely use this for historical analysis.

Sign ups with Cursor

No

cursor.com

Yes, GA4

What role Conceptual plays today

Going forward12 / 12

Click-based attribution: how we build it

A short POV on what and how we should build a click based attribution model to supplement our measurement. Three paths, built separately:

1. Web

Visits on x.ai, grok.com, cursor.com through to the web conversion.

2. Web → Mobile

Need to separate the two: a web visit that ends in an app install and an in-app conversion.

3. Ad network → Mobile directly

No web touch at all. The MMP owns this.

1 and 2

3. Ad network → Mobile

For 3 we use AppsFlyer, which unfortunately is only available in the aggregate (SSOT) for iOS; for Android we have it on the individual level. This is iOS restrictions that just prevent us from capturing it.

iOS

Aggregate only: AppsFlyer SSOT (SKAdNetwork + modelled). No user-level click → install → conversion path, so it joins the model at the aggregate level per campaign.

Android

User-level: appsflyer_id on the install and on every in-app conversion, so it joins identity resolution like any other touchpoint.