Add the VoteMate Widget to Your Website

Embed the VoteMate voting-information assistant on your site by pasting a single <script> tag. The loader adds a launcher (or an inline panel) that opens the full VoteMate assistant in a sandboxed iframe. It runs alongside your page without touching your styles, globals, or framework — and streams answers securely through your partner subscription.

This page is everything you need to go live: onboarding, the embed snippet, the full configuration reference, security model, and troubleshooting.

What you get

A single <script> tag renders the full VoteMate app inside a sandboxed iframe on your page — as a floating launcher (a button in a corner that opens a chat panel) or an inline panel (mounted directly in your page flow). The widget:

  • Runs guest-only — no VoteMate account is required to use it.

  • Streams answers through VoteMate's partners API, authenticated by your subscription key.

  • Is isolated — because it renders in an iframe, it never inherits or affects your CSS, JavaScript, or framework.

Before you start: onboarding & approval

Partner access is granted manually so that every embedding organization is reviewed before it can reach the backend.

  1. Request access and get approved. A prospective partner requests access and is reviewed manually. Approval is a deliberate gate, completed before any credential is issued. Once approved, your organization is registered and activated.

  2. Receive your subscription key. On approval, you receive one Azure API Management (APIM) subscription key scoped to the VoteMate partners product. That product exposes only the chat streaming and ballot-lookup endpoints, so a partner key cannot reach first-party routes. Retrieve the key from the APIM developer portal.

  3. Register your domains. Provide every origin that will host the widget (for example https://www.example.org and https://example.org). The backend authorizes requests by matching the browser Origin (or Referer) against this list. Register all production and staging hosts before going live — requests from an unregistered origin receive an HTTP 403.

  4. Paste the snippet. Add the tag below (replace YOUR_SUBSCRIPTION_KEY), just before your closing </body> tag.

  5. Allow the origin in your CSP if your site sends a Content Security Policy (see the Content Security Policy section below).

Quick start

Paste this just before the closing </body> tag and replace YOUR_SUBSCRIPTION_KEY with the key issued to your organization:

<script src="https://widget-dev.votemate.io/v1/widget.js" data-widget-url="https://widget-dev.votemate.io/v1/app/" data-subscription-key="YOUR_SUBSCRIPTION_KEY" data-mode="floating" data-position="bottom-right" data-theme="light" data-locale="en"></script>

That is the entire integration. The launcher appears in the corner you choose, and the chat panel opens on click.

Use the environment-appropriate host: widget.votemate.io for production, widget-<env>.votemate.io for non-prod. The data-widget-url must point at the same host's /v1/app/.

Embed shapes

The loader supports two shapes, selected by data-mode.

Floating (default) — a launcher button in a corner that toggles a panel:

<script src="https://widget-dev.votemate.io/v1/widget.js" data-widget-url="https://widget-dev.votemate.io/v1/app/" data-subscription-key="YOUR_SUBSCRIPTION_KEY" data-mode="floating" data-position="bottom-right" data-theme="light" data-locale="en"></script>

Inline — mounts the iframe directly into a target element, in the page flow:

<div id="votemate"></div>
<script src="https://widget-dev.votemate.io/v1/widget.js" data-widget-url="https://widget-dev.votemate.io/v1/app/" data-subscription-key="YOUR_SUBSCRIPTION_KEY" data-mode="inline" data-target="#votemate" data-height="760" data-theme="light" data-locale="en"></script>

Configuration reference

All options are passed as data-* attributes on the script tag.

  • data-widget-urlRequired. Absolute URL of the hosted widget app the iframe loads (the same host's /v1/app/).

  • data-subscription-keyRequired. Your APIM subscription key. Forwarded to the app as the key query parameter.

  • data-modeOptional, default floating. Embed shape. Accepts floating or inline.

  • data-positionOptional, default bottom-right. Launcher corner (floating only). Accepts bottom-right or bottom-left.

  • data-themeOptional, default light. Color theme. Accepts light or dark.

  • data-localeOptional, default en. UI language. Accepts en (English) or es (Spanish).

  • data-targetRequired for inline mode. CSS selector of the element to mount into (inline only), e.g. #votemate.

  • data-heightOptional, default 760. Iframe height in pixels (inline only).

The loader forwards data-subscription-key, data-theme, and data-locale to the widget app as key, theme, and locale query parameters on the iframe URL.

Positioning (floating)

data-position="bottom-right" anchors the launcher and panel to the right edge; data-position="bottom-left" anchors them to the left. The launcher is a 56px circle fixed 20px from the bottom and chosen side. The panel opens at 380px wide by 600px tall and shrinks to fit small viewports.

Theme and locale

Set data-theme to light or dark to match your site. Set data-locale to en for English or es for Spanish. Both are forwarded to the app on load.

How it works

The widget is delivered from a content delivery network as static files. Your page loads one small loader script (widget.js), which creates the sandboxed iframe pointing at the hosted VoteMate app (/v1/app/). Everything dynamic — the chat itself — leaves the CDN and streams through the VoteMate partners API (Azure API Management → VoteMate backend), authenticated by your subscription key and gated by the origin check described below.

  1. Your page loads the loader script from the VoteMate CDN: https://widget-dev.votemate.io/v1/widget.js.

  2. The loader creates a sandboxed iframe pointing at the hosted app: https://widget-dev.votemate.io/v1/app/.

  3. When a user chats, the request goes to APIM, authenticated with your subscription key.

  4. APIM validates the subscription, then forwards the request to the VoteMate backend.

  5. The backend re-checks your subscription and the request origin, then streams the answer back into the iframe.

You host nothing of ours except that one <script> tag.

Getting a subscription key

The widget reaches the VoteMate backend through Azure API Management (APIM). Each partner receives one subscription key scoped to the VoteMate partners product, which exposes only the chat and ballot-lookup endpoints.

  1. Complete partner onboarding and approval (see the Before you start section above).

  2. Once approved, retrieve your subscription key from the APIM developer portal.

  3. Register the domains that will embed the widget (see below) so requests from your site are accepted.

Register your domains

The backend authorizes requests by matching the browser Origin (or Referer) against the list of domains registered for your subscription. Provide every origin that will host the widget, for example https://www.example.org and https://example.org. Requests from an unregistered origin receive an HTTP 403 response, so register all production and staging hosts before going live.

Each partner record stores an allowed_domains list alongside its subscription id, organization name, status, theme, and locale. On every gated request the backend authorizes the call only when:

  • a partner record exists for the forwarded subscription id,

  • the partner status is active, and

  • the request origin matches an entry in the registered allowed_domains.

Any failed check returns an opaque HTTP 403, which keeps the gate from revealing whether a given subscription id or origin is known.

Content Security Policy

If your site sends a Content Security Policy, allow the widget origin so the loader script and chat iframe load:

Content-Security-Policy: script-src 'self' https://widget-dev.votemate.io; frame-src https://widget-dev.votemate.io;

script-src permits loading widget.js, and frame-src permits the chat iframe. The chat stream runs inside that iframe and connects to the VoteMate partners host under VoteMate's own origin and policy, so your page does not need a connect-src entry for it.

How your subscription key is protected

The subscription key is a publishable identifier used for quota and telemetry, not a private authentication secret. It is expected to appear in your page source. Abuse is contained by several backend controls rather than by hiding the key:

  • APIM enforces a per-key rate limit (60 requests per minute).

  • APIM enforces a per-key daily quota (10,000 requests per day).

  • The backend validates the request Origin/Referer against your registered domains and rejects mismatches with an HTTP 403.

  • CORS restricts which sites may read responses in the browser.

Because of the origin check, a copied key only works from domains you have registered. Treat the key as public, and contact VoteMate to rotate it if you need to retire a domain.

Sign-in behavior

The embedded widget is guest-only. When a user clicks Sign In, it opens the full VoteMate app in a new tab (first-party authentication), rather than authenticating inside the iframe.

Versioning

The loader is served from a versioned path (/v1/widget.js). Backward-compatible changes ship under the same major version. Breaking changes ship under a new major path, and migration guidance accompanies each one.

Troubleshooting

  • The launcher does not appear — confirm data-widget-url is an absolute URL and that widget.js loaded (check the browser network tab and console).

  • Nothing renders (inline) — the data-target element does not exist on the page when the loader runs; check the selector and that the container is present.

  • Requests return 403 — the embedding origin is not registered for your subscription, or your partner status is not yet active. Register the exact origin(s) and confirm activation.

  • Requests return 404 — the partners API base URL is missing its version segment. It must include /partners/v1, not a bare /partners.

  • Requests return 429 — you have exceeded the rate limit or daily quota; retry after the window resets, or contact VoteMate to discuss higher limits.

  • Styles look off — the widget renders inside an iframe and does not inherit your CSS, so the usual cause is a CSP directive blocking frame-src. Allow the widget origin (see the Content Security Policy section above).

Need help?

Contact VoteMate to request access, register or retire a domain, rotate a key, or discuss higher rate limits.