Core Concepts
Shared vocabulary used across the SDKs, the API, and the dashboard. Read this once — every other page builds on these ideas.
Organization and project
Pug is multi-tenant. Your data always lives inside a project; projects belong to an organization. You only deal with these for billing and access — the things you actually instrument are events and profiles.
| Concept | What it is | Scope |
|---|---|---|
| Organization | Team workspace with members and billing | All projects in the org |
| Project | Isolated analytics environment | Events, profiles, insights |
Public key (pub_…) | Client credential for SDKs | Single project |
Private key (prv_…) | Secret credential for your servers | Single project |
The dashboard URL is prefixed with the active project: /p/<projectId>/….
Event pipeline
When your app calls track(), the event travels through an async pipeline before it appears in analytics.
Timing: ingestion is near-real-time. Events typically appear in Live within seconds and in Insights queries within the same minute. Profile writes are fully async, processed by profile workers.
Events
An event is a named occurrence with properties and a timestamp.
track('button_clicked', { label: 'Sign up', page: '/pricing' })- Event name (
kind) — any string; well-known events have typed schemas. Names starting withpug.are reserved. - Custom properties — your key/value pairs (string, number, boolean, timestamp).
- Auto-properties — fields prefixed with
$that the SDK and server attach automatically (e.g.$url,$browser,$country).$-prefixed keys are reserved — see Auto-properties. - Timestamp — defaults to send time; override per event for offline replay.
Events are immutable once stored. Corrections mean a new event or a profile-trait update.
Profiles
A profile represents a user — anonymous or identified.
Anonymous → identified
- A visitor arrives. The SDK creates an anonymous ID (
anon-…) tied to the device. - Events accumulate against that anonymous ID.
- The user signs in. You call
identify('user-123', { email: '…' }). - On that first identify, the SDK sends the anonymous ID alongside your external ID so the backend can merge the prior anonymous activity into the identified profile.
// Before sign-in — anonymous
track('page_view')
track('add_to_cart', { productId: 'sku_123' })
// After sign-in — merges anonymous history into the identified profile
await identify('user-123', { email: '[email protected]', plan: 'pro' })
track('purchase', { productId: 'sku_123', amount: 29.99, currency: 'USD' })Three ID terms recur across the SDKs and API:
| ID | What it is | When used |
|---|---|---|
Anonymous ID (anon-…) | Device ID the SDK generates | Before sign-in |
| External ID | Your stable user ID, passed to identify() | After sign-in |
| Distinct ID | The umbrella value stored on every event | Anonymous ID until identified, then external ID |
Storage and timing
- Writes (identify, trait updates, merges) are processed asynchronously by profile workers via NATS.
- Expect a few seconds between an
identify()call and the profile appearing in dashboard search. - Use a stable external ID (your database user ID), not something that changes like an email.
Sessions
A session groups events within a single visit. SDKs manage session IDs automatically:
- A new session starts on the first event after the idle timeout (default 30 minutes of inactivity).
- The session extends on each event inside the window, up to a max duration (default 24 hours).
- The Web SDK syncs the session ID across browser tabs via
localStorage.
Force a new session without clearing identity with rotate(). Clear identity and start fresh with reset().
Insights
An insight is a query specification — the definition of an analytics question, not a saved chart:
| Field | Example |
|---|---|
| Events | page_view, purchase |
| Time range | Last 7 days |
| Granularity | Day |
| Aggregation | Unique users |
| Breakdown | $country |
| Filters | plan = 'pro' |
The same insight model powers the dashboard’s charts and the shared.insights.v1.InsightsService API, which you can query from your own backend with a private key. Insight types include trends, funnels, retention, segmentation, user flow, and session metrics.
Authentication modes
Pug has three auth boundaries: the public key (pub_…) authenticates client SDKs, the private key (prv_…) authenticates your server, and a JWT authenticates the dashboard. See Authentication for the full matrix of headers, scopes, and examples.
Further reading
- Authentication — keys, headers, Connect RPC
- Well-known events — typed event schemas
- Glossary — quick term lookup