demoloop-widget
v1.0.0
Published
Embed Demoloop experiences and connect product context, events, modules, and safe host actions.
Maintainers
Readme
demoloop-widget
Embed Demoloop in a web product and give the hosted experience structured context without granting arbitrary access to the host page.
Install
npm install demoloop-widgetimport { init, identify, setContext, registerAction, setModules } from "demoloop-widget";
await init({ key: "dl_xxx" });
identify({ id: "user_123", email: "[email protected]", company: "Acme" });
setContext({
productName: "Client Portal",
section: "Analytics",
software: {
tenant: "Acme Enterprise",
screens: [{ label: "Visitors", path: "/app?tab=visitors" }],
},
});
registerAction("open-visitors", "/app?tab=visitors");
registerAction("open-report", async (request, { signal }) => {
const reportId = String(request.payload?.reportId || "");
if (!reportId) return false;
await openReport(reportId, { signal });
return { reportId };
});
setModules([
{ id: "product-demo", label: "Explore the product", experience: "demo", presentation: "modal" },
{ id: "solutions", label: "Talk to solutions", experience: "assistant", presentation: "popup" },
]);The script-loader form remains supported:
<script src="https://getdemoloop.com/widget.js" data-key="dl_xxx" async></script>API
init(options)validates the widget key and host domain and resolves when ready.open({ module?, experience?, presentation? })opens a configured experience.identify(user),setContext(context), andtrack(name, properties)synchronize runtime context.registerAction(name, handler)andsetActions(actions)expose explicit host capabilities.setModules(modules)advertises independently launchable experiences, including future channels such as video calls.on(event, listener)returns an unsubscribe function. Browser events remain available asdemoloop:<event>custom events.getState(),close(), anddestroy()support SPA lifecycle management.
Action handlers receive an AbortSignal. Requests are bounded to 1–30 seconds, return structured success/error results, and are cancelled when the hosted experience stops waiting. String navigation handlers are restricted to the current host origin.
React
import { DemoloopProvider, useDemoloop } from "demoloop-widget/react";
function App() {
return (
<DemoloopProvider options={{ key: "dl_xxx" }}>
<DemoButton />
</DemoloopProvider>
);
}
function DemoButton() {
const demoloop = useDemoloop();
return <button disabled={!demoloop.ready} onClick={() => demoloop.open()}>See it live</button>;
}Protocol and security
The widget and hosted demo communicate with the versioned 1.0 protocol. Messages use exact target origins, stale context revisions are ignored, action names are allow-listed by the host, and nested context is sanitized before being persisted with a demo session. API keys and server credentials must never be placed in SDK context or metadata.
