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

# Lifecycle Callbacks

> Monitor trace creation, flushes, errors, and closures programmatically

## Overview

Lifecycle callbacks let you observe trace events without modifying your tracing logic. Use them for monitoring, metrics, alerting, or debugging — the SDK invokes them at key points in a trace's lifecycle.

## TraceCallbacks Interface

```typescript theme={null}
interface TraceCallbacks {
  /** Called once when the trace is first created on the server (first successful flush) */
  onCreated?: (traceId: string) => void;

  /** Called after each successful flush */
  onFlushed?: (traceId: string, itemCount: number) => void;

  /** Called when a flush operation fails after retries */
  onFlushError?: (error: Error, operation: string) => void;

  /** Called when the trace is closed */
  onClosed?: (traceId: string, reason?: string) => void;

  /** Called when items are dropped (e.g., queue full) */
  onDropped?: (count: number, reason: string) => void;
}
```

## Callback Reference

### onCreated

Fired once per trace, after the first successful flush (i.e., the server has acknowledged the trace).

```typescript theme={null}
onCreated: (traceId: string) => void
```

| Parameter | Type     | Description                           |
| --------- | -------- | ------------------------------------- |
| `traceId` | `string` | W3C-compatible trace ID (32-char hex) |

### onFlushed

Fired after every successful flush. Useful for tracking throughput or confirming delivery.

```typescript theme={null}
onFlushed: (traceId: string, itemCount: number) => void
```

| Parameter   | Type     | Description                                              |
| ----------- | -------- | -------------------------------------------------------- |
| `traceId`   | `string` | The trace that was flushed                               |
| `itemCount` | `number` | Number of items (events, attributes, tags) in this flush |

### onFlushError

Fired when a flush fails after exhausting all retries. The data from that flush attempt is lost.

```typescript theme={null}
onFlushError: (error: Error, operation: string) => void
```

| Parameter   | Type     | Description                                                       |
| ----------- | -------- | ----------------------------------------------------------------- |
| `error`     | `Error`  | The final error after retries                                     |
| `operation` | `string` | The operation that failed (e.g., `"CreateTrace"`, `"FlushTrace"`) |

### onClosed

Fired when a trace is closed, either explicitly via `trace.close()` or automatically (e.g., max lifetime exceeded, page unload).

```typescript theme={null}
onClosed: (traceId: string, reason?: string) => void
```

| Parameter | Type                  | Description                                           |
| --------- | --------------------- | ----------------------------------------------------- |
| `traceId` | `string`              | The trace that was closed                             |
| `reason`  | `string \| undefined` | Optional close reason passed to `trace.close(reason)` |

### onDropped

Fired when items are discarded because the flush queue has reached `maxQueueSize`. This is a signal to reduce event volume or increase the queue size.

```typescript theme={null}
onDropped: (count: number, reason: string) => void
```

| Parameter | Type     | Description                                   |
| --------- | -------- | --------------------------------------------- |
| `count`   | `number` | Number of items dropped                       |
| `reason`  | `string` | Why items were dropped (e.g., `"queue full"`) |

## Setting Callbacks

### Client-Level (All Traces)

Callbacks set on the client apply to every trace it creates:

```typescript theme={null}
const client = new Client('your-api-key', {
  callbacks: {
    onCreated: (traceId) => {
      console.log('Trace created:', traceId);
    },
    onFlushError: (error, operation) => {
      console.error(`${operation} failed:`, error.message);
    }
  }
});
```

### Per-Trace (Override)

Per-trace callbacks override client-level callbacks for that specific trace:

```typescript theme={null}
const trace = client.trace({
  name: 'CriticalFlow',
  callbacks: {
    onFlushed: (traceId, itemCount) => {
      metrics.increment('critical_flush', { traceId, itemCount });
    },
    onFlushError: (error, operation) => {
      alerting.send(`Critical trace flush failed: ${error.message}`);
    }
  }
});
```

## Use Cases

### Metrics Collection

Track SDK health and throughput:

```typescript theme={null}
const client = new Client('your-api-key', {
  callbacks: {
    onCreated: () => metrics.increment('mirador.traces.created'),
    onFlushed: (_, itemCount) => {
      metrics.increment('mirador.flushes.success');
      metrics.histogram('mirador.flush.item_count', itemCount);
    },
    onFlushError: (error, operation) => {
      metrics.increment('mirador.flushes.error', { operation });
    },
    onDropped: (count) => {
      metrics.increment('mirador.items.dropped', {}, count);
    }
  }
});
```

### Error Alerting

Get notified when trace delivery fails:

```typescript theme={null}
const client = new Client('your-api-key', {
  callbacks: {
    onFlushError: (error, operation) => {
      // Send to your error tracking service
      Sentry.captureException(error, {
        tags: { operation, source: 'mirador-sdk' }
      });
    },
    onDropped: (count, reason) => {
      Sentry.captureMessage(`Mirador SDK dropped ${count} items: ${reason}`, 'warning');
    }
  }
});
```

### Debug Logging

Verbose output during development:

```typescript theme={null}
const client = new Client('your-api-key', {
  debug: true,
  callbacks: {
    onCreated: (traceId) => console.log(`[Mirador] Created: ${traceId}`),
    onFlushed: (traceId, n) => console.log(`[Mirador] Flushed ${n} items for ${traceId}`),
    onFlushError: (err, op) => console.error(`[Mirador] ${op} failed:`, err),
    onClosed: (traceId, reason) => console.log(`[Mirador] Closed: ${traceId} (${reason ?? 'no reason'})`),
    onDropped: (count, reason) => console.warn(`[Mirador] Dropped ${count}: ${reason}`)
  }
});
```

### Trace Correlation Logging

Log trace IDs for request correlation in your backend:

```typescript theme={null}
import { Client } from '@miradorlabs/nodejs-sdk';

const client = new Client(process.env.MIRADOR_API_KEY, {
  callbacks: {
    onCreated: (traceId) => {
      logger.info({ traceId, msg: 'Mirador trace started' });
    },
    onClosed: (traceId, reason) => {
      logger.info({ traceId, reason, msg: 'Mirador trace ended' });
    }
  }
});
```

## Error Safety

Callbacks are invoked inside a try-catch — if your callback throws, the SDK logs the error (via the configured [logger](/advanced/logging)) and continues normally. Your callbacks will never crash the SDK or interrupt trace delivery.

## Next Steps

<CardGroup cols={2}>
  <Card title="Custom Logging" icon="terminal" href="/advanced/logging">
    Configure SDK logging output
  </Card>

  <Card title="Retry Logic" icon="rotate" href="/advanced/retry-logic">
    Network failure handling
  </Card>

  <Card title="Types" icon="code" href="/api-reference/types">
    Full TraceCallbacks type definition
  </Card>
</CardGroup>
