← All docs

Data model

Visitors, users, actors, sessions, conversions, and the full list of columns stored on every event.

This page defines every term LaunchPulse uses and lists every column on an event. If a number somewhere in the app doesn’t match your intuition, the definition is probably here.

Core concepts

ConceptDefinition
Visitorvisitor_id, from the _lp_vid cookie. Anonymous, one per browser/device, 30-day lifetime
Useruser_id, set by identify() with your internal id. The $identify event itself is stored, so journeys stay reconstructable
Actoruser_id when set, otherwise visitor_id. The unit for conversion, activation, alert visitor counts, and “people” counts
Sessionsession_id, rotated after 30 minutes of inactivity and by reset()
ConversionA read-time definition: an event name (aliases included) OR a $pageview whose path starts with your configured path. An actor converts at their first matching event
First value / activationAn actor is activated when they hit the first-value event at or after their conversion time
Time to valueMedian seconds between conversion and first value, across activated actors
AttributionFirst-touch by default. Sources group by first_source, frozen for the visitor’s 30-day lifetime

Visitor vs. actor — the one that trips people up

The dashboard’s “Visitors” counts distinct visitor ids. But converters and activated count distinct actors.

That difference is deliberate. A visitor id is per browser, so the same person on their laptop and their phone is two visitors. Once they log in and you call identify(), both collapse into one actor. Counting conversions by actor means a person who signs up on mobile and activates on desktop is one converter, not two.

Practical consequence: a conversion rate is not a clean division of two numbers on the same screen. It’s converting actors over the relevant visitor population, and if a lot of your people use multiple devices, actor counts will be lower than visitor counts by design.

Activation is a share of converters

Activation rate is activated ÷ converters, not activated ÷ visitors. Someone who never converted can’t activate, so they aren’t in the denominator.

And activation requires the first-value event at or after the conversion timestamp. If your app fires first value before conversion, that actor never counts as activated. The onboarding test view warns about exactly this inversion — see Going live.

Full detail in Conversions and activation.

Attribution

Attribution is first-touch by default: a visitor’s source is whatever brought them in the first time, frozen for the 30-day cookie lifetime. That’s first_source, first_campaign, first_landing_page, and it’s what the Sources report groups by.

Session-level fields (session_source, session_medium, session_campaign, session_landing_page) are also recorded, so you can break insights down by the source of a specific session rather than the visitor’s original one. See Sources.

Two behaviors that surprise people

1. Configuration is retroactive

Your conversion event, your first-value event, and your aliases are never written into stored events. They’re applied when a query runs.

That means changing any of them reinterprets your entire history instantly. No re-install, no re-tagging, no data migration, no waiting for new data to accumulate. Rename your conversion event and last quarter’s conversion numbers are recomputed on the next page load.

This is why aliases fix typos retroactively, and why it’s safe to change your mind about what counts as activation a month in. See Event aliases.

2. Empty columns disappear

The analytics store drops columns that are entirely empty for a project. If you’ve never sent a value for something, the column doesn’t exist for you.

Three consequences you’ll actually run into:

  • Revenue reads 0 if you’ve never sent revenue. Not an error — the column isn’t there. See Revenue tracking.
  • An insight broken down by a dimension you never send renders as an empty card. Break down by UTM campaign on a site that has never received a UTM tag and there’s nothing to show.
  • The events detail view shows a different column set per project. Two projects, two column lists.

Event columns

Every column you’ll see in the events detail view and in the CSV export.

ColumnMeaning
timeThe event timestamp
received_atAuthoritative server receive time. Drives partitioning
client_timeWhat the browser reported, clamped to [received − 5 min, received]
event_idUnique id for the event
project_idThe project the event belongs to
event_nameThe event name, e.g. $pageview, signup
visitor_idAnonymous per-browser id from _lp_vid
session_idSession id, rotated after 30 min idle or on reset()
user_idYour internal id, set by identify()
ingest_sourcebrowser or server
hostnameHost the event came from
pathPage path
urlFull page URL
referrerReferring URL
utm_sourceutm_source from the URL
utm_mediumutm_medium from the URL
utm_campaignutm_campaign from the URL
utm_contentutm_content from the URL
utm_termutm_term from the URL
sourceDerived source for this event
mediumDerived medium for this event
campaignDerived campaign for this event
session_sourceSource attributed to the session
session_mediumMedium attributed to the session
session_campaignCampaign attributed to the session
session_landing_pageFirst page of the session
first_sourceFirst-touch source, frozen for the visitor’s lifetime
first_campaignFirst-touch campaign
first_landing_pageFirst page the visitor ever landed on
countryISO-3166 alpha-2 country code
deviceDevice type
browserBrowser
osOperating system
revenue_microsRevenue × 1,000,000, as an integer
currencyCurrency of the revenue value
propertiesYour custom properties

Notes on the ones that aren’t self-explanatory:

  • received_at is the authority. It’s when the collector actually got the event, and it’s what partitioning is based on. client_time is a claim made by the browser, so it’s clamped to the window [received − 5 minutes, received] — a device with a wildly wrong clock can’t push events into the future or far into the past.
  • revenue_micros is an integer, not a float. $19.99 is 19990000. Integer math avoids floating-point drift when summing revenue.
  • properties holds whatever you send. Keep personal data out of it — see Privacy.

Project statuses

StatusBehavior
setupOnboarding. Events go to the debug stream only and are never stored
activeEvents are persisted
pausedEvents are accepted and dropped
Soft-deletedProject disappears from the app; analytics data is retained

Range semantics

How each range in the app is built:

RangeWindowBuckets
todaySince UTC midnightHour
7d / 30d / 90dRolling N × 24 hoursDay
12moFrom the 1st of the month, 11 months backMonth
CustomSnaps to UTC days, capped at 12 monthsDay

The Local/UTC toggle affects display only. Bucketing is always computed in UTC. Switching to Local relabels the axis; it does not recompute which events fall into which bucket. On a non-UTC timezone this makes labels look offset relative to bucket boundaries — that’s expected, not a bug.

What’s next

NextTroubleshooting

Talk to us

Questions about LaunchPulse, or want a walkthrough? Send a note and a real person replies.

Or email us at hello@launchpulse.dev