UpVoiced Docs · Widget
Install the feedback widget
The widget puts your boards, roadmap and changelog inside your own site or app: a launcher opens a panel where people vote, post and see what shipped, without leaving the page. It is one script tag, under 20 KB compressed, and it never touches your page’s styles, cookies or storage.
1. Add the script tag
In the dashboard, open Settings → Widget and copy the snippet: it already contains your workspace slug. Paste it before </body> on every page that should show the widget.
<!-- UpVoiced widget: paste before </body> on every page that shows it. -->
<!-- Replace your-slug with your workspace slug (Settings → Widget shows the exact snippet). -->
<script async src="https://cdn.upvoiced.com/w.js" data-workspace="your-slug"></script>
The script is async: it never blocks your page. Launcher, position, colours and tabs come from your settings, so you don’t change the snippet when they change. If you want to call the JavaScript API before the script has loaded, add the queue stub first:
<!-- The queue stub lets you call UpVoiced before w.js has loaded; calls run in order once it has. -->
<script>
window.UpVoiced = window.UpVoiced || { q: [] };
['identify', 'config', 'open', 'close', 'on', 'track'].forEach(function (m) {
window.UpVoiced[m] =
window.UpVoiced[m] ||
function () {
window.UpVoiced.q.push([m].concat([].slice.call(arguments)));
};
});
UpVoiced.on('ready', function () {
document.documentElement.setAttribute('data-feedback-ready', 'yes');
});
</script>
<script async src="https://cdn.upvoiced.com/w.js" data-workspace="your-slug"></script>
Using React, Next.js, Vue, Nuxt, Svelte, Angular, Webflow or WordPress? Seeframeworks and site builders.
2. Allow your site’s origin
For security the widget only lets people sign in, vote and post from sites you list. In Settings → Widget → Allowed origins, add the exact origin of each site: scheme, host and port, as your browser’s address bar shows it before the first /. Only owners and admins can change the list; members see it read-only.
https://app.example.com ✓ exact scheme and host
https://app.example.com:8443 ✓ with a port
http://localhost:3000 ✓ local development (http only for localhost, 127.0.0.1, [::1])
https://*.example.com ✗ no wildcards: add each subdomain
https://example.com/app ✗ no paths
http://app.example.com ✗ plain http- Until you add a site, the widget there still shows your public boards, but signing in, voting and posting are refused. Your own portal (
https://your-slug.upvoiced.com) is always allowed and needs no entry; other UpVoiced addresses can’t be listed. - The dashboard checks each entry with the same rules as the API and saves it in its normal form (lower case, default port and trailing slash removed). Up to 50 origins.
- Removing an origin takes effect at once. Browsers may keep an allowed preflight for up to 10 minutes, but every request is checked again.
- From a site that isn’t listed, the API answers
403 origin_deniedwithout CORS headers, so the browser console shows a CORS error andUpVoiced.identifyresolves{ ok: false, error: "network_error" }.
3. Tabs, launcher and theme
Settings → Widget → Tabs and launcher chooses the tabs (Feedback, Roadmap, What’s new), the launcher (pill, icon or side tab) and its position, with a preview in light and dark. Colours, font and corner radius follow Settings → Brandingand pass the contrast guard. Changes reach visitors within about a minute (the settings are cached briefly). The Roadmap tab shows only while your public roadmap is on.
A page can override the look with attributes on the script tag; anything not listed, or not valid, is ignored. UpVoiced.config() overrides both (API reference).
| Attribute | Values | Example |
|---|---|---|
data-workspace | Your workspace slug. Required. | acme |
data-launcher | icon, pill, tab (a side tab on the edge of the page) or none (no launcher; open the panel from your own button). | pill |
data-position | bottom-right, bottom-left, right-middle or left-middle. | bottom-right |
data-offset | Distance from the edge in px, 0–200: one number for both axes or "x,y". | 16 |
data-theme | light, dark or auto (follows the visitor’s system setting). | auto |
data-accent | A #rrggbb colour. It goes through the same contrast guard as your branding, so text stays readable. | #2f63c4 |
data-radius | none, sm, md, lg or full. | md |
data-mount | A CSS selector. The panel renders inside that element, always open, with no launcher. | #feedback |
data-nonce | Your page’s CSP nonce (see the strict CSP guide). | — |
Inline instead of floating
With data-mount the panel renders inside your element, always open, with no launcher or close button. Useful for a “Feedback” page in your app:
<section id="feedback" aria-label="Feedback"></section>
<script async src="https://cdn.upvoiced.com/w.js" data-workspace="your-slug" data-mount="#feedback"></script>4. Sign people in with your app’s account
Without more setup, visitors confirm their email with a 6-digit code inside the panel the first time they vote or post. If they are already signed in to your app, your server can sign a short-lived token so they never see that step:identify signed-in users.
What the widget does on your page
- Adds one
<uv-widget>element with a Shadow DOM; its styles can’t leak into your page and yours can’t break it. No global CSS, no inline styles on your elements. - Reads no cookies,
localStorageorsessionStorage; a signed-in session lives in memory only. Noeval. - Loads its panel script only when someone opens it. Keyboard and screen-reader accessible (WCAG 2.2 AA), respects reduced motion, in English, Portuguese (Brazil), Spanish, German or French, following your portal language.
- Talks to
https://api.upvoiced.comand loads scripts fromhttps://cdn.upvoiced.com; allow both if your site has a Content Security Policy (strict CSP guide).
Troubleshooting
| Symptom | Check |
|---|---|
| No launcher appears | The slug in data-workspace (the console warns when it is missing or invalid), that the script loads (network tab), and data-launcher="none". |
| People can read but not vote, post or sign in | Add the page’s exact origin under Allowed origins (step 2). |
| A tab is missing | The tab is off in Settings → Widget, the roadmap is not public, or the page narrowed the tabs with UpVoiced.config({ tabs }). |
| Blocked by Content Security Policy | Follow the strict CSP guide. |