Docs

Everything needed to install the widget and, if you want, talk to it from your own code. Most sites only need the first section.

Install

Paste this before the closing </body> tag on every page where you want the widget. Replace the key with the one from your project page in the dashboard.

<script
  src="https://feedoback.com/widget.js"
  data-project="pk_your_project_key"
  async
></script>

The script is async, so it never blocks your page. A round launcher appears in the bottom-right corner once it has loaded.

Check it works

Open your site. You should see the launcher. In the dashboard, the project page switches from Waiting for the first visit to Live the moment the widget loads anywhere on an allowed domain. If it does not appear, open the browser console: the widget prints one line saying why it removed itself.

Allowed domains

A project can be locked to the domains you list. The browser attaches the page’s origin to every request and a page cannot forge it, so the widget refuses to run anywhere else. Use *.example.com to allow every subdomain. Leave the list empty while developing and the widget runs anywhere, including localhost.

What visitors can do

  • Point & comment. They click an element, and a comment box opens beside it with the element outlined. A screenshot of the visible page is attached automatically.
  • Record screen. They share a tab or window and talk through it. Up to five minutes, with pause and preview before sending.
  • Send feedback. Plain text with an optional email so you can reply, and one to five stars if you ask for them.

Every submission files under the page it was sent from, with the viewport, browser, language and time zone. Visitors never see anyone else’s comments.

Appearance

The Widget section of a project sets the launcher’s colour, size and corner, a light or dark panel, a greeting shown above the menu, and whether the feedback form opens with a star rating. Changes reach every page on the next load; nothing in the snippet changes. Text on the launcher picks black or white by itself, so any colour stays readable.

Versions

Add data-version to the snippet with whatever names a release for you, and every thread records it. Each page grows a version filter as soon as one arrives, which is how you tell feedback about last week’s build from feedback about today’s.

<script src="…/widget.js" data-project="pk_…" data-version="2.8.1" async></script>

Stable targets

When a visitor points at an element, the widget records the most stable way it can find to identify it: a data-feedback-id if you set one, then data-testid, a stable id, an aria-label, a role, and finally a short CSS path. Framework-generated ids are ignored. If you want reports about an element to survive redesigns, give it a feedback id:

<button data-feedback-id="checkout-pay">Pay now</button>

SDK

The snippet exposes window.Feedoback. You do not need it for the widget to work; it is there for when you want to open it from your own button or tell it who the visitor is. This is the web widget’s; an app SDK has its own four calls.

MethodWhat it does
open()Open the panel.
close()Close the panel.
toggle()Open it if closed, close it if open.
startFeedback()Start the element picker, as if the visitor chose Point & comment.
startRecording()Open the panel on the screen recording step.
identify(visitor)Attach who the visitor is: { id, email, name }. Any field is optional.
setContext(context)Attach up to 30 flat key–value pairs of your own: plan, version, account.
destroy()Remove the widget from the page entirely.

Identify the visitor

Call this once your app knows who is signed in. It is shown in the dashboard next to their messages so you can reply. It is never used to decide what anyone may see.

Feedoback.identify({
  id: "usr_4821",
  email: "[email protected]",
  name: "Marina Vega",
});

Feedoback.setContext({
  plan: "pro",
  appVersion: "2.8.1",
});

Calling before the script has loaded

Because the script is async, your code may run first. Queue calls and the widget replays them when it boots:

window.Feedoback = { q: [] };
window.Feedoback.q.push(["identify", { id: "usr_4821" }]);

Roll out gradually

A project can show the launcher to everyone, or only to visitors you allow. Identify visitors from your app as above; each one appears in the project’s widget section as your site names them. Under Who sees it, choose Change, pick Only listed visitors, allow the people who should see it, or add someone by id or email before they visit. Everyone else gets nothing, not even the launcher, until you switch back to everyone.

The launcher stays hidden until you identify an allowed visitor, so call identify() as soon as your app knows who is signed in. On a server-rendered page that means queuing it before the script (above). In a single-page app, call it from wherever your session loads — the widget re-checks when you name someone, so a call that lands after the page is up still shows the launcher.

This is for trying the widget with your own team or a few friendly customers first. It is not a lock: the identity comes from your page, so treat it as a rollout switch rather than a way to hide the widget from a determined visitor.

Single-page apps

The widget survives client-side navigation and reads the current URL each time something is sent. If your app re-runs the snippet on a route change, nothing happens: a second copy is ignored. To remove the widget, for example when a user signs out, call Feedoback.destroy().

Mobile apps

The same project takes feedback from an app. There is one key, one feedback area and one set of pages: a screen route and a page path that mean the same thing land together, so an app and the site it belongs to read as one product. Four packages, none of which has a dependency of its own:

  • feedoback-ios — Swift, iOS 15+
  • com.feedoback:feedoback-android — Kotlin, minSdk 24
  • feedoback-react-native — a Turbo Module over both
  • feedoback_flutter — platform channels over both

All four say the same four things. start once at launch, present from a control your app already owns — a Settings row, a menu item — identify when you know who someone is, and setScreen so feedback is filed under the screen it came from. A floating launcher is there if you want one and off if you do not, because most apps already have a place for this. The install screen inside Feedoback has the exact code for your stack, with your key in it.

Turn it on first

A site proves where it is running by the origin the browser sends, which a page cannot forge. An app has no equivalent: a bundle id is only what the app says about itself. So mobile is off until you turn it on, and you turn it on by naming the apps the key ships in, under Mobile apps on the project. Until then the SDK stays dormant, draws nothing and prints one line saying why.

You also choose who may send: anyone using the app, only visitors it has identified, or only people you allowed by name. The middle one is the default, because a signed-in person is one you can already find, warn and block.

Screenshots

Every message carries a picture of the screen, and the visitor sees it before it goes and can take it off — nothing is sent that the person looking at it did not look at first. Secure text fields are painted over without being marked; anything else sensitive you mark yourself with redact, or a FeedobackRedact wrapper in React Native and Flutter. In Flutter the wrapper is the whole of it: Flutter draws its own text, including the dots in an obscured field, so there is no native field to find.

What the app sends

What you hand it, plus what any app can read about itself: the message, the rating, the screenshot the visitor kept, your bundle id and version, the device model, OS version, locale, time zone, screen size and orientation, and a random install id that dies with the app. Not the advertising identifier, the vendor identifier, location, contacts, crashes or network traffic. Nothing is swizzled and nothing is intercepted — an SDK that reaches for those is one a security review rejects.

Content Security Policy

If your site sends a CSP header, allow the Feedoback origin in three places:

script-src  https://feedoback.com;
connect-src https://feedoback.com;
img-src     data: blob:;

The widget styles itself with constructed stylesheets, so it needs no 'unsafe-inline' in style-src. Screen recording uses the browser’s own permission prompt and needs nothing from you, unless your page is itself inside an iframe, in which case that frame needs allow="display-capture".

Privacy

The widget sets no cookies and sends nothing until a visitor presses send. What it collects is listed on the security page; how it is handled is in the privacy policy. If your visitors are in a jurisdiction that requires notice for feedback tools, mention Feedoback in your own privacy policy.