Configuration
Full configuration reference for auto-instrumentation — enrichment, userId resolution, environment variables, and limitations.
Configuration reference
instrument({
// ─── Required ───
apiKey: 'your-api-key', // or PROVENANCE_API_KEY env var
origin: 'my-service', // or PROVENANCE_ORIGIN env var
// ─── Platform ───
platformUrl: 'https://...', // default: https://platform.provenance.dev
apiUrl: 'https://...', // explicit API URL (skips platform resolution)
allowLocalhost: false, // allow localhost URLs (dev only)
// ─── Patches ───
instrumentations: ['http', 'http-outbound', 'express', 'fastify', 'fetch'], // which modules to patch
// ─── Enrichment ───
enrich: (ctx) => ({ ... }), // common fields merged into every interaction
// ─── Resolution ───
routes: { ... }, // route pattern → { resourceType, action }
models: { ... }, // ORM model name → { resourceType } or null
actions: { ... }, // HTTP verb → action override
topics: { ... }, // message topic → { resourceType, action } or null
outbound: { ... }, // hostname → { resourceType, action }
resourceId: { ... }, // resource type → (ctx) => id
userId: (ctx) => '...', // user ID resolver function
resolve: (ctx) => { ... }, // full override function
exclude: [ ... ], // paths to skip
});User ID resolution
The auto-instrumentation resolves the user performing each interaction through a chain — first match wins:
x-useridheader — if the incoming request includes this header, it's used directlyuserId()resolver function — a configurable function you provide in theinstrument()configreq.user.id— fallback to theidproperty ofreq.user(set by auth middleware like Passport, express-jwt, etc.)
Default behavior
With no configuration, the userId is resolved from the x-userid header or req.user.id:
instrument({
apiKey: process.env.PROVENANCE_API_KEY,
origin: 'order-service',
});
// If your auth middleware sets req.user = { id: 'user-123', email: '...' }
// → userId resolves to 'user-123' automaticallyCustom userId resolver
When your user object doesn't have an id field, or you want to use a different property:
instrument({
apiKey: process.env.PROVENANCE_API_KEY,
origin: 'order-service',
// Extract userId from your auth middleware's user object
userId: (ctx) => ctx.user?.sub, // JWT subject claim
// or
userId: (ctx) => ctx.user?.email, // use email as identifier
// or
userId: (ctx) => ctx.user?.uid, // Firebase UID
// or
userId: (ctx) => ctx.headers['x-forwarded-user'], // proxy header
});The ctx object passed to the resolver is the same request context used everywhere else — it has user, headers, params, body, etc.
The resolver runs when req.user becomes available (after your auth middleware) and again at flush time. The x-userid header always takes priority — if it's set, the resolver is not called.
Enrichment
Add common fields to every interaction's data object — IP address, session ID, environment, or anything else from the request context:
instrument({
apiKey: process.env.PROVENANCE_API_KEY,
origin: 'order-service',
enrich: (ctx) => ({
ip: ctx.headers['x-forwarded-for']?.split(',')[0]?.trim(),
sessionId: ctx.headers['x-session-id'],
environment: process.env.NODE_ENV,
}),
});The enrich function is called once per request at flush time. The returned object is merged into every interaction's data — HTTP, Prisma, fetch, and manual track() calls all get the same fields.
Fields from the individual interaction take priority over enriched fields. If a Prisma interaction already has { model: 'Order', operation: 'create' } and your enrich function returns { ip: '1.2.3.4', model: 'override' }, the result is { ip: '1.2.3.4', model: 'Order', operation: 'create' } — the interaction's own model wins.
The ctx object is the same request context available everywhere else:
enrich: (ctx) => ({
// From headers
ip: ctx.headers['x-forwarded-for']?.split(',')[0]?.trim(),
sessionId: ctx.headers['x-session-id'],
correlationId: ctx.headers['x-correlation-id'],
// From auth
tenantId: ctx.user?.tenantId,
userRole: ctx.user?.role,
// From environment
environment: process.env.NODE_ENV,
region: process.env.AWS_REGION,
version: process.env.APP_VERSION,
// From request
userAgent: ctx.headers['user-agent'],
})If the enrich function throws, the error is silently caught — interactions are still flushed without the enriched fields. This ensures enrichment never breaks your application.
Environment variables
| Variable | Description |
|---|---|
PROVENANCE_API_KEY | API key (used if apiKey not passed to instrument()) |
PROVENANCE_ORIGIN | Origin name (used if origin not passed) |
Limitations
- Node.js only — auto-instrumentation uses
AsyncLocalStorageand module patching, which are Node.js-specific. Python and Java equivalents are planned. - ESM —
require('@stdiolabs/provenance-sdk/auto')works with CommonJS. For ESM apps, use--require provenance-sdk/autoin your Node.js flags or import before other modules. - Fastify — requires explicit
instrumentFastify(app)call because Fastify hooks are per-instance. - Prisma — requires explicit
instrumentPrisma(client)call because the Prisma client is user-instantiated. - Sequelize — requires explicit
instrumentSequelize(sequelize)call because the Sequelize instance is user-created. - Body capture — request bodies are only captured for
POST,PUT, andPATCHrequests with JSON content. - Response capture — response bodies are captured for resource ID extraction but not stored in the interaction metadata (to avoid logging sensitive data).