LIVE · AUDIT-CHAINED · EU-RESIDENT
SYSTEM · 99.99% UPTIME
v 1.0 ↗ MADE IN EU

@nexbasira/embed

A browser widget that renders the NexBasira field-side experience inside your own app. Drop in a <div>, point it at a minted session URL, listen for lifecycle events. No iframe boilerplate you have to write yourself.

Install

npm install @nexbasira/embed

Or via <script> tag for non-bundled use — see Script tag below.

Basic usage

import { embed } from "@nexbasira/embed";

const widget = embed({
  container: "#nb-host",          // selector or HTMLElement
  sessionUrl: invite.url,          // minted by your backend via the Node/Python SDK
  width: "100%",
  height: "720px",
  onReady: () => console.log("iframe loaded"),
  onSessionJoined: (id) => console.log("field user joined", id),
  onEvidenceAdded: (ev) => console.log("evidence", ev),
  onSessionComplete: (id) => router.push(`/inspections/${id}`),
});

sessionUrl is the one-shot signed URL your backend gets back from sessions.invite(). Never embed an API secret in the URL — only the field-session token, which is single-use + IP/UA-pinned.

Imperative methods

The returned widget handle lets the host page drive the field-side experience programmatically — typically used by a toolbar outside the iframe:

widget.requestSnapshot();    // operator-side trigger; field captures a frame
widget.openWhiteboard();
widget.closeWhiteboard();
widget.switchCamera();        // toggle front / rear on supported devices
widget.mute();
widget.unmute();
widget.endSession();
widget.destroy();             // tear down the iframe + remove listeners

Each method posts a message to the iframe's window via postMessage with the configured expectedOrigin; the iframe's internal dispatcher routes them to the relevant control.

Lifecycle events

Every callback you pass to embed({ on... }) is invoked when the matching postMessage from the iframe arrives. The origin check is enforced — messages from any other origin are ignored, so you can trust the payload shape.

CallbackFires whenPayload
onReadyiframe finished loading + handshake
onSessionJoinedField user joined the roomsessionId
onSessionCompleteSession closed (operator ended, or auto-expired)sessionId
onEvidenceAddedNew snapshot / annotation / whiteboard / clip{ id, kind }
onWhiteboardOpenedWhiteboard panel opened
onWhiteboardSavedWhiteboard exported to Evidence{ id }
onParticipantJoined / onParticipantLeftParticipant state change{ id, role }
onErrorAny iframe-side error{ message, code }

Script tag

For consumers without a bundler:

<script src="https://unpkg.com/@nexbasira/embed@latest/dist/index.umd.js"></script>
<div id="nb-host" style="width: 100%; height: 720px"></div>
<script>
  const widget = NexBasira.embed({
    container: "#nb-host",
    sessionUrl: "<minted-by-your-backend>",
    onSessionComplete: (id) => alert("done: " + id),
  });
</script>

The bundle attaches NexBasira.embed on window for this pattern.

Origin pinning

By default the widget derives the expected iframe origin from the URL you passed (sessionUrl) and rejects messages from any other origin. If you're hosting the field-side experience on a custom domain (Pro tier), pass expectedOrigin explicitly:

embed({
  container: "#nb-host",
  sessionUrl: "https://inspect.yourco.com/r/abc",
  expectedOrigin: "https://inspect.yourco.com",
  // ...
});

React app?

Use @nexbasira/react instead — same widget underneath, idiomatic React API (<NexBasiraSession> component + useNexBasiraSession() hook), fresh-closure callbacks across re-renders.

What's next