CORS errors
The widget calls our API from the visitor’s browser. Our API rejects any request whose Origin header doesn’t match the domain you registered for this site_id. This is deliberate — it prevents your <script> tag from being stolen and used on someone else’s site.
The error you see
In DevTools → Console:
Access to fetch at 'https://api.spelo.ai/v1/ab1c2d3e/token' from origin 'https://example.com'has been blocked by CORS policy: Response to preflight request doesn't pass access control check:No 'Access-Control-Allow-Origin' header is present on the requested resource.This means: you tried to use the widget from https://example.com, but that domain isn’t registered for this site_id.
Fix
-
Check the Origin
In DevTools → Network → click the failing request → Headers. The Origin header shows the exact domain your browser is using.
-
Check the registered domains
Dashboard → Site detail → Domains. You’ll see a list like:
example.comwww.example.com -
Is your Origin in that list?
Must match exactly (protocol optional). Pitfalls:
www.vs. nowww.— these are different domains. Register both.- Subdomains —
app.example.comis distinct fromexample.com. Register or use a wildcard. - Different TLDs — staging on
example.dev, prod onexample.com, preview deploys onexample.vercel.app— all different.
-
Add the missing domain
Dashboard → Site detail → Domains → Add domain → save.
Changes take effect within ~60 seconds (cache TTL).
-
Reload the site
Hard reload (Cmd-Shift-R / Ctrl-Shift-R) to pick up the new CORS config.
Wildcards
You can register *.example.com to cover all subdomains. This does not cover the apex — register example.com separately if you use it.
Wildcards only cover one level: *.example.com matches app.example.com but not foo.app.example.com.
Common cases
Vercel / Netlify preview deploys
Every PR gets a unique URL like my-app-git-feature-foo-userid.vercel.app. Options:
- Register the production domain only; preview deploys won’t show the orb (safest for prod correctness)
- Register
*.vercel.app(too broad — don’t, every Vercel customer’s preview would match) - Register a specific preview URL per PR (tedious)
- Use separate site_ids for prod and preview (recommended for serious setups)
www vs. apex
A common setup is:
- Apex
example.com→ redirects towww.example.com
Register both domains. The redirect happens before the widget loads, but once the browser is on www., it stays there and widget requests come from www.example.com.
Reverse proxy / custom domain
If you front our widget CDN through your own domain (e.g. widget.example.com → spelo.ai), register example.com (the page loading the script) as the domain. The spelo.js host doesn’t matter for CORS; the API call Origin is what we check.
Localhost during dev
http://localhost:3000, http://localhost:5173, http://127.0.0.1:3000 all work without registration — we always allow localhost. No config needed.
Dashboard / marketing site CORS
If you see CORS errors on app.spelo.ai or docs.spelo.ai (our sites, not yours), that’s a bug on our side — please email support. Our own CORS is configured separately from customer CORS.
Preflight caching
Browsers cache successful CORS preflights for up to 24 hours. If you registered a new domain but still see CORS errors briefly, that’s just the preflight cache — it resolves itself within seconds once you make a fresh request.
Why wildcards aren’t the default
We don’t set Access-Control-Allow-Origin: * because it would undermine the purpose — anyone on any domain could use your site_id. Multi-tenancy security requires per-site origin validation.