Event Tracking โ
Reference documentation for Lantern's analytics event system.
How Event Tracking Works โ
Lantern's analytics pipeline flows from client-side capture through server-side validation to storage and reporting.
Event Flow โ
Flash SDK (browser)
โ Validate client-side (@lantern/shared/analytics)
โ Analytics Cloud Run (POST /analytics/track)
โ Forge SDK (destination: realtime)
โ Firestore (real-time) + BigQuery (analytics)
โ Scheduled SQL aggregation (daily, 2 AM UTC)
โ Aggregated BigQuery tables
Forge SDK (backend services)
โ Validate + sanitize
โ BigQuery (default) โ venues-api, cloud functions, etc.
โ Firestore + BigQuery (realtime option)- Capture โ The
FlashSDK in the web app captures user interactions and emits structured events viaflash.track(). Auto events fire automatically on lifecycle hooks (session start, hash-route navigation). - Validate (client) โ Flash validates the event name and payload against the shared taxonomy before sending. Invalid events are rejected immediately and logged as warnings in development.
- Ingest โ Valid events are sent to the Analytics API, which attaches server-side metadata (timestamp, environment, user context) and runs a second validation pass.
- Store โ Events are written to Firestore (real-time presence) and BigQuery (
analytics_eventstable). - Aggregate โ A scheduled SQL job runs nightly to roll up raw events into pre-aggregated tables for fast dashboard reads.
Where Events Are Used โ
- Admin dashboards โ Active user counts, engagement funnels, feature adoption rates
- Merchant reporting โ Offer impressions, claim rates, and redemption rates per venue
- Platform health โ Session duration, page views, and drop-off analysis
- Debugging โ Real-time event stream via the Debug View
Single Source of Truth โ
๐ฆ @lantern/shared/analytics
All event definitions โ including the auto and registered event rules โ live in @lantern/shared/analytics. Both the Flash client SDK and the Analytics API server consume from the same shared package. Changes to the taxonomy automatically reflect in the admin Event Taxonomy page.
For the full API specification including request/response schemas, authentication, and rate limits, see the Analytics API Reference page in the admin portal.
Event Model โ
Lantern uses a two-tier event model for all analytics tracking. Every event falls into one of two tiers based on how it fires.
Auto Events โ
- Auto events are collected automatically by the Flash SDK โ no manual calls needed. They fire on lifecycle hooks like session start and hash-route navigation, and are always active regardless of what other events you track.
Registered Events โ
- Registered events cover all developer-instrumented tracking โ from core Lantern interactions (lighting lanterns, sending waves, viewing offers) to feature experiments and ad-hoc instrumentation.
- Built-in registered events have known schemas and semantics, powering first-class dashboard widgets and cross-feature aggregation.
- Dynamically registered events can be added at runtime (via admin UI or code) without updating the shared package โ they're validated by naming convention.
The full list of registered events โ with parameters, triggers, and usage examples โ is in the Event Taxonomy.
Naming Rules for Dynamic Events โ
| Rule | Value | Description |
|---|---|---|
| Pattern | [a-z][a-z0-9_]* | Snake_case, starting with a lowercase letter |
| Max Length | 64 chars | Maximum total event name length |
Examples: onboarding_step ยท ab_variant_seen ยท share_method
import { flash } from '@/lib/flash'
flash.track('onboarding_step', {
entityId: 'step_3',
entityType: 'feature',
metadata: { step_name: 'profile_photo' },
})Event Creation Process โ
There are two ways to add a new event to Lantern's analytics taxonomy.
Path 1: Admin Form โ GitHub โ Shared Package (recommended) โ
Use this path when proposing a new event through the admin portal. The form captures all metadata up front and creates a trackable implementation ticket.
- Define โ Fill out the Event Creator form in the admin portal (name, category, description, trigger, parameters).
- Save โ The event definition is saved to Firestore with status pending.
- Submit โ Click "Submit to GitHub" to create an implementation issue. Status moves to submitted.
- Assign โ A developer is assigned to the issue. Status moves to in_progress.
- Install โ The developer adds the
defineEvent()call topackages/shared/analytics/index.jsand opens a PR. Status moves to installed. - Activate โ Once merged and verified in production, the event is promoted to active.
Form (admin portal)
โ Firestore (pending)
โ GitHub issue (submitted)
โ Developer assigned (in_progress)
โ PR to @lantern/shared/analytics (installed)
โ Verified in production (active)Path 2: Direct Code Addition โ
Developers can add events directly to packages/shared/analytics/index.js via a PR โ bypassing the admin form. This is appropriate when the developer already knows the full event schema and doesn't need the intake workflow.
- Add a
defineEvent()call inpackages/shared/analytics/index.js. - Open a PR targeting
dev. - Once merged, the event appears automatically in the admin Event Taxonomy page.
Status Lifecycle โ
| Status | Meaning |
|---|---|
| pending | Saved in admin form, not yet submitted to GitHub |
| submitted | GitHub issue created |
| in_progress | Developer assigned and working |
| installed | Code merged, awaiting production verification |
| active | Verified and tracking in production |
| cancelled | Implementation cancelled before completion |
| archived | Retired from active use |
SDK Integration โ
How to track events from the Lantern web app.
Basic Usage (Flash โ client-side) โ
import { flash } from '@/lib/flash'
// Track a registered event
flash.track('lantern_lit', {
entityId: '<venue_id>',
entityType: 'venue',
})
// Track a dynamically registered event
flash.track('filter_applied', {
entityId: '<feature_name>',
entityType: 'feature',
})Backend Usage (Forge โ server-side) โ
import { forge } from '@lantern/forge'
// System/service event โ BigQuery only (default)
await forge.track({
serviceId: 'venues-api',
eventName: 'venue_searched',
metadata: { result_count: 12 },
})Event Validation โ
Events are validated both client-side (Flash SDK) and server-side (analytics API). Invalid event names are rejected before reaching BigQuery.
import { validateEventName } from '@lantern/shared/analytics'
const result = validateEventName('my_custom_event')
// { valid: true, tier: 'registered' }
const bad = validateEventName('UPPER_CASE')
// { valid: false, tier: 'registered', error: '...' }