Ulsav Docs
Insights

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.

GroupTypes
Trafficevent.viewed, checkout.started, credential.viewed, credential.shared, outbound.clicked
Lifecycleregistration.created, registration.submitted, approval.decided, order.confirmed
Issuancecredential.issued
Admissioncheckin.recorded
Moneyrefund.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:

IdentifierLifetimeStorage
VisitorAcross visitsBrowser local storage
SessionOne browser sessionBrowser 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.

KeyUnitMeaning
event.viewscountEvent page views
event.visitorscountDistinct visitor identifiers
orders.confirmedcountConfirmed Orders
orders.freecountConfirmed Orders with a zero total
revenue.gross_minormoneyOrder grand totals
revenue.net_minormoneyGross minus platform fee and fee tax
aov_minormoneyGross divided by confirmed Orders
registrations.createdcountRegistrations created
participants.expectedcountActive Participants on confirmed Registrations
checkins.recordedcountCheckIns recorded
no_showscountExpected minus checked in
refunds.countcountRefunds 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.

Net revenue
net=gross−platform fee−tax on platform fee\text{net} = \text{gross} - \text{platform fee} - \text{tax on platform fee}

The fee tax is the tax charged on Ulsav's fee, not the tax on the ticket.

Average order value
AOV=grossconfirmed orders\text{AOV} = \frac{\text{gross}}{\text{confirmed orders}}

Rounded down to whole minor units. Zero confirmed Orders gives zero, not an error.

Conversion rate
conversion=confirmed ordersEvent page views\text{conversion} = \frac{\text{confirmed orders}}{\text{Event page views}}

Orders, not seats. One Order can hold several Registrations.

Capacity sold
capacity sold=confirmed registrations∑capacity of active published Passes\text{capacity sold} = \frac{\text{confirmed registrations}}{\sum \text{capacity of active published Passes}}

A Pass with no capacity is excluded from the denominator.

Turnout
turnout=distinct participants with a CheckInactive participants on confirmed registrations\text{turnout} = \frac{\text{distinct participants with a CheckIn}}{\text{active participants on confirmed registrations}}

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.

On this page