Guide

Three browser behaviors shape how APIs get used: cookies follow every matching request, CORS blocks reads across origins unless the server allows them, and responses can stream instead of arriving all at once. Each one is a source of confusing bugs if you do not know the rules.

Concept

Before you start: an origin is the scheme, host and port of a URL, such as https://app.example.com. Two URLs with different origins are cross-origin, even if they share a parent domain.

Cookies

The server sets state with Set-Cookie, and the browser sends the cookie back on matching requests:

HTTP
Set-Cookie: session=8f2k...; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=2592000
  • Secure means HTTPS only.
  • HttpOnly hides the cookie from JavaScript, which blunts session theft through XSS.
  • SameSite=Lax stops the cookie from being sent on most cross-site subrequests. This is the main modern defense against CSRF.

Every cookie rides on every matching request. A 4 KB cookie on your static-asset domain adds 4 KB of upload to every image request. Authentication details are covered in authentication and authorization.

CORS

Browsers enforce the same-origin policy. JavaScript on app.example.com cannot read responses from api.other.com unless that server opts in with CORS headers.

For simple requests, such as GET or POST with basic content types, the browser sends the request and checks Access-Control-Allow-Origin on the response. For anything else, such as PUT, a JSON content type or a custom header like Authorization, the browser first sends a preflight OPTIONS request:

The preflight costs a full extra round trip. Access-Control-Max-Age lets the browser cache the preflight result. CORS protects users' browsers. It is not server-side access control. curl ignores it entirely.

Compression

Clients send Accept-Encoding: gzip, br, zstd, and the server picks one and labels it with Content-Encoding. Text compresses well. A 500 KB JSON or JavaScript payload often shrinks to 60 to 100 KB with gzip. Brotli typically saves another 15 to 20% over gzip on text.

Do not compress formats that are already compressed, such as JPEG or video.

Streaming

When the server does not know the body length up front, HTTP/1.1 uses chunked transfer encoding (Transfer-Encoding: chunked). It sends the body in length-prefixed pieces. HTTP/2 and HTTP/3 do not need it, since DATA frames already mark the body's boundaries.

Server-Sent Events (Content-Type: text/event-stream) keep one response open and push data: ... lines as events happen. Most LLM chat APIs stream tokens this way. It is simpler than WebSockets when data flows only from server to client.

WebSockets start as an HTTP/1.1 request with Upgrade: websocket, then turn the connection into a full-duplex message channel. Use them when both sides push messages at low latency, such as chat, collaborative editing or multiplayer.

gRPC runs on HTTP/2, with streams for concurrent and bidirectional calls and Protobuf bodies (see serialization). Because it relies on HTTP/2 trailers, browsers cannot call it directly. That is why gRPC-Web and Connect exist.

For a comparison of these choices, see real-time delivery.

Common mistakes

  • Expecting CORS to protect your API. Any client can send requests that ignore CORS. Use authentication on the server.
  • Sending large cookies to static domains. Every image request carries them.
  • Choosing WebSockets for one-way updates. SSE is simpler and passes through more proxies.

Check yourself

  • Why does a PUT from a browser cost one more round trip than a GET to the same API? The browser sends an OPTIONS preflight first, which waits for a response before the PUT is sent.
  • Why does SameSite=Lax help against CSRF? The browser does not send the cookie on most cross-site requests, so a forged form on another site cannot use the user's session.

Key takeaways

  • Cookies follow every matching request. HttpOnly, Secure and SameSite limit how they can be stolen or misused.
  • CORS is a browser rule for reading cross-origin responses. Non-simple requests add one preflight round trip.
  • Text compresses well. Already-compressed formats do not.
  • Pick the streaming protocol by who sends messages: SSE for server to client, WebSockets for both, gRPC for service-to-service calls.

Further learning

MDN: HTTP documents cookies, CORS and streaming headers in detail.

Revisit requests, methods and status codes for the vocabulary used throughout.