How does CORS work?
When a script calls fetch() for another origin, the browser adds an Origin header naming the page’s origin, and scripts can’t change it. If the response includes Access-Control-Allow-Origin with that origin, or * for any origin, the script can read the response. If not, the browser blocks it, and the script sees only a generic network error.
A request that goes beyond what an HTML form can send, such as a PUT, PATCH or DELETE, a POST with a JSON body, or one with custom headers, gets a preflight first. The browser sends an OPTIONS request asking whether the method and headers are allowed, and sends the real request only if the server agrees. A plain form-style POST isn’t preflighted, so CORS doesn’t stop another site sending requests that change data. That needs authentication and protection against cross-site request forgery (CSRF).
Only browsers enforce CORS. A server-side script or a command-line tool can send any Origin header it likes, so CORS controls which web pages can read a response, not who can call an API.
Why does CORS matter for a website voice agent?
A voice widget runs in your page but talks to the vendor’s servers, so its requests are cross-origin. The vendor’s server decides which websites may use the widget, usually from a list of allowed origins, and CORS headers carry that decision to the browser.
Origins are exact. https://example.com, https://www.example.com and http://localhost:3000 are three different origins, so every address your site answers on needs its own entry.
How Kawl Now uses CORS and allowed origins
Each agent has its own list of up to 10 allowed origins, each with a scheme, a host, any port and no path. Origins must use HTTPS, except http://localhost and http://127.0.0.1 for local testing.
When a visitor starts a call, the widget asks the server for a one-use call ticket from your page. The browser preflights that request with your page’s origin, and the server returns Access-Control-Allow-Origin with that origin only when it’s on the agent’s list. From any other origin, the browser blocks the request and no call starts.
The widget’s public display settings, such as its button label and colour, are readable from any origin. The management API sends no CORS headers, so call it from server-side code, and the MCP server refuses requests that carry another website’s Origin header.
The origin check relies on the browser’s Origin header, so it controls where conversations can start in a browser but isn’t authentication, and there’s no CAPTCHA or bot protection yet. Customer calls also stay off until you switch them on.
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Content-Type
Vary: OriginCommon questions
Is CORS a security feature?
Partly. CORS relaxes the browser’s same-origin policy in a controlled way, deciding which web pages can read a server’s responses. It doesn’t stop requests from servers, scripts or tools outside a browser, so an API still needs authentication.
Why does an API request work in curl but fail in the browser?
Because only browsers enforce CORS. curl ignores it, while a browser blocks a cross-origin response unless the server sends Access-Control-Allow-Origin for your page’s origin. The browser console shows the specific CORS error, which page scripts can’t see.