Install the snippet
Add the widget to any site with one script tag, and control where and to whom it shows.
This page is for the developer of a site that CEC reviews with CEC Feedback. Each project's
Installation tab in the dashboard shows the snippet with the project key filled in, so copy it
from there. In the examples, pk_… stands for that key.
Add the snippet
Paste this into the <head> of every page that should get the widget:
<script async src="https://feedback-api.cec.dev/w/loader.js" data-project="pk_…"></script>- It stays out of the way. The loader is small, loads
async, and fetches the rest of the widget only when the widget is shown. It adds no layout shift. - It updates itself. This is the evergreen loader: it picks up fixes automatically and is cached for 5 minutes.
- The first load verifies the installation. The Installation tab switches to "Installation verified" once the widget has loaded on the site.
Pinning a version with Subresource Integrity
Sites that require SRI can pin a loader version instead. The hash of each loader is published at
https://feedback-api.cec.dev/w/sri.json:
{ "loader.js": "sha384-…", "loader.1.2.0.js": "sha384-…" }Use the versioned file and its hash. crossorigin="anonymous" is required, because browsers only
check integrity on a CORS request:
<script
async
src="https://feedback-api.cec.dev/w/loader.1.2.0.js"
integrity="sha384-…"
crossorigin="anonymous"
data-project="pk_…"
></script>A pinned loader always loads the same code, so it doesn't get fixes until you move to a newer version.
Allowed origins
Settings › General › Allowed origins decides which sites the widget may load on.
| Allowed origins | The widget loads on… |
|---|---|
| Empty (the default for new projects) | Any website. |
| One or more entries | Only those sites. |
An entry is an exact origin such as https://client.example.com, or *.example.com for any https
subdomain of example.com. www., a port, or http instead of https each make a different
origin. Elsewhere the widget doesn't appear, and its requests are refused with
403 origin_not_allowed.
When to restrict
The project key is visible in the page source. With no allowed origins, anyone who copies it can show the widget, and send feedback to the project, from their own site. Add origins once you know which sites the project covers.
Who sees the widget
Settings › Widget › Visibility picks one of three modes:
| Mode | The widget shows… |
|---|---|
| Show widget to everyone | To every visitor. |
| Only show widget to members | Only to CEC team members who have signed in from the widget. Open the page once with ?cecfb=1 to get the locked widget and its Sign in as team member button. |
| Show widget with secret query parameter | Only after a visit with ?cecfb=<secret key>, for example https://client.example.com/?cecfb=k3y…. The widget then stays on for the rest of that browser tab's session. The key is on the same settings page, and regenerating it stops old links from working. |
Two things show the widget in every mode:
?cecfb_id=<feedback id>opens that feedback item. Links from the dashboard, emails and integrations use it.window.CecFeedback.open()from the site's own code (see the JavaScript SDK).
Changes to the visibility mode reach visitors within a few minutes, because the widget caches its settings.
Keeping data out of screenshots
Screenshots show what the reporter sees, so mark sensitive content before the site goes live:
| Attribute | Effect in screenshots |
|---|---|
data-cecfb-mask | The element is painted over with a solid grey box. Password inputs are always masked, with or without it. |
data-cecfb-ignore | The element is hidden, as if it had visibility: hidden. |
<div class="account-balance" data-cecfb-mask>£12,345.67</div>
<aside class="chat-widget" data-cecfb-ignore>…</aside>Reporters can also black out parts of the page themselves. See Security and privacy.
Content Security Policy
If the site sends a CSP header, add these sources and keep everything else as it is:
| Directive | Add | Why |
|---|---|---|
script-src | https://feedback-api.cec.dev | The loader and the rest of the widget. |
connect-src | https://feedback-api.cec.dev, plus 'self' if the policy doesn't already allow it | The widget's API calls and uploads. Screenshots also fetch the page's own stylesheets, fonts and images. |
img-src | https://feedback-api.cec.dev data: blob: | Screenshot previews, thumbnails and the theme logo. |
media-src | blob: | Playing back a screen recording before it's sent. |
style-src needs no change: the widget styles itself inside its own shadow root.
Member sign-in opens a window on https://feedback.cec.dev that sends a token back to the page.
The header Cross-Origin-Opener-Policy: same-origin cuts that link and breaks sign-in. Use
same-origin-allow-popups, or leave the header unset.
What the widget stores in the browser
The widget sets no cookies. It keeps a few localStorage entries on the site, all starting with
cecfb:: its cached settings (5 minutes), the reporter's name, email and token, a signed-in
member's token, where the launcher was dragged to, whether the welcome popup was dismissed, and an
unsent draft. An accepted ?cecfb secret is kept in sessionStorage, so it ends with the tab.
Troubleshooting
Open the browser's developer tools and filter the console and network tabs for cecfb or
feedback-api.
| Symptom | Likely cause | Fix |
|---|---|---|
GET /v1/widget/config answers 403 origin_not_allowed | The project has allowed origins, and this page's origin isn't one of them. | Add the exact origin (the request's Origin header) under Settings › General, or empty the list. |
GET /v1/widget/config answers 404 not_found | The data-project key is wrong, the key was rotated, or the project is archived. | Copy a fresh snippet from the Installation tab. |
No request for /w/loader.js at all | The snippet isn't on the page (page cache, tag manager, theme override), or the CSP blocks it. | View the page source and check the console for a CSP error. |
| The loader loads but no widget shows | Visibility is "members only" or "secret query parameter". | Open the page with ?cecfb=<secret key>, sign in as a team member, or call CecFeedback.open(). |
| A settings change doesn't show | The widget caches its settings for up to 5 minutes. | Wait, or clear the cecfb:cfg: entry from localStorage. |
| Sign in as team member opens and closes, but nothing changes | The page sends Cross-Origin-Opener-Policy: same-origin. | See Content Security Policy. |
| The SRI loader fails with "Failed to find a valid digest" | The hash doesn't match the version, or crossorigin="anonymous" is missing. | Copy both again from https://feedback-api.cec.dev/w/sri.json. |
Still stuck? Send CEC the page URL, the browser and its version, and the x-request-id response
header of the failing request.
Rotating the project key
Installation › Rotate key issues a new project key. The old snippet stops working immediately, and the widget disappears from every site that still uses it, so every site needs the new snippet (or the new key, for the WordPress plugin). Rotate the key only when you need to cut off an old copy of it.