Widget not appearing? Start here
Open your browser DevTools, go to the Network tab, filter for button.js, and reload. What you see tells you which of three problems you have:
- No
button.jsrequest at all. The widget is vendored or bundled inline — an old manual copy — instead of the CDN package. Switch to@featurefast/react(see the React guide) so it loads the live runtime from the CDN. - The
button.jsrequest fails (red, “Provisional headers are shown”, a CSP issue in DevTools). CSP is blocking it. Add the two directives —script-src https://cdn.featurefast.aiandconnect-src https://<your-deployment>.convex.site. See CSP setup. - It loads but shows the OLD UI.That's the browser cache of the loader. Hard-reload (
Cmd+Shift+R) or try incognito; it self-clears within about 5 minutes.
Anonymous vs authenticated
Marketing and static sites with no login must enable Allow anonymous submissions in Settings and should set Allowed origins. Authenticated apps compute customerHash = HMAC-SHA256(secretKey, customerId) (hex) server-side. Your projectId is public and safe to expose; the secret key (ff_sk_…) is server-only.
Error reference
These are the exact responses from POST /v1/prompts when a submission is rejected.
| Status | Error | What it means |
|---|---|---|
| 404 | Unknown project | The projectIddoesn't exist — check for typos or a stale id. |
| 403 | Origin not allowed for this project | The request origin isn't in Allowed origins. Add it, or leave the list empty to allow any origin. |
| 401 | customerHash is required for this project | Anonymous submissions are off and no hash was sent. Enable anonymous, or pass a customerHash. |
| 401 | Invalid customerHash | The hash didn't verify. Recompute HMAC-SHA256(secretKey, customerId) with the right secret key. |
| 400 | customerId is required when customerHash is provided | You sent a hash without the customerId it was computed from. Send both. |
Note: an empty Allowed origins list means any origin is allowed.
How updates ship & cache
The npm package @featurefast/react is a tiny shell that injects https://cdn.featurefast.ai/button.js — a loader with a 5-minute cache — which in turn loads a content-hashed, immutable runtime. Widget UI changes ship from the CDN and reach every site within about 5 minutes. You do not republish your app or bump the package version to get them.