What is a Trace?
A trace represents a single logical operation or flow in your application. It’s the fundamental unit of data in the Mirador platform. Traces capture:
- The operation name
- Attributes (key-value metadata)
- Tags (categorical labels)
- Events (timestamped milestones)
- Transaction hints (blockchain correlation)
Creating a Trace
Create a trace using the client.trace() method:
const trace = client.trace({ name: 'UserCheckout' });
Trace Options
| Option | Type | Default | Description |
|---|
name | string | undefined | Name identifying the trace |
includeUserMeta | boolean | true | Include browser metadata |
maxRetries | number | 3 | Retry attempts on failure |
retryBackoff | number | 1000 | Base backoff delay (ms) |
autoClose | boolean | false | Automatically close trace on page unload |
const trace = client.trace({
name: 'CriticalOperation',
includeUserMeta: true,
maxRetries: 5
});
Trace Lifecycle
Create
Call client.trace() to create a new trace builder
Build
Add attributes, tags, events, and transaction hints using the fluent API
Flush
First flush sends CreateTrace to the gateway
Update
Subsequent flushes send UpdateTrace with new data
Keep-Alive & Closing Traces
The SDK automatically sends keep-alive pings to the server every 10 seconds (configurable) to maintain trace liveness:
const client = new Client('your-api-key', {
keepAliveIntervalMs: 15000 // Ping every 15 seconds (default: 10000)
});
Always close traces when you’re done to clean up resources:
const trace = client.trace({ name: 'UserSession' });
try {
// ... add events, attributes, etc ...
await trace.close('Session ended');
} catch (error) {
trace.addEvent('error', { message: error.message });
await trace.close('Session failed');
}
Enable auto-close on page unload for browser applications:
const trace = client.trace({
name: 'UserSession',
autoClose: true // Automatically close on page unload
});
The Builder Pattern
The Trace class uses a fluent builder pattern. All methods return this, allowing you to chain calls:
const trace = client.trace({ name: 'SwapExecution' })
.addAttribute('from', '0xabc...')
.addAttribute('to', '0xdef...')
.addTags(['dex', 'swap', 'ethereum'])
.addEvent('quote_received', { price: '1.5' })
.addEvent('user_approved')
.addTxHint('0x123...', 'ethereum');
Getting the Trace ID
After the first flush completes, you can retrieve the trace ID:
const trace = client.trace({ name: 'MyTrace' });
trace.flush();
// After flush completes
const traceId = trace.getTraceId();
console.log('Trace ID:', traceId);
getTraceId() returns null until the first flush has completed and the gateway has responded with a trace ID.
Flushing
The Web SDK automatically batches and sends trace data at the end of the current JavaScript tick (microtask). The first flush sends a CreateTrace request, and subsequent flushes send UpdateTrace requests with any new data.
You can also call flush() manually at any time to send pending data immediately:
const trace = client.trace({ name: 'MyTrace' })
.addAttribute('key', 'value')
.addEvent('started');
trace.flush(); // Send immediately instead of waiting for microtask
The Node.js SDK does not flush automatically. Use create() to send the initial trace and close() to send final updates.
Best Practices
Name Traces Descriptively
Use clear, action-oriented names:
// Good
client.trace({ name: 'UserSignup' })
client.trace({ name: 'TokenSwap' })
client.trace({ name: 'NFTMint' })
// Avoid
client.trace({ name: 'trace1' })
client.trace({ name: 'data' })
One Trace Per Logical Operation
Create a new trace for each distinct user action or flow:
// User connects wallet
const connectTrace = client.trace({ name: 'WalletConnect' });
// User initiates swap (separate operation)
const swapTrace = client.trace({ name: 'TokenSwap' });
Include Context Early
Add identifying attributes at trace creation:
const trace = client.trace({ name: 'Transfer' })
.addAttribute('userId', currentUser.id)
.addAttribute('sessionId', session.id)
.addAttribute('walletAddress', wallet.address);
Next Steps