Vibiz
Vibiz
Vibiz docs
Overview
Install with an agentConsent and privacyEventsIdentify and traitsInstallPackagesVerify
Overview
Overview

Packages

What ships, where it comes from, and how versions behave.

Two entry points over one implementation.

Browser@vibiz/analyticscapture, identity, queue, delivery
Server@vibiz/analytics/nodeconversions your browser never sees

Shipping a second capture implementation for the server would mean two copies of cookie handling and consent reading drifting apart, which surfaces as two behaviours under one name and no way to tell from a dashboard which produced a row. The server entry point does not capture anything: it sends events you already know about, over the same wire format the browser uses, into the same parsing path on the collector.

Why the server half exists

The browser cannot see a webhook, a background job, or a payment confirmed by a provider three seconds after the customer closed the tab. Those are the events worth the most, because they carry the revenue that actually settled rather than the total that was in the cart.

import { track } from '@vibiz/analytics/node';

await track({
  orgId: process.env.VIBIZ_ID,
  event: 'purchase',
  visitorId,                      // persisted with the order at checkout
  properties: { value: 49.9, currency: 'EUR', order_id: order.id },
});

Say who the visitor is, not who you are

A server call reaches us from your datacentre. Read off the request, the address, the user agent and the country describe your infrastructure rather than your customer, and Meta is handed a robot in Frankfurt as the person who converted. Send the visitor's own instead, captured on the request that came from their browser:

await track({
  orgId: process.env.VIBIZ_ID,
  event: 'purchase',
  visitorId,
  url: landingUrl,          // where the UTMs and the click id are read from
  clientIp, clientUserAgent, clientCountry,
  properties: { value: 49.9, currency: 'EUR', order_id: order.id },
});

url is worth its own sentence, because nothing else replaces it. We do not receive UTM parameters, we extract them from that string, along with fbclid, gclid and ttclid. A server event sent without it carries no campaign and no click id, which is to say it is attributable to no advertising at all. Send the landing URL; later conversions can omit it, because acquisition is already recorded against the visitor.

Capture the three client fields when the browser is in front of you and keep them with the order. By the time a payment webhook fires, the request in your hands belongs to Stripe.

visitorId is what joins a server side conversion to the visit that produced it, and therefore to the ad click. It is readable from the vbz_vid cookie: store it with the order. It is the difference between a purchase attributed to a campaign and one attributed to nobody.

Send the same order_id from both halves. Without it a purchase tracked in both places counts twice, which is worse than tracking it in neither: the numbers look better and optimisation is trained on revenue that does not exist.

It never throws

track returns a result rather than raising. It runs inside payment webhooks and order confirmations, and a tracking call that takes down a checkout handler is a far worse outcome than a missing event.

There is no retry underneath it either, on purpose. A caller inside a webhook already has a retry policy imposed by the provider, and a second one below it produces duplicate events on every redelivery.

The wire protocol is append-only

A version shipped today is still posting the same envelope in three years. Fields may be added, since older senders simply omit them, but never renamed, retyped or given a new meaning. Changing the shape means a new version and a migration that lifts the old one, never an edit in place.

This is why sid, d, el and pii are optional: every one was added after the first client shipped, and that client still works.

Install

The npm package, in the framework you are already using.

Verify

Prove the install works, and find out what is wrong when it does not.

On this page

Why the server half existsSay who the visitor is, not who you areIt never throwsThe wire protocol is append-only