Collective Vision

Embedding the Widget

Drop a single script tag onto any website; multi-tenant and anonymous-first.

The feedback widget is a single <script> tag you drop into any website. It is multi-tenant and anonymous-first — it is not limited to one admin user, and any number of unrelated sites can embed it independently.

Quick start

<script
  src="https://feedback-dev.jfcreations.com/widget.js"
  data-workspace="demo-workspace"
  data-board="main"
></script>

Drop that on any page (your site, a client's site, a CodePen — anywhere). On the first hit the workspace and board are auto-provisioned, so there's no API call or signup required to start collecting feedback.

Script tag options

AttributeRequiredMeaning
data-workspaceyesTenant slug. Pick one per site/product. Auto-created on first use.
data-boardyesSurface within the workspace (e.g. main, feature-requests). Auto-created.
data-api-basenoOverride the API origin. Defaults to the script's own origin (so you usually omit it).

Multi-tenancy — answering "is it only my single admin user?"

No. There are three independent layers:

  1. Workspaces = tenants. Each embedding site uses its own data-workspace; rows are isolated by workspace_id and never bleed across tenants. Embed the script on 50 different sites with 50 different data-workspace values and you get 50 isolated boards.
  2. End-users = the people on the embedding site. They are anonymous-first: the widget mints an anon_ id (with a random suffix) into localStorage (cv_uid) so visitors can submit and vote without an account. (You can pass a real externalUserId when posting via the API to tie feedback to your own logged-in users.)
  3. Admins = you (the operator). Admin auth (ADMIN_API_TOKEN / sessions) is only for the moderation/dashboard side. It has nothing to do with who can use an embedded widget.

So: anyone on any embedding site can submit/vote anonymously; you (admin) moderate. One deployment serves unlimited tenants.

Embedding on a third-party site

It just works cross-origin — the API mirrors the request Origin and sets permissive CORS (Access-Control-Allow-Credentials: true), because the widget is designed to live on arbitrary domains. A partner can paste:

<script
  src="https://feedback-dev.jfcreations.com/widget.js"
  data-workspace="acme-corp"
  data-board="product"
></script>

…and acme-corp/product is provisioned for them, fully isolated from yours.

Calling the API directly (no widget)

The same public endpoints back the widget, so you can build a custom UI:

# List approved, visible feedback
curl https://feedback-dev.jfcreations.com/api/v1/acme-corp/product/feedback

# Submit
curl -X POST https://feedback-dev.jfcreations.com/api/v1/acme-corp/product/feedback \
  -H 'Content-Type: application/json' \
  -d '{"title":"Add SSO","description":"We need Okta","externalUserId":"user-123"}'

# Upvote
curl -X POST https://feedback-dev.jfcreations.com/api/v1/acme-corp/product/feedback/42/votes \
  -H 'Content-Type: application/json' \
  -d '{"externalUserId":"user-123"}'

# Comment (note: field is "content")
curl -X POST https://feedback-dev.jfcreations.com/api/v1/acme-corp/product/feedback/42/comments \
  -H 'Content-Type: application/json' \
  -d '{"content":"+1, blocking our rollout","externalUserId":"user-123"}'

Moderation behaviour (important when opening to the public)

Sourcemoderation_stateVisible immediately?
widgetapprovedyes (auto-approved)
api / mcp / importpendingno (is_hidden=1, awaits review)

Widget submissions auto-approve — convenient for trusted embeds, risky for open-internet pages (spam). Before exposing a widget to anonymous traffic at scale, decide whether to flip widget submissions to pending and rely on the rate-limit middleware on write paths.

Production note

Replace feedback-dev.jfcreations.com with your production worker hostname when you cut a staging/production deploy. The data-api-base attribute lets a single copy of the snippet target different environments without changing the bundled script.

On this page