Customer journeys

A journey is the set of sessions 3x attributes to one person: the first ad click three weeks ago, a direct visit last week, the quiz on the phone today. Sessions stay cookieless sessions; a journey only links them. Linking goes exactly as far as the legal basis allows.

How sessions are linked

Every link has a reason. Two sessions that share a key (the same visitor id, click id, hashed identity …) belong to the same journey; journeys merge when a later key connects them.

ReasonKeyNeeds consentConfidence
manuala link you set in the dashboard, the API or MCP (for example a WhatsApp lead confirmed to a session)–1.0
consent_vidthe first-party visitor id x3_vid, or the consented ad cookies _fbp / _ttpyes0.95
identitythe same hashed e-mail, phone or external id from a lead (identify(), leads.create) – also across devicesno (your form's legal basis)0.95
click_idthe same ad click id (gclid, gbraid, wbraid, fbclid, li_fat_id, ttclid, msclkid) arriving in the URL of several sessions, or persisted after consent (x3_clk)no (URL parameter)0.9
daily_hashthe same daily visitor hash – same day only, its salt is deleted every nightno0.6
consent_vid (key kind install)the install id of an app (app tracking): every session of one app install, sent only with the app's analytics purpose grantedyes (the app's consent mode)0.95

Without consent nothing is stored on the device, so a visitor who returns next week without a click id, without consent and without filling in a form starts a new journey. 3x never uses fingerprinting and never matches IP address or user agent across days.

A key shared by too many sessions is ignored, because it no longer identifies one person: a click id pasted into a shared link, an office NAT where many colleagues use the same browser build, a test e-mail address used by a whole team.

KeyIgnored above
click ids (gclid, fbclid, …)20 sessions
li_fat_id50 sessions
daily visitor hash8 sessions
hashed e-mail, phone, external id500 sessions
x3_vid, _fbp, _ttp, app install id2 000 sessions

A journey stops growing at 500 sessions.

Retroactive merging

Links work in both directions: when a person fills in a form in their fifth session, the identity key links that session to the lead's sessions on other devices, and every session already linked to either side joins the same journey. Linking runs right after ingest, after leads.create, and as a background job (journeys.link) that catches up on everything else; the Imported history is backfilled into journeys from click ids and leads.

  • Link: POST /v1/projects/{project}/journeys/link with {sessionId, targetSessionId} or {sessionId, journeyId} (scope leads:write), the dashboard's journey page, or the MCP tool journeys_link.
  • Unlink: POST /v1/projects/{project}/journeys/unlink with {sessionId} detaches a session into its own journey; automatic keys no longer pull it back (only a new manual link does).

Retention and erasure

  • Sessions deleted by the project's retention drop their links with them; a journey whose sessions are all gone is removed by the maintenance job.
  • Erasing a lead (DELETE /v1/projects/{project}/leads/{id}) removes the identity links it contributed; the journey is split again where nothing else connects its parts.
  • Keys are stored as keyed HMACs, never as raw values – except click ids (stored on sessions anyway) and the consented _fbp/_ttp values used for conversion uploads, which are cleared after 90 days.

Visits of a lead

The lead profile's Sitzungen, the API GET /v1/projects/{project}/leads/{id}/sessions and MCP leads_sessions list every visit of a lead – before and after the inquiry – with the evidence that links it. There is no second link table: the visits of a lead are its anchors plus every session of their journeys.

EvidenceMeaningWithout consent?
form_submitthe lead's own visit (form, quiz, x3.lead(), identify() in that visit)yes – the visitor sent the form
wa_refthe WhatsApp reference code of the visit led to the leadyes – the visitor sent the code
conversiona conversion of the lead was recorded in this visityes
sdk_identifythe website called x3.identify({ leadId }) in this visit with the lead's external id, X3 id or CRM record idper the project's identify consent rule
identitythe same hashed e-mail, phone or external id in another inquiryyes
manuala person assigned the visit (dashboard „Einem Lead zuordnen“, REST, MCP) – user and time are stored, audit log lead.session.linkyes – your knowledge
visitor_idthe same consented visitor id x3_vid (or _fbp/_ttp) as a linked visit – earlier and later visits of that browserno: consent only
click_idthe same ad click id as a linked visityes (URL parameter)
same_daythe same daily visitor hash as a linked visit – same day onlyyes, same day only

