Metrics
Facts, the two ways they arrive, and the exact definition behind every dashboard number
A Fact is one recorded observation: a page view, a checkout start, a credential view, an Order confirming. Metrics are the named calculations over Facts and the domain records. This page explains where the numbers come from, how duplicates are avoided, and the arithmetic behind the headline figures.
Fact store
Append-only
Never updated, only added
Scoped to
One Organization
No cross-tenant reads
Beacon types
Five
The public endpoint is an allowlist
Raw retention
180 days
Rollups survive longer
Dedupe
Per navigation or source event
Currency
Labelled INR
Mixed currencies are not separated
What a Fact records
A Fact carries the Organization, and any of the Event, Pass, Registration, Participant, Order, and Account it belongs to. It also carries the actor type, the fact type, the time, and attribution fields.
There are fifteen fact types.
| Group | Types |
|---|---|
| Traffic | event.viewed, checkout.started, credential.viewed, credential.shared, outbound.clicked |
| Lifecycle | registration.created, registration.submitted, approval.decided, order.confirmed |
| Issuance | credential.issued |
| Admission | checkin.recorded |
| Money | refund.succeeded, refund.failed, payout.settled, payout.failed |
Facts never hold names, emails, phone numbers, or raw IP addresses. They hold identifiers and attribution.
How facts arrive
There are two paths, and they have different jobs.
Lifecycle projection reads events the other modules already emit: an Order confirming, a Registration being created or submitted, an approval being decided, a credential being issued, a CheckIn being recorded, a refund or payout changing state. Each source event becomes at most one Fact.
The public beacon records traffic. Public Event surfaces send a page view, and the checkout and credential pages send their own observations. The endpoint is unauthenticated, rate-limited by the general API limiter, and restricted to the five traffic types. It cannot read or return Organization data.
Why a replay is safe
Every beacon observation carries a dedupe key. A navigation identifier is the strongest key, so a reload does not double-count. Without one, the session, the fact type, and the subject are combined.
Lifecycle projection dedupes by the source event identifier. Replaying an outbox delivery writes nothing twice.
What the beacon says about a visitor
Two anonymous identifiers are used:
| Identifier | Lifetime | Storage |
|---|---|---|
| Visitor | Across visits | Browser local storage |
| Session | One browser session | Browser session storage |
Neither is an Account. A signed-in Account can be attached to a Fact, but the visitor identifier is not an identity.
When Do Not Track is on, the beacon sends no visitor identifier. Only the session identifier is used, and no persistent visitor survives. That means a returning visitor cannot be recognized in that browser.
Source and medium come from UTM parameters first. Without them, the referrer host is classified as search, social, internal, or referral. No referrer becomes direct with medium none.
The metric catalogue
Twelve metric keys are defined and versioned. Keys are stable and never renamed.
| Key | Unit | Meaning |
|---|---|---|
| event.views | count | Event page views |
| event.visitors | count | Distinct visitor identifiers |
| orders.confirmed | count | Confirmed Orders |
| orders.free | count | Confirmed Orders with a zero total |
| revenue.gross_minor | money | Order grand totals |
| revenue.net_minor | money | Gross minus platform fee and fee tax |
| aov_minor | money | Gross divided by confirmed Orders |
| registrations.created | count | Registrations created |
| participants.expected | count | Active Participants on confirmed Registrations |
| checkins.recorded | count | CheckIns recorded |
| no_shows | count | Expected minus checked in |
| refunds.count | count | Refunds recorded |
The dashboard cards do not all read this table. Sales, registration, revenue, capacity, and turnout figures are SQL over the Orders, Registrations, and CheckIns tables, and the dashboard KPIs read the traffic Facts directly. The catalogue defines the vocabulary; it is not a single query engine.
The arithmetic
Gross revenue is the sum of confirmed Order grand totals.
The fee tax is the tax charged on Ulsav's fee, not the tax on the ticket.
Rounded down to whole minor units. Zero confirmed Orders gives zero, not an error.
Orders, not seats. One Order can hold several Registrations.
A Pass with no capacity is excluded from the denominator.
A person admitted at three sessions counts once.
Funnels are cohorts
The marketing funnel is viewed, registration started, checkout started, order confirmed. The attendance funnel is issued, viewed, checked in.
A later stage can never exceed an earlier one. Ulsav rises the earlier stage to match the later one, working backwards, because reaching a later stage proves the earlier one happened. It never lowers a later stage.
The two funnels use different units. Marketing counts visitors, registrations, and Orders. Attendance counts Participants.
Rollups and expiry
A daily rollup table stores metric values per scope and day. The worker rebuilds the last two days on its cycle. The rollup is a cache: the current read APIs compute from Facts and domain tables, so a missing rollup does not blank a dashboard.
Raw Facts expire after 180 days. Traffic older than that disappears from views and visitors. Order, registration, check-in, and payout figures come from the domain tables, so they remain.
Limits worth knowing
- Every money figure is labelled INR. Orders in other currencies are summed into the same number.
- Traffic is first-party only. No third-party pixel is rendered today, even when a pixel ID is stored.
- There is no per-Event uniques model beyond the visitor identifier.
- A beacon sent while offline is lost; it is fire-and-forget.
Related
- Insights — the dashboards these numbers feed
- Attribution — the source fields
- Reports — the same metrics as tables
- Check-in — where attendance comes from