@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