JavaScript SDK
Identify reporters, attach metadata and open the widget from the site's own code.
Once the snippet is on a page, window.CecFeedback lets the site identify who is leaving feedback,
attach custom metadata, and open the widget from its own buttons. To read or change feedback from
a server or a script, use the REST API instead.
Calling the SDK before the widget loads
The loader is async, so the site's code can run before it does. Put this one-liner above the
snippet. It queues every call, and the widget replays the queue in order once it loads:
<script>window.CecFeedback||(function(p){p.q=[];['identify','setMetadata','open','close','hide','show','on'].forEach(function(m){p[m]=function(){p.q.push([m,[].slice.call(arguments)])}});window.CecFeedback=p})({});</script>
<script async src="https://feedback-api.cec.dev/w/loader.js" data-project="pk_…"></script>While calls are queued they return undefined, so write await CecFeedback.identify(…) rather
than .then(). off only exists once the widget has loaded.
TypeScript types are served at https://feedback-api.cec.dev/w/cec-feedback.d.ts. Save the file
into your project (inside your tsconfig include) and window.CecFeedback is typed everywhere.
Methods
| Call | What it does |
|---|---|
identify({ name, email }) | Remembers who is leaving feedback on this device, so the widget skips its name and email prompt. name is 1–100 characters and email up to 254. Always resolves; problems are reported with console.warn('[cecfb] …'). |
setMetadata(record) | Merges record into the custom metadata sent with every submission. Up to 50 keys of 1–64 characters; each value is a string of up to 500 characters, a finite number or a boolean. null removes a key. |
open(mode?) | Opens a mode: 'pin', 'page', 'video' or 'threads'. Without a mode it opens the first one the launcher offers. |
close() | Closes the feedback form, the mode menu and the feedback panel. |
hide() / show() | Hides and restores the launcher. Console and network capture keep running. |
on(event, callback) / off(event, callback) | Subscribes to the events below. A callback that throws never stops the widget. |
| Event | Payload | Fires when |
|---|---|---|
submitted | { feedbackId, number, kind } | Feedback was created. kind is 'screenshot', 'video' or 'text'. |
opened | { mode } | A mode starts, from the launcher or from open(mode). |
closed | {} | The mode from the last opened ended: sent, cancelled or closed. |
The SDK works in every visibility mode: open() loads
the widget even where it's otherwise hidden, so the site's own "Send feedback" button always works.
Examples
A "Send feedback" button
<button id="send-feedback" type="button">Send feedback</button>document.querySelector('#send-feedback')?.addEventListener('click', () => {
window.CecFeedback.open('page');
});Identify the signed-in user
window.CecFeedback.identify({ name: 'Jane Doe', email: 'jane@example.com' });
window.CecFeedback.setMetadata({ plan: 'pro', accountId: 'acc_123' });On WordPress, the plugin's Identify signed-in users by name and email setting does this without code. See WordPress plugin.
Analytics on submit
window.CecFeedback.on('submitted', ({ feedbackId, number, kind }) => {
window.dataLayer?.push({ event: 'cecfb_feedback_submitted', feedbackId, number, kind });
});Privacy
identify says who a reporter claims to be; it is not a sign-in. CEC uses the email to follow up
and never treats it as a password or uses it to grant access. Send only the metadata the team
needs (a plan or an account ID, not secrets or extra personal data): it's stored with every
submission, and the CEC team can see it.