# Segment Integration

Send Segment events to Brizz for observability alongside your AI agent traces

[Segment](https://segment.com) is a Customer Data Platform (CDP) that collects analytics events from your apps and routes them to hundreds of tools. It provides a single API for tracking user actions — [track](https://segment.com/docs/connections/spec/track/), [identify](https://segment.com/docs/connections/spec/identify/), [page](https://segment.com/docs/connections/spec/page/), and [group](https://segment.com/docs/connections/spec/group/) calls — and delivers them to any connected destination.

By connecting Segment to Brizz, your product analytics events appear alongside AI agent traces in the same session timeline, giving you a complete picture of what your users do and how your agents respond.

## Why Connect Segment?

Integrating Segment with Brizz enables:

- **Unified Observability**: See Segment events alongside OpenTelemetry traces in the same session timeline
- **User Journey Context**: Attach product events (sign-ups, purchases, feature usage) to AI agent sessions
- **No Code Changes Required**: If you already use Segment, events flow to Brizz automatically via a destination

## Two ways to connect

Both routes deliver the same events to the same place — pick one.

| | [Destination Function](#setup-custom-destination-function) | [Webhook destination](#setup-webhook-destination) |
|---|---|---|
| What you configure | A JavaScript function you paste into Segment | Segment's built-in Webhooks destination, pointed at a URL Brizz gives you |
| Where the URL comes from | You supply Brizz's ingestion endpoint | Brizz generates it when you create the webhook |
| Authentication | A Brizz telemetry key, in the function's settings | An HMAC shared secret, or a Brizz telemetry key |
| Best for | Full control over the payload, custom transforms | Getting connected without writing code |

:::info
These are **inbound** webhooks — Segment pushing events *into* Brizz. They're unrelated to [outbound webhooks](/docs/api/webhooks.md), where Brizz calls an endpoint *you* own to tell you a session matured. Same word, opposite direction, separate configuration.
:::

## Setup: Custom Destination Function

A [Destination Function](https://segment.com/docs/connections/functions/destination-functions/) is a JavaScript function that runs inside Segment and forwards events to an external API.

### 1. Create a Destination Function

Navigate to **Catalog > Functions** in Segment.

![Navigate to Functions in the Segment catalog](/docs/guides/integration/segment/catalog_function.png)

Click **New Function** and select **Destination**.

![Create a new destination function](/docs/guides/integration/segment/new_function.png)

### 2. Add the Function Code

Replace the default code with the Brizz destination function below. Copy the entire code block and paste it into the function editor.

The function handles all four Segment event types (track, identify, page, group) and supports [batching](https://segment.com/docs/connections/functions/destination-functions/#batching-the-destination-function) for efficient delivery.

```javascript
// Brizz – Segment Custom Function (Destination)
// Settings: apiKey, serviceName (optional), environment (optional), baseUrl (optional)

const DEFAULT_BASE_URL = 'https://telemetry.brizz.dev'

// ── Helpers ──────────────────────────────────────────────────────────────────

const SEVERITY_MAP = {
  trace: 1, debug: 5, info: 9, warn: 13, warning: 13, error: 17, fatal: 21, critical: 21
}

function brizzAliases(field) {
  const parts = field.split('_')
  const camel = 'brizz' + parts.map(p => p[0].toUpperCase() + p.slice(1)).join('')
  const dot = 'brizz.' + parts.join('.')
  const underscore = 'brizz.' + field
  return [...new Set([camel, dot, underscore])]
}

function lookupBrizzField(props, field) {
  for (const key of brizzAliases(field)) {
    if (typeof props[key] === 'string' && props[key]) return props[key]
  }
  return undefined
}

function lookupBrizzSeverity(props) {
  for (const key of brizzAliases('severity_number')) {
    const val = props[key]
    if (typeof val === 'number' && val >= 0 && val <= 24) return val
  }
  const level = lookupBrizzField(props, 'severity')
  if (typeof level === 'string' && SEVERITY_MAP[level.toLowerCase()] !== undefined) {
    return SEVERITY_MAP[level.toLowerCase()]
  }
  return undefined
}

function flattenObject(obj, prefix) {
  const result = {}
  for (const [key, value] of Object.entries(obj)) {
    const fullKey = prefix ? `${prefix}.${key}` : key
    if (value && typeof value === 'object' && !Array.isArray(value)) {
      Object.assign(result, flattenObject(value, fullKey))
    } else {
      result[fullKey] = value
    }
  }
  return result
}

function buildBrizzEvent(event, settings, eventName, eventType, body) {
  const attributes = flattenObject(event.context || {})

  if (event.userId) attributes['brizz.user_id'] = event.userId
  if (event.anonymousId) attributes['segment.anonymous_id'] = event.anonymousId
  if (event.messageId) attributes['segment.message_id'] = event.messageId
  attributes['segment.event_type'] = eventType

  const props = event.properties || event.traits || {}
  const severityNumber = lookupBrizzSeverity(props)

  const cleanBody = body && typeof body === 'object' && !Array.isArray(body)
    ? Object.fromEntries(Object.entries(body).filter(([k]) => !k.startsWith('brizz')))
    : body

  const result = {
    name: eventName,
    service_name: settings.serviceName || lookupBrizzField(props, 'service_name') || 'unknown',
    session_id: lookupBrizzField(props, 'session_id') || '',
    timestamp: event.timestamp || new Date().toISOString(),
    source: 'segment',
    environment: settings.environment || lookupBrizzField(props, 'environment'),
    attributes,
    body: cleanBody
  }

  if (severityNumber !== undefined) {
    result.severity_number = severityNumber
  }

  return result
}

async function sendToBrizz(brizzEvent, settings) {
  const baseUrl = settings.baseUrl || DEFAULT_BASE_URL
  const endpoint = `${baseUrl}/raw/events`

  let response
  try {
    response = await fetch(endpoint, {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${settings.apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(brizzEvent)
    })
  } catch (error) {
    const message =
      error && typeof error.message === 'string' ? error.message : String(error)
    throw new RetryError(`Network error while calling ${endpoint}: ${message}`)
  }

  if (response.status >= 500 || response.status === 429) {
    throw new RetryError(`Failed with ${response.status}`)
  }

  if (response.status === 401 || response.status === 403) {
    throw new ValidationError('Invalid Brizz API key (401 Unauthorized)')
  }

  if (response.status >= 400) {
    const body = await response.text()
    throw new ValidationError(`Request failed with ${response.status}: ${body}`)
  }
}

function mapEvent(event, settings) {
  switch (event.type) {
    case 'track':
      return buildBrizzEvent(event, settings, event.event, 'track', event.properties || {})
    case 'identify':
      return buildBrizzEvent(event, settings, 'identify', 'identify', event.traits || {})
    case 'group':
      return buildBrizzEvent(event, settings, 'group', 'group', { group_id: event.groupId, ...(event.traits || {}) })
    case 'page': {
      const pageName = event.name ? `page.${event.name}` : 'page_view'
      return buildBrizzEvent(event, settings, pageName, 'page', event.properties || {})
    }
    default:
      return null
  }
}

// ── Event Handlers ───────────────────────────────────────────────────────────

async function onBatch(events, settings) {
  const brizzEvents = events.map(e => mapEvent(e, settings)).filter(Boolean)
  if (brizzEvents.length === 0) return
  await sendToBrizz(brizzEvents, settings)
}

async function onTrack(event, settings) {
  await sendToBrizz(mapEvent(event, settings), settings)
}

async function onIdentify(event, settings) {
  await sendToBrizz(mapEvent(event, settings), settings)
}

async function onGroup(event, settings) {
  await sendToBrizz(mapEvent(event, settings), settings)
}

async function onPage(event, settings) {
  await sendToBrizz(mapEvent(event, settings), settings)
}

async function onScreen(event, settings) {
  throw new EventNotSupported(
    'screen events are not currently mapped to Brizz telemetry. Consider using page events instead.'
  )
}

async function onAlias(event, settings) {
  throw new EventNotSupported(
    'alias events are not currently mapped to Brizz telemetry. Consider using identify events instead.'
  )
}

async function onDelete(event, settings) {
  throw new EventNotSupported(
    'delete events are not currently mapped to Brizz telemetry. Handle user deletion via your data privacy process outside of Brizz.'
  )
}
```

### 3. Configure Settings

Click the **Settings** tab and add the following fields:

![Function settings tab](/docs/guides/integration/segment/settings.png)

| Setting         | Type   | Required | Description                                                                 |
| --------------- | ------ | -------- | --------------------------------------------------------------------------- |
| `apiKey`        | String | **Yes**  | Your Brizz API key (found in **Settings > API Keys** in the Brizz dashboard) |
| `serviceName`   | String | No       | Static application name. Can also be sent per-event via `brizzServiceName`.  |
| `environment`   | String | No       | Deployment environment (e.g. `production`). Can also be sent via `brizzEnvironment`. |
| `baseUrl`       | String | No       | Override the telemetry endpoint. Defaults to `https://telemetry.brizz.dev`. |

Add the **API Key** setting:

![Add API Key setting](/docs/guides/integration/segment/add_settings_api_key.png)

Optionally add **Service Name**:

![Add Service Name setting](/docs/guides/integration/segment/add_settings_service_name.png)

Review your final settings:

![Final settings overview](/docs/guides/integration/segment/final_settings.png)

### 4. Name and Create the Function

Give your function a name (e.g. "Brizz") and click **Create Function**.

![Name and create the function](/docs/guides/integration/segment/configure_function.png)

### 5. Connect a Source

Back in the Segment catalog, find your new Brizz destination and click **Connect Destination**.

![Connect destination from catalog](/docs/guides/integration/segment/connect_destination.png)

Select the source you want to send events from:

![Select source](/docs/guides/integration/segment/connect_source.png)

### 6. Enable the Destination

Fill in the destination settings (API key, etc.) and **enable** the destination using the toggle.

![Destination settings and enable toggle](/docs/guides/integration/segment/destination_settings.png)

### 7. Verify Events

Open the **Event Tester** tab to confirm events are flowing. It may take a couple of minutes on the first run.

![Event tester showing successful delivery](/docs/guides/integration/segment/event_tester.png)

Verify that events show as **successfully delivered**:

![Final verification of event delivery](/docs/guides/integration/segment/final_verify.png)

Once delivered, events appear in the Brizz session timeline:

![Events visible in a Brizz session](/docs/guides/integration/segment/brizz_session.png)

---

## Setup: Webhook destination

Instead of running a function, you can point Segment's built-in **Webhooks** destination at an endpoint Brizz generates for you. Brizz walks you through this in the product, with screenshots for each Segment screen — start from **Integrations > Segment > Connect**, and the wizard supplies the URL and credentials as you go.

The shape of it:

1. **Create the webhook in Brizz** and choose how Segment will authenticate:
   - **Shared secret (HMAC)** — Brizz generates a signing secret. Paste it into the **Shared Secret** field of the Segment destination. Shown once.
   - **Telemetry key** — reuse a Brizz [telemetry key](/docs/admin/api-keys.md). You'll send it as an `Authorization: Bearer <key>` header in the mapping.
2. **Add the Webhooks destination in Segment** and pick the source that will send events to it.
3. **Add a mapping**, set streaming behavior to **Send**, and choose which event types trigger it (Track, Identify, Page, Group).
4. **Map the fields**: set the mapping's **URL** to the webhook endpoint Brizz gave you. If you chose telemetry key auth, add the `Authorization` header here too.
5. **Send a test record** from Segment and confirm it arrives.

Manage or remove these webhooks later under **Integrations > Segment**.

## Sending Brizz Metadata in Events

Brizz extracts special fields from event [properties](https://segment.com/docs/connections/spec/track/#properties) (or [traits](https://segment.com/docs/connections/spec/identify/#traits) for identify/group) using a naming convention. All fields accept multiple formats:

| Field              | Accepted Property Keys                                              | Description                          |
| ------------------ | ------------------------------------------------------------------- | ------------------------------------ |
| `session_id`       | `brizzSessionId`, `brizz.session.id`, `brizz.session_id`           | Links the event to a Brizz session   |
| `service_name`     | `brizzServiceName`, `brizz.service.name`, `brizz.service_name`     | Application name (settings override) |
| `environment`      | `brizzEnvironment`, `brizz.environment`                             | Deployment environment (settings override) |
| `severity_number`  | `brizzSeverityNumber`, `brizz.severity.number`, `brizz.severity_number` | OTel severity 0-24              |
| `severity` (text)  | `brizzSeverity`, `brizz.severity`                                   | String level (e.g. `"error"` maps to 17) |

:::tip
To correlate Segment events with Brizz traces, send the same `session_id` you use in the Brizz SDK. See [Sessions](/docs/instrument/sessions.md) for details.
:::

**Example:**

:::tabs
:::tab[Python]
```python
import segment.analytics as analytics

analytics.track(
    user_id="user-123",
    event="Order Completed",
    properties={
        "revenue": 99.99,
        "brizzSessionId": session_id,
        "brizzServiceName": "my-app",
        "brizzEnvironment": "production",
    },
)
```
:::tab[Node.js]
```typescript
analytics.track({
  userId: 'user-123',
  event: 'Order Completed',
  properties: {
    revenue: 99.99,
    brizzSessionId: sessionId,
    brizzServiceName: 'my-app',
    brizzEnvironment: 'production',
  },
});
```
:::

All properties that don't start with `brizz` are passed through as-is into the Brizz event body. Brizz-prefixed properties are consumed as metadata and stripped from the body.

## Supported Event Types

| Segment Type | Brizz Event Name                    | Body              |
| ------------ | ----------------------------------- | ----------------- |
| `track`      | Event name (e.g. "Order Completed") | `properties`      |
| `identify`   | `"identify"`                        | `traits`          |
| `page`       | `"page.{name}"` or `"page_view"`   | `properties`      |
| `group`      | `"group"`                           | `{ group_id, ...traits }` |

Batching is supported — when Segment sends a batch of events, they are forwarded to Brizz in a single API call.

## Managing the Integration

To disconnect or reconfigure the Segment integration:

1. Go to **Connections > Destinations** in the Segment dashboard
2. Find your Brizz destination function
3. Disable the toggle or delete the destination

Events already delivered to Brizz will remain in your telemetry history.

## References

- [Segment Spec Overview](https://segment.com/docs/connections/spec/) — the full event specification (track, identify, page, group, common fields)
- [Segment Common Fields](https://segment.com/docs/connections/spec/common/) — context, timestamps, and fields shared by all event types
- [Destination Functions](https://segment.com/docs/connections/functions/destination-functions/) — how Segment custom destination functions work
- [Destination Functions: Batching](https://segment.com/docs/connections/functions/destination-functions/#batching-the-destination-function) — batch handler configuration
- [Functions Editing Environment](https://segment.com/docs/connections/functions/environment/) — testing and deploying functions in Segment
- [Adding a Destination](https://segment.com/docs/connections/destinations/add-destination/) — general guide for connecting sources to destinations
- [Brizz Sessions](/docs/instrument/sessions.md) — how to use session IDs to correlate events with traces
- [Brizz Custom events](/docs/instrument/custom-events.md) — emitting custom events from the Brizz SDK

## See also

- [Custom events](/docs/instrument/custom-events.md) — naming conventions and attributes/body distinction.
- [Sessions](/docs/instrument/sessions.md) — make Segment events line up with the right session.
- [Slack](/docs/integrations/slack.md) and [Jira](/docs/integrations/jira.md) — outbound integrations for issues found in this data.
- [Outbound webhooks](/docs/api/webhooks.md) — the other direction: Brizz calling your endpoint when a session matures.
