Vectry Analytics
← Blog
Engineering 2 min read

Instrumenting a Node.js service with @vectry/node

A practical guide to event design: namespaces, the operation grammar, change diffs, and capture patterns that never block your request path.

  • #sdk
  • #nodejs
  • #instrumentation
  • #guide

Instrumentation fails for two reasons: it’s too much work, or it produces events nobody can use later. This guide covers both — how to wire @vectry/node into a service in minutes, and how to design events that stay explainable a year from now.

Install and initialize

npm install @vectry/node
import { Vectry } from '@vectry/node';

const vectry = new Vectry({
  apiKey: process.env.VECTRY_API_KEY,
});

One client per process. The SDK batches and ships events asynchronously — capture() resolves fast and never sits in your request path.

Design the namespace first

Every event carries a namespace following the grammar {domain}.{entity}.{operation}:

  • inventory.item.updated
  • auth.session.created
  • billing.invoice.issued

Resist the temptation to invent free-form names. The namespace is how humans filter streams, how dashboards group signals, and how future-you finds anything. If you can’t name the domain and entity, you haven’t decided what the event is yet.

The operation is the contract

The operation object is what makes a Vectry event more than a log line:

await vectry.capture({
  namespace: 'inventory.item.updated',
  actor_id: 'usr-99992',
  actor_type: 'user',
  operation: {
    type: 'updated',
    system_domain: 'inventory',
    system_entity: 'item',
    system_entity_id: 'item-3339',
    changes: {
      original: { quantity: 3 },
      updated: { quantity: 5 },
    },
  },
});

Three rules we follow internally:

  1. Always name the instance. system_entity_id is what lets traces and threads assemble around a real thing.
  2. Diff only what changed. changes is a field-level diff, not a full snapshot — small, readable, auditable.
  3. Non-mutating events still have a target. A signaled or evaluated operation names the entity it evaluated, even though nothing changed.

Actors are never optional

actor_type accepts user, system, ai and device. The temptation is to default everything to system and move on — don’t. When an AI agent acts on your operation, actor_type: 'ai' is the difference between an auditable decision and an anonymous one. An event without a real actor is a bug, not a data point.

Where to capture

Put capture calls at the domain boundary, not in controllers: the service method that actually mutates the entity is the one place that knows the original and updated values. Instrument there once, and every caller — HTTP handler, queue consumer, cron job — emits the same well-formed event.

That’s the whole discipline. One grammar, captured where the truth lives, with the actor attached. Everything else — traces, threads, explanations, anomalies — Vectry builds from there.

Stop guessing. Start explaining.

Bring causal infrastructure to your operation — or start instrumenting with the open-source SDKs today.