Widget install & API
The widget is one <script> snippet. It defines a global command function, injects
a small loader from a stable URL, and mounts the core on demand.
Install
Paste this just before </head>, swapping lh_site_YOUR_KEY for your site's
publishable key (safe to expose — it only permits submitting feedback):
<script>!function(w,d){w.luuphub=w.luuphub||function(){(w.luuphub.q=w.luuphub.q||[]).push(arguments)};var s=d.createElement('script');s.async=1;s.src="https://w.luuphub.com/loader.js";s.setAttribute('data-lh-site',"lh_site_YOUR_KEY");d.head.appendChild(s)}(window,document);</script>
How it works
The snippet defines window.luuphub as a queue stub — the classic
analytics-style pattern. Any command you call before the core finishes loading is
pushed onto window.luuphub.q and replayed once the core mounts, so a call
on a cold page is never dropped. The injected loader reads its own tag's
attributes:
data-lh-site(required) — your publishablelh_site_…key.data-lh-api(optional) — override the API origin (self-hosting / staging).
Commands
Call the global with a command name and optional argument:
// Open the widget panel (e.g. from your own "Feedback" button).
luuphub('open');
// Close it.
luuphub('close');
// Attach a signed identity (see the Identify & SSO recipe).
luuphub('identify', { userId: 'u_123', email: 'a@b.com', auth: signedToken });
// Clear identity on logout.
luuphub('reset');
| Command | Argument | Effect |
|---|---|---|
open |
— | Opens the feedback panel. |
close |
— | Closes the panel. |
identify |
{ userId?, email?, auth } |
Associates submissions with a signed user. |
reset |
— | Forgets the current identity (call on logout). |
Single-page apps
The widget tracks client-side navigation automatically (history + a
lh:navigation event), so route changes in a SPA are captured with the correct
page context — no manual re-init.
Next
- Identify & SSO — sign identity server-side.
- Theming contract — brand the widget.