Roxels/ docs
embed

Embed overview

The Roxels embed is a JavaScript SDK plus an iframe. The SDK exposes one entry point — Roxels.start() — which mounts the iframe and returns a controller. The iframe handles all the hard browser media work (microphone, audio playback, LiveKit connection, screenshare). Your page never touches WebRTC.

One entry point, three displays

Roxels.start({ display: "modal" }); // centered dialog widget
Roxels.start({ display: "compact" }); // bottom-right panel widget
Roxels.start({ display: "none" }); // headless — you render the UI

The display choice is per-call, made by your code at start time. The same template can run as a modal here and headless there. Display is not a template setting.

Every call returns a controller object. You use it to pause, mute, screenshare, send messages, hang up, and subscribe to events. The controller is the same shape for all three displays.

const call = Roxels.start({ display: "modal", templateKey: "rk-..." });
call.on("connected", () => console.log("call is live"));
call.on("understanding", (data) => console.log("extracted:", data));
call.muteMic();
call.hangUp();

When to use which mode

Mode Pick when
Modal You want a polished out-of-the-box widget that dominates the screen during the conversation.
Compact You want the conversation to live in a corner panel so the user can keep working on your page.
Headless You want the conversation to feel native to your product — custom orb, custom transcript, custom controls. Roxels still runs the call; you draw every pixel.

If you don't know yet, start with modal — it's the fastest path to a working embed. You can switch to headless later by changing one option; the controller API is identical.

What the iframe does

For all three modes, the iframe at app.roxels.ai/embed/<sessionId> is the live runtime. It:

  • Captures the microphone.
  • Plays back agent audio.
  • Maintains the LiveKit room and reconnects on transient drops.
  • Streams events back to the SDK over postMessage.
  • Accepts commands from the SDK over postMessage.

The iframe always emits events and accepts commands, regardless of display mode. This is why the same controller API works for modal, compact, and headless.

Backwards compatibility

Older code uses Roxels.open(...) instead of Roxels.start(...). open() still works — it's a thin shim that calls start() under the hood. New integrations should use start() because the returned controller is more capable than the legacy callback-based API.

  • Install — Add the script to your page, pick your initialization style.
  • Persistent launcher — Configure the floating button: position, visibility rules, view-based show/hide.
  • Display modes — Modal vs compact in more detail.
  • Headless mode — The full guide to running Roxels with your own UI. This is the page to share with engineers building a custom voice experience.
  • JS API reference — Every method, every option.
  • Events — Every event the embed emits.