@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.
| Callback | Fires when | Payload |
|---|---|---|
onReady | iframe finished loading + handshake | — |
onSessionJoined | Field user joined the room | sessionId |
onSessionComplete | Session closed (operator ended, or auto-expired) | sessionId |
onEvidenceAdded | New snapshot / annotation / whiteboard / clip | { id, kind } |
onWhiteboardOpened | Whiteboard panel opened | — |
onWhiteboardSaved | Whiteboard exported to Evidence | { id } |
onParticipantJoined / onParticipantLeft | Participant state change | { id, role } |
onError | Any 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
- @nexbasira/react — React wrapper
- @nexbasira/node — server-side SDK to mint the
sessionUrl - Source on GitHub