# Custom events

Emit custom events to track product actions, business outcomes, and feedback signals.

Events let you capture specific actions, milestones, and outcomes inside your application. Traces capture *how* something happened (latency, tokens, tool calls); events capture *what* happened (`order.placed`, `feedback.positive`, `agent.goal.achieved`).

:::info
**Always attach events to a session.** Emit them inside a session context, or include `brizz.session.id` as an attribute. Without a session, events show up but can't be correlated with the conversation that produced them.
:::

## When to use events

Use events to track:

- **Business outcomes** — `subscription.upgraded`, `order.placed`, `signup.completed`
- **Agent milestones** — `agent.goal.achieved`, `tool.execution.failed`
- **User interactions** — `feedback.submitted`, `button.clicked`, `flow.abandoned`

:::tip
**Reporting a number?** If the thing you're recording is a measurement — an eval score, a rating, a latency — use [`record_metric`](/docs/instrument/record-metric.md) instead of a custom event. You get a typed shape (value, unit, scale, polarity) and a real metric you can filter and chart by, rather than a free-form attribute bag Brizz has to be told how to read.
:::

## Inside a session

Events emitted within a session context inherit the session ID automatically.

:::tabs
:::tab[Python]
```python
from brizz import start_session, emit_event

with start_session("session-123", {"user_id": "user-42"}):
    # Tagged with session.id = session-123 automatically
    emit_event("user.action", {"action": "chat", "flow": "smart"})
    response = openai.chat.completions.create(...)
```
:::tab[Node.js]
```typescript
import { withSessionId, emitEvent } from '@brizz/sdk';

const processChat = withSessionId('session-123', async () => {
  emitEvent('chat.started', { userId: 'user-42', flow: 'smart' });

  const result = await generateText({
    model: openai('gpt-4'),
    prompt: 'Hello!',
    experimental_telemetry: { isEnabled: true },
  });

  return result;
});
```
:::

## Outside a session

If you can't be inside a session scope, include the session ID as an attribute. Brizz will link the event to the right session.

:::tabs
:::tab[Python]
```python
from brizz import emit_event

emit_event(
    "order.placed",
    attributes={
        "brizz.session.id": "session-123",
        "plan": "pro",
        "amount": 49,
    },
    body={
        "order_id": "ord-789",
    },
)
```
:::tab[Node.js]
```typescript
import { emitEvent } from '@brizz/sdk';

emitEvent(
  'order.placed',
  {
    'brizz.session.id': 'session-123',
    plan: 'pro',
    amount: 49,
  },
  {
    order_id: 'ord-789',
  },
);
```
:::

## Attributes vs body

- **`attributes`** — high-level metadata you want to filter and chart by in the dashboard. Keep them flat: strings, numbers, booleans.
- **`body`** — free-form JSON, comments, or larger blobs that provide context but don't need to be filterable.

A good rule: if you'd ever want a chart "events broken down by X", put X in attributes.

## Naming conventions

Use dot-notation namespaces — they sort sensibly and stay readable as the catalog grows.

- `category.action` — `auth.login`, `feedback.positive`
- `category.object.action` — `agent.tool.error`, `agent.run.completed`

Stick to one convention across your team. `user.signup` everywhere is better than mixing `user.signup`, `UserSignup`, and `user_signed_up`.

## Best practices

1. **Use consistent naming.** Lock in a convention up front; renaming events later means breaking dashboard mappings.
2. **Track outcomes, not just starts.** Emit `agent.run.completed` *and* `agent.run.failed` — funnels need both.
3. **Keep payloads lean.** Don't dump every variable in scope into the body — use it for context, not state snapshots.
4. **Map system events early.** If you're emitting feedback events, set up [system event mappings](/docs/instrument/user-feedback.md) so dashboard filters and charts pick them up.

## See also

- [Events (in the dashboard)](/docs/platform/events.md) — browse and search the events you emit, and verify new instrumentation landed.
- [Sessions](/docs/instrument/sessions.md) — capture and enrich the session context events attach to.
- [User feedback](/docs/instrument/user-feedback.md) — the special case of feedback events and system mappings.
- [Identify users](/docs/instrument/identify-users.md) — attach user IDs so events correlate with the right person.
