Skip to main content

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.

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

Events, logs, or snapshots?

SignalProtocolExample
A user does somethingEventsign_up, purchase, page_view
Your app does somethingLogError, warning, deploy, job completion
An external service has a metricSnapshotGitHub 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:
SignalUse event or log?Why
User clicks “Export”EventIt’s a user action you want in funnels and retention
Export job failsLogIt’s an application error, not a user action
User sees an error pageLogIt’s an application error — count and filter by user in log queries
Server returns 500LogIt’s infrastructure behavior
Payment succeedsEvent (revenue)It’s a business outcome tied to a user
Payment gateway times outLogIt’s a system failure
API rate limit hitLogIt’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.
// 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

PatternExampleWhen to use
noun_verbreport_exported, invite_sentCompleted actions (most events)
noun_verbcheckout_started, trial_endedState transitions
page_viewpage_viewPage or screen views (use this exact name)
feature_usedfeature_used with feature propertyGeneric 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.
// 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 typeExamplesWhy
What happenedplan, amount, format, sourceCore dimensions for breakdowns
Where it happenedpage_url, screen, sectionLocation context
Experiment contextvariant, experiment_idA/B test analysis
Business contextcurrency, coupon_code, referrerRevenue 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_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:
tell.register({ app_version: '2.1.0', environment: 'production' });
Every subsequent event includes these properties automatically. See Events & 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.
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 for severity levels and SDK methods.

A starter tracking plan

Here’s a minimal set of events that covers most SaaS products:
EventPropertiesWhy
page_viewurl, title, referrerTraffic and navigation
sign_upplan, source, referrerAcquisition
loginmethodActivation and frequency
feature_usedfeature, contextEngagement
purchaseplan, amount, currencyRevenue
invite_sentroleVirality
export_createdformat, row_countValue delivery
Start small. You can always add events later — but renaming or removing them means losing historical continuity.

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