Events, logs, or snapshots?
| Signal | Protocol | Example |
|---|---|---|
| A user does something | Event | sign_up, purchase, page_view |
| Your app does something | Log | Error, warning, deploy, job completion |
| An external service has a metric | Snapshot | GitHub stars, Shopify revenue, Cloudflare requests |
When it’s unclear
Some signals could go either way. Here’s how to decide:| Signal | Use event or log? | Why |
|---|---|---|
| User clicks “Export” | Event | It’s a user action you want in funnels and retention |
| Export job fails | Log | It’s an application error, not a user action |
| User sees an error page | Log | It’s an application error — count and filter by user in log queries |
| Server returns 500 | Log | It’s infrastructure behavior |
| Payment succeeds | Event (revenue) | It’s a business outcome tied to a user |
| Payment gateway times out | Log | It’s a system failure |
| API rate limit hit | Log | It’s infrastructure, even if a user triggered it |
Naming events
Usesnake_case. Be specific. Name the action, not the UI element.
Naming conventions
| Pattern | Example | When to use |
|---|---|---|
noun_verb | report_exported, invite_sent | Completed actions (most events) |
noun_verb | checkout_started, trial_ended | State transitions |
page_view | page_view | Page or screen views (use this exact name) |
feature_used | feature_used with feature property | Generic feature tracking |
purchase not ecommerce.purchase. Use properties for dimensions, not the event name.
category. The second fragments your data.
Choosing properties
Properties are the key-value pairs that make your events queryable. Every property you send becomes a breakdown, filter, or aggregation dimension.What to include
| Property type | Examples | Why |
|---|---|---|
| What happened | plan, amount, format, source | Core dimensions for breakdowns |
| Where it happened | page_url, screen, section | Location context |
| Experiment context | variant, experiment_id | A/B test analysis |
| Business context | currency, coupon_code, referrer | Revenue and attribution |
What NOT to include
- PII in plain text — use the redact transform or hash values before sending
- High-cardinality IDs — don’t put
request_idortrace_idin event properties (use logs for that) - Redundant context — the SDK already sends device type, OS, browser, and session ID automatically
Super properties
If you find yourself adding the same property to everytrack call, register it once:
Structuring logs
Logs need a severity level and a message. The service name is set once when you initialize the SDK. Add structured data for anything you’d want to filter or search on.billing, auth, api, worker. This becomes your primary filter dimension in log queries.
See Logs for severity levels and SDK methods.
A starter tracking plan
Here’s a minimal set of events that covers most SaaS products:| Event | Properties | Why |
|---|---|---|
page_view | url, title, referrer | Traffic and navigation |
sign_up | plan, source, referrer | Acquisition |
login | method | Activation and frequency |
feature_used | feature, context | Engagement |
purchase | plan, amount, currency | Revenue |
invite_sent | role | Virality |
export_created | format, row_count | Value delivery |
What’s next
- Events & Properties — the full event model and SDK methods
- Logs — structured logging with severity levels
- Integrations — pull snapshots from external services
- Filtering — how properties become filters and breakdowns