Traces & spans
startTrace, addSpan, addMessage, setOutput, and init.
because.init(options?)
Configure the SDK. Call once at app startup.
import because from '@refactorlabs/because';
because.init({
apiKey: 'your-api-key', // falls back to BECAUSE_API_KEY env var
apiUrl: 'https://...' // optional, override the ingest endpoint
});If no API key is found, the SDK disables itself. All calls become no-ops with no errors thrown.
Options
| Option | Type | Description |
|---|---|---|
apiKey | string | Your Because API key |
apiUrl | string | Override the default ingest URL |
debug | boolean | Log SDK operations to stdout |
because.startTrace(name, fn)
Wraps an async function in a trace. The trace is sent to Because when fn resolves or throws.
await because.startTrace('Assess claim', async () => {
// work happens here
});name must be 5–500 characters. Any characters are accepted, so names like Insurance claim - CLM-2024-03941 work fine.
Pass options as the second argument:
await because.startTrace(
'Insurance claim - CLM-2024-03941',
{
input: because
.table('Claim submission')
.fromObject({ claimId: 'CLM-2024-03941', vehicle: '2019 Toyota Camry' })
.build(),
metadata: { claimId: 'CLM-2024-03941', policyNumber: 'POL-8821-AU' },
retentionPeriod: '30d'
},
async () => {
// work happens here
}
);Options
| Option | Type | Description |
|---|---|---|
input | JsonObject | Input data attached to the trace |
metadata | Record<string, string | number | boolean | null> | Filterable key-value metadata |
retentionPeriod | RetentionPeriod | How long to keep the trace. Default: '7d' |
Retention periods
type RetentionPeriod = '1d' | '7d' | '30d' | '90d' | '1y';because.addSpan(type, name, ...)
Add a span to the currently active trace. Must be called within a startTrace callback. name follows the same 5–500 character rule as trace names.
There are two forms: static and callback.
Static form
Pass an options object to set input, output, durationMs, and other fields manually:
because.addSpan('db', 'Policy lookup', {
metadata: { table: 'policies', queryType: 'sql' },
input: {
query: 'SELECT * FROM policies WHERE number = $1',
params: ['POL-8821-AU']
},
output: { rows: 1 }
});Callback form
Pass an async callback and Because handles timing and output automatically. The span's durationMs is set from how long the callback takes, and its output is set from the callback's return value.
const policy = await because.addSpan('json', 'Load policy', async () => {
return await db.policies.findOne({ number: 'POL-8821-AU' });
// ^ becomes the span output automatically
});
// policy is typed to the return valuePass options as the third argument to include input, alerts, redact, or metadata:
await because.addSpan(
'json',
'Load policy',
{ input: { policyNumber: 'POL-8821-AU' }, redact: ['holder.name'] },
async () => {
return await db.policies.findOne({ number: 'POL-8821-AU' });
}
);Overloads
| Signature | Description |
|---|---|
addSpan(type, name, options?) | Static - set all fields manually |
addSpan(type, name, fn) | Callback - auto-timing, auto-output |
addSpan(type, name, opts, fn) | Callback with options |
Span types
| Type | Use for |
|---|---|
message | Plain text output |
json | Structured JSON data |
table | Tabular data (use because.table()) |
chart | Charts (use because.chart()) |
http | HTTP requests (usually via because.fetch()) |
llm | LLM calls, see LLM spans |
image | Images rendered inline, see Image spans |
db | Database queries, see Database spans |
Options
| Option | Type | Description |
|---|---|---|
input | JsonObject | Input to this step |
output | JsonObject | Output from this step |
durationMs | number | How long this step took |
metadata | DbSpanMetadata | When type: 'db', set collection, table, or queryType |
alerts | SpanAlert[] | Threshold rules evaluated at ingest. See Alerts |
redact | string[] | Fields to redact from input/output. See Redaction |
because.addMessage(name, text, opts?)
Shorthand for adding a message span. Useful for log-style checkpoints.
because.addMessage('Validation passed', 'All policy checks cleared', {
level: 'info'
});
because.addMessage(
'High-value claim',
'Claim exceeds $10,000 - flagged for review',
{ level: 'warn' }
);Options
| Option | Type | Description |
|---|---|---|
level | 'info' | 'warn' | 'error' | Severity. Default: 'info' |
because.setOutput(output, redact?)
Set the output on the active trace. Call at the end of a startTrace callback.
await because.startTrace('Insurance claim - CLM-2024-03941', async () => {
// ... spans ...
because.setOutput({
claimId: 'CLM-2024-03941',
decision: 'approved',
settlement: 6840
});
});Pass a redact array as the second argument to redact fields before the output is stored:
because.setOutput(
{ decision: 'approved', claimant: { name: 'James Okafor', address: '...' } },
['claimant.name']
);See Redaction for the full redaction syntax.