The Core SaaS Event Model
Event tracking is the foundation of SaaS product analytics. Without a consistent, well-designed event model, every analysis question becomes a archaeology project: digging through inconsistent naming, missing properties, and events that were tracked for six months then changed and re-tracked differently. The cost of a bad event model is paid continuously — every time a data question cannot be answered cleanly, every time a dashboard is unreliable, every time a new analyst joins and cannot understand why the data looks the way it does.
This reference defines the canonical SaaS event model: the core event categories every SaaS should instrument, the naming conventions that keep the event taxonomy navigable at scale, and the property schemas that make events analytically useful across all categories.
🔑 The 6 Core Event Categories
A well-structured SaaS event model organizes all events into a small number of categories that correspond to distinct analytical use cases. The six categories below cover the full product lifecycle from user interaction to revenue.
| Category | What It Tracks | Primary Use Case |
|---|---|---|
| User Events | Individual user actions in the product | Activation, engagement, feature adoption |
| Account Events | Account-level lifecycle changes | Account health, expansion signals |
| Feature Events | Usage of specific product features | Feature adoption, product-led growth analysis |
| Billing Events | Subscription and payment state changes | Revenue analytics, churn signals |
| Error Events | Application errors and exceptions | Reliability, user experience degradation |
| Performance Events | Latency, throughput, system health | Operational monitoring, user impact |
These categories are not mutually exclusive — a single user action can trigger events in multiple categories. A user upgrading their plan generates a user event (upgrade action taken), an account event (account tier changed), and a billing event (subscription modified). Tracking these as separate events in their respective categories keeps each analytical question clean and avoids mixing concerns.
Event Naming Conventions
Consistent naming is what makes an event model navigable. Inconsistency accumulates quickly: one team names events user_signed_up, another uses UserSignedUp, another uses signup_completed. A few months in, you have four events that mean the same thing and no reliable way to query signup rates.
The Object-Action Pattern
The most widely adopted convention is the object-action pattern: [Object]_[Action] in snake_case. The object is the resource being acted on; the action is the past-tense verb describing what happened.
- →
user_signed_up— notsignup_completedornew_user_created - →
project_created— notcreate_projectornew_project - →
subscription_upgraded— notupgrade_completedorplan_changed_up - →
report_exported— notexport_reportordownload_initiated
Naming Rules
- → Always past tense for actions — events describe things that happened
- → snake_case throughout — no camelCase, no PascalCase, no spaces
- → Object first — this groups related events alphabetically in any tool
- → Be specific about the object —
dashboard_widget_addednotthing_added - → No abbreviations unless universal —
subscriptionnotsub,organizationnotorg
Event Name Registry
Maintain a central event registry — a document or database table — where every event name, its definition, who owns it, and when it was added is recorded. New events must be added to the registry before they are instrumented. This prevents duplicate events, enforces naming conventions, and gives analysts a source of truth.
Universal Property Schema
Every event in the model, regardless of category, should carry a set of universal properties. These are the context fields that make any event analytically useful: who did it, in what account, in what session, and when.
| Property | Type | Description |
|---|---|---|
| event_id | UUID | Unique identifier for this event instance |
| event_name | String | The event name from the registry |
| timestamp | ISO 8601 | Server-side timestamp of when the event occurred |
| user_id | String | Authenticated user ID, null for anonymous events |
| anonymous_id | String | Pre-authentication session identifier |
| account_id | String | The account/organization the user belongs to |
| session_id | String | Groups events within a single session |
| platform | Enum | web, mobile_ios, mobile_android, api |
| environment | Enum | production, staging, development |
Category-Specific Property Schemas
In addition to universal properties, each event category has a set of standard properties that provide category-specific analytical context.
User Event Properties
- →
user_role— the user's role in the account (admin, member, viewer) - →
user_plan— the subscription plan the user's account is on - →
user_created_at— the user's account creation date (for cohort analysis) - →
feature_context— which product area triggered this event
Account Event Properties
- →
account_plan— current subscription plan - →
account_created_at— account creation date - →
account_size— number of seats or users in the account - →
previous_value/new_value— for state-change events (plan changes, seat count changes)
Billing Event Properties
- →
plan_id— identifier of the subscription plan - →
amount— amount in cents (avoid floats for currency) - →
currency— ISO 4217 currency code - →
billing_period— monthly, annual - →
mrr_delta— MRR impact of this billing event
Error Event Properties
- →
error_type— classification of the error (authentication, validation, integration, system) - →
error_code— application-specific error code - →
error_message— human-readable description (sanitized of PII) - →
severity— critical, high, medium, low - →
request_id— correlates the error to a specific API request
Example Event Taxonomy
The table below shows a representative event taxonomy for a B2B project management SaaS, illustrating how the naming convention and category structure apply in practice.
| Event Name | Category | Key Properties | Primary Analysis Use |
|---|---|---|---|
| user_signed_up | User | signup_source, plan, referrer | Acquisition, funnel top |
| user_activated | User | time_to_activate, activation_action | Activation rate |
| project_created | Feature | project_type, template_used | Feature adoption |
| task_completed | Feature | task_type, assignee_count, completion_method | Core engagement |
| report_exported | Feature | report_type, format, row_count | Power user signal |
| account_seat_added | Account | previous_seat_count, new_seat_count | Expansion signal |
| subscription_upgraded | Billing | from_plan, to_plan, mrr_delta | Revenue analytics |
| subscription_cancelled | Billing | reason, plan, days_since_signup, mrr_delta | Churn analysis |
| integration_connected | Feature | integration_type, connection_method | Integration adoption |
| api_error_raised | Error | endpoint, error_code, severity, request_id | Reliability monitoring |
Common Instrumentation Mistakes
- → Tracking page views instead of actions. Page views tell you where users go. Action events tell you what they do. For product analytics, user and feature events are far more informative than page view counts.
- → Missing the anonymous-to-identified transition. Users interact with your product before signing up. Track anonymous events and alias them to the user ID at signup — otherwise you lose all pre-signup behavior context and cannot measure funnel conversion accurately.
- → Inconsistent property naming across events.
user_idin one event anduserIdin another breaks any cross-event query. Enforce property naming consistency via a shared tracking plan and automated validation. - → Tracking too many events too early. Instrumenting everything generates noise and maintenance burden. Start with the events that answer your most important product questions, then expand. A focused 30-event taxonomy is more useful than 300 poorly-defined events.
- → Not filtering test and internal users from analytics. Events from your team's accounts contaminate product metrics. Filter by email domain, user flag, or account property in your analytics pipeline to exclude internal usage.