What X3 does without consent: nothing is written to or read from the visitor's device beyond what the cookieless measurement reads (§ 25 TDDDG). A returning visitor without consent is recognized only through deterministic, user-initiated facts – a form or quiz they send, a WhatsApp code, a click id in the ad link, your website reporting a known lead, a manual assignment – or on the same day through the daily hash, whose salt is deleted every night. Never through fingerprinting, never by IP or browser across days. „Kam X-mal wieder“ and the leads list's „Besuche“ therefore count only those visits for visitors without consent; Pulse's „Wiederkehrende Besucher“ counts consenting visitors only.

  • Merged leads (a duplicate merged into its original) add their visits to the original (viaLead names the duplicate).
  • Zuordnung lösen (POST …/leads/{id}/sessions/unlink) deletes this lead's manual and identify({ leadId }) links of the visit and detaches it from the journey, so automatic links stop applying to it; the inquiry visit itself cannot be removed. A new manual assignment brings it back.
  • Erasure: erasing the lead removes its manual and identity links (and the journeys they held together split again); retention deletes visits after the project's retention days – the lead stays, its visit list gets shorter.
  • Sessions list: the column Lead and the filter f.lead=eq:true („Nur mit Lead“) show visits that belong to a lead; the leads list's Besuche counts every visit of the lead.

Visitor id lifetime

x3_vid lives 13 months (395 days) by default and at most, renewed on every visit with consent – the period European data-protection authorities commonly accept for consented analytics cookies. A project may shorten it with tracking.journeys.visitorIdDays (1–395, PATCH /v1/projects/{project}/tracking-config), and it is never longer than the project's retention: a cookie that outlives the data would only re-identify visitors whose earlier visits are already deleted. The SDK uses the lifetime for the JavaScript cookie and sends it to the first-party proxy (POST /v1/id with days), which sets the HttpOnly cookie with it. Name the lifetime in your privacy notice (see Privacy).

Attribution models

Session reports keep their meaning: model **session** (the default) credits a conversion to the session it happened in. Journey models spread one conversion over the journey's sessions that started before it (plus 5 minutes of clock skew) within a 90-day lookback:

ModelCredit
sessionthe converting session gets 100 % (today's reports)
first_touchthe journey's first session in the window gets 100 %
last_touchthe last session before the conversion gets 100 %
linearequal shares for every session
position40 % first, 40 % last, 20 % split across the sessions in between (one session: 100 %, two: 50/50)
time_decayweight halves every 7 days before the conversion: 2^(−Δt / 7 d), normalised

Pass model to GET /v1/projects/{project}/ads/report and GET /v1/projects/{project}/analytics/breakdown (MCP: ads_performance, analytics_breakdown) or use the model switcher in the dashboard's Campaigns and Ads views.

  • In the ads report, conversions, leads and conversion value become fractional credits under a journey model, and CPL, cost per conversion and ROAS follow the chosen model. Sessions, relevant sessions, cost per session and cost per relevant session stay session-level – they describe traffic, not outcomes.
  • In a breakdown, every row keeps its session KPIs and gains attributed: {conversions, leads, value} for the chosen model.
  • Credit that lands on a session without an ad (direct, organic) is not shown in ad rows, so ad totals under journey models can be lower than under session.

Journey coverage

GET /v1/projects/{project}/analytics/journeys (MCP journeys_coverage) reports for the filter: journeys, multi-session journeys, coverage = share of converting sessions whose journey has more than one session (and the same for leads), average sessions to convert, median days to convert, and linked sessions per reason. Low coverage on a site with long sales cycles usually means few visitors consent and few click ids or forms connect their visits.

API

EndpointScopePurpose
GET /v1/projects/{project}/journeysanalytics:readJourneys with a session in the range (min_sessions, converted, cursor pagination)
GET /v1/projects/{project}/journeys/{id}?by=journey|session|leadanalytics:read (by=lead: leads:read)One journey: sessions with source, ad, device, key events and link reason; conversions with the credit of every model and the match quality per destination; leads only with leads:read
POST /v1/projects/{project}/journeys/linkleads:writeManual link
POST /v1/projects/{project}/journeys/unlinkleads:writeDetach a session
GET /v1/projects/{project}/leads/{id}/sessionsanalytics:read + leads:summaryEvery visit of a lead with its evidence (visits of a lead)
POST /v1/projects/{project}/leads/{id}/sessions · …/sessions/unlinkleads:writeAssign a visit to a lead / remove it
GET /v1/projects/{project}/sessions/{sessionId}/lead-candidatesanalytics:read + leads:readLeads of a visit and suggestions to assign it
GET /v1/projects/{project}/analytics/journeysanalytics:readJourney coverage

A journey that was merged into another one still resolves: the response carries the surviving journey with requestedId set to the id you asked for.

What the SDK stores after consent (x3_vid, x3_clk, _fbp, _fbc, _ttp) and how it is deleted again is described in Consent and CMPs; the legal reasoning in Legal basis.