> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tell.rs/llms.txt
> Use this file to discover all available pages before exploring further.

# What to Track

> When to use events vs logs vs snapshots — and how to name them.

Tell has three data protocols. Choosing the right one for each signal keeps your data clean and your queries fast.

## 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 |

**Events** are user-centric. Every event is tied to a device and a user. Use events for anything you'd put in a product analytics tool — signups, purchases, feature usage, page views, funnels, retention.

**Logs** are infrastructure-centric. They're tied to a service and a severity level, not a user. Use logs for errors, warnings, deploys, background job status — anything your application does that isn't a direct user action.

**Snapshots** pull metrics from external services on a schedule. Use snapshots for data that lives outside your app — repository stars, store revenue, email delivery rates.

### 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                    |

The test: **would a product manager care about this in a funnel or retention chart?** If yes, it's an event. If it's something an engineer debugs in a log viewer, it's a log.

## Naming events

Use `snake_case`. Be specific. Name the action, not the UI element.

```javascript theme={null}
// Good
tell.track('sign_up', { plan: 'free' });
tell.track('invite_sent', { role: 'editor' });
tell.track('report_exported', { format: 'csv' });

// Bad
tell.track('click_button');        // what button?
tell.track('SignUp');              // use snake_case
tell.track('user_did_a_thing');   // be specific
```

### 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                   |

Keep your event namespace flat. Don't use dots or slashes — `purchase` not `ecommerce.purchase`. Use properties for dimensions, not the event name.

```javascript theme={null}
// Good — one event name, dimensions in properties
tell.track('purchase', { category: 'subscription', plan: 'pro' });
tell.track('purchase', { category: 'one_time', product: 'report' });

// Bad — splitting into multiple event names
tell.track('subscription_purchase', { plan: 'pro' });
tell.track('one_time_purchase', { product: 'report' });
```

The first approach gives you one funnel step, one retention event, and one metric — broken down by `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](/pipeline/transforms/redact) or hash values before sending
* **High-cardinality IDs** — don't put `request_id` or `trace_id` in 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 every `track` call, register it once:

```javascript theme={null}
tell.register({ app_version: '2.1.0', environment: 'production' });
```

Every subsequent event includes these properties automatically. See [Events & Properties](/tracking/events-and-properties) for details.

## 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.

```javascript theme={null}
tell.log('error', 'Payment gateway timeout', {
  gateway: 'stripe',
  duration_ms: 12340,
  retry_count: 3
});
```

Use a consistent service name for each SDK instance — `billing`, `auth`, `api`, `worker`. This becomes your primary filter dimension in log queries.

See [Logs](/tracking/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           |

Start small. You can always add events later — but renaming or removing them means losing historical continuity.

## What's next

* [Events & Properties](/tracking/events-and-properties) — the full event model and SDK methods
* [Logs](/tracking/logs) — structured logging with severity levels
* [Integrations](/tracking/integrations/overview) — pull snapshots from external services
* [Filtering](/analytics/filtering) — how properties become filters and breakdowns
