Skip to content
GitHub
Get started →

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

  1. Check the Origin

    In DevTools → Network → click the failing request → Headers. The Origin header shows the exact domain your browser is using.

  2. Check the registered domains

    Dashboard → Site detail → Domains. You’ll see a list like:

    example.com
    www.example.com
  3. Is your Origin in that list?

    Must match exactly (protocol optional). Pitfalls:

    • www. vs. no www. — these are different domains. Register both.
    • Subdomains — app.example.com is distinct from example.com. Register or use a wildcard.
    • Different TLDs — staging on example.dev, prod on example.com, preview deploys on example.vercel.app — all different.
  4. Add the missing domain

    Dashboard → Site detail → DomainsAdd domain → save.

    Changes take effect within ~60 seconds (cache TTL).

  5. 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 to www.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.comspelo.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.

See also