Skip to main content

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

OptionTypeDefaultDescription
namestringundefinedName identifying the trace
includeUserMetabooleantrueInclude browser metadata
maxRetriesnumber3Retry attempts on failure
retryBackoffnumber1000Base backoff delay (ms)
autoClosebooleanfalseAutomatically close trace on page unload
const trace = client.trace({
  name: 'CriticalOperation',
  includeUserMeta: true,
  maxRetries: 5
});

Trace Lifecycle

1

Create

Call client.trace() to create a new trace builder
2

Build

Add attributes, tags, events, and transaction hints using the fluent API
3

Flush

First flush sends CreateTrace to the gateway
4

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