@sumidata/browser

Session replay, console/error capture, and product events for the browser. Same SDK that ships on the CDN `<script>` tag — packaged for Next.js, Vite, Nuxt, and any bundler/CSP-strict setup.
792
Install
npm install @sumidata/browser
Latest Version:0.10.0
License:Proprietary
Last Updated:Oct 1, 2026
Links: npm
Maintainer: sumidata-dev

@sumidata/browser

Session replay, console/error capture, and product events for the browser. Same SDK that ships on the CDN <script> tag — packaged for Next.js, Vite, Nuxt, and any bundler/CSP-strict setup.

Install

npm install @sumidata/browser

Quickstart

import Sumidata from '@sumidata/browser'

Sumidata.init({ projectId: 'YOUR_PROJECT_ID' }) // starts recording

That is enough to get a replay in your dashboard. CommonJS:

const Sumidata = require('@sumidata/browser')
Sumidata.init({ projectId: 'YOUR_PROJECT_ID' })

Call init() in the browser only. It touches window/document, so in SSR frameworks run it client-side (see the framework guides below). Importing the package on the server is safe; calling init() on the server is not.

Configuration

Sumidata.init(config):

Option Type Default Notes
projectId string — Required. Your Sumidata project id (a UUID).
apiUrl string https://api.sumidata.io Base URL of the Sumidata API the SDK sends to.
flushInterval number 10000 Batch flush interval, ms.
masking 'fieldsOnly' | 'fieldsAndLabels' | 'dangerouslyNoMask' 'fieldsOnly' Input masking level.
captureNetworkBodies boolean true Capture request/response bodies of network calls.
autocapture 'on' | 'off' | boolean 'on' Automatic interaction events.
chat 'true' | 'false' | boolean false Site chat widget. Does not appear with the package: the chat bundle reads its config from the CDN loader and, without it, logs [Sumidata] Chat: no config found. For the widget use the CDN snippet with data-chat="true".
sdkUrl string — URL of sumidata.js, e.g. https://sdk.sumidata.io/sumidata.js. The heatmap page-capture bundle is loaded from the same place; without it page capture for heatmaps is off.

API

Method Purpose
init(config) Start the session and recording. Returns a Promise.
identify(userId) Link the session to a user; rotates the session on user change.
event(name, properties?) Track a product event.
purchase(order) Record an order (0.10.0 or later). See Purchases.
identifyExperiment([{ id, variant }]) Register A/B assignments (idempotent).
reset() Clear identity and start a fresh session (call on logout).
getSessionId() Current session id, or null. A new session can start at any time — read it when you send it, don't cache it at page load.
shutdown() Stop recording and flush.
push(method, args?) Command form: push('event', ['plan_selected']) is the same as event('plan_selected'). Takes identify, event, purchase, identifyExperiment, reset.
Sumidata.identify('user-42')
Sumidata.event('plan_selected', { plan: 'pro' })

Purchases

Record each order with purchase() (SDK 0.10.0 or later), once, when the order is placed:

Sumidata.purchase({
  orderId: 'ord-1001',
  totalAmount: 100,
  currency: 'USD',
  items: [
    { productId: 'shirt', productName: 'Shirt', quantity: 1, unitPrice: 40 },
    { productId: 'shoes', productName: 'Shoes', quantity: 1, unitPrice: 60 },
  ],
})

The SDK sends the order at once, in its own request, together with your project, the visitor's device and session (so the order is linked to the session and its replay) and the buyer. The buyer is the id you passed to identify(); an externalUserId on the order names a different buyer and wins. A call made before init() resolves waits in the SDK queue. With the CDN <script> snippet use the command form — it also waits if the SDK has not loaded yet. The wait needs the queue line that opens the install snippet; check that your page has it before the loader tag, or a call made before the SDK loads throws in your code:

<script>
  window.Sumidata = window.Sumidata || { push: function(m, a) { (this.q = this.q || []).push([m, a]) } };
</script>

Then:

window.Sumidata.push('purchase', [{
  orderId: 'ord-1002',
  totalAmount: 40,
  currency: 'USD',
  items: [{ productId: 'shirt', productName: 'Shirt', quantity: 1, unitPrice: 40 }],
}])
Field Type Notes
orderId string | number Required, non-empty. 1001 and '1001' are the same order.
totalAmount number What the buyer paid, after discount.
currency string ISO 4217, e.g. USD.
discountAmount number
couponCode string
isPrimarySale boolean
timestamp number Epoch ms. Default: the moment of the call.
items array Products: productId (required, non-empty string), productName, productCategory, quantity (whole, from 1, default 1), unitPrice (from 0, default 0).
externalUserId string The buyer. Overrides identify().
utmSource … utmContent string Campaign. Empty ones are filled from the buyer's latest campaign, otherwise the device's.

purchase() returns nothing and never throws. A recorded order is silent; anything else is logged to the console with the [Sumidata] prefix:

Console message Meaning
Purchase not sent: orderId must be a non-empty string or a number / Purchase not sent: purchase() expects an order object Nothing was sent.
Purchase <id> was already recorded — not counted again The project already has this orderId — a reload of the thank-you page is safe. A stored order cannot be corrected by resending.
Purchase <id> rejected — <field>: <reason> The server refused the order, e.g. product fields at the order level instead of items[].
Purchase <id>: <n> item(s) dropped: <reason> The order was recorded without the invalid products.
Purchase <id> not accepted — the project's monthly session quota is used up Nothing was stored.
Purchase <id> not delivered — call purchase() again to resend The browser reported the request as failed. The SDK does not resend on its own. A page that navigates away right after the call can log this too, while its request still delivers the order — calling again then reports it as already recorded.

Call purchase() once per order: two calls with the same orderId at the same moment can both be stored. There is no way to delete a single order — send test orders to a separate project.

event() cannot record a purchase: it moves every property into the event payload, so an orderId sent through it never counts.

Orders sent from your backend still go to POST https://api.sumidata.io/sdk/ingest — field reference, limits and response shapes: sumidata.io/docs/conversions/server-ingest.

Every method is error-isolated: a failure inside the SDK is logged with a [Sumidata] prefix and never throws into your application.

Framework guides

  • Next.js (App Router)
  • Vite / React
  • Nuxt
  • Google Tag Manager

Version History

Version Released License
0.10.0 Proprietary
0.7.0 Proprietary
0.3.1 Proprietary
0.3.0