# CORS (Cross-Origin Resource Sharing) support for Invoking from the browser

Add CORS headers to invoke Edge Functions from the browser.

To invoke edge functions from the browser, you need to handle [CORS Preflight](https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request) requests.

## Automatic CORS handling

The [`withSupabase`](/docs/guides/functions/auth) wrapper handles CORS and preflight (`OPTIONS`) requests for you, so you don't add headers manually:

```ts index.ts
import { withSupabase } from 'npm:@supabase/server@^1'

export default {
  fetch: withSupabase({ auth: 'user' }, async (req, ctx) => {
    const { name } = await req.json()
    return Response.json({ message: `Hello ${name}!` })
  }),
}
```

## Manual CORS handling

If your function doesn't use `withSupabase`, add the headers yourself. See the [example on GitHub](https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/browser-with-cors/index.ts).

Note: **For `@supabase/supabase-js` v2.95.0 and later:** Import CORS headers directly from the SDK to ensure they stay synchronized with any new headers added to the client libraries.

Import `corsHeaders` from `npm:@supabase/supabase-js@^2/cors` to automatically get all required headers:

```ts index.ts
import { corsHeaders } from 'npm:@supabase/supabase-js@^2/cors'

console.log(`Function "browser-with-cors" up and running!`)

export default {
  fetch: async (req) => {
    // Handle the CORS preflight request.
    if (req.method === 'OPTIONS') {
      return Response.json({ ok: true }, { headers: corsHeaders })
    }

    try {
      const { name } = await req.json()
      return Response.json({ message: `Hello ${name}!` }, { headers: corsHeaders })
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error)
      return Response.json({ error: message }, { status: 400, headers: corsHeaders })
    }
  },
}
```

Importing from the SDK keeps your allow-list aligned with the headers the client libraries send: when you upgrade the SDK version in your function and redeploy, newly added headers are picked up with it. As of `@supabase/supabase-js` v2.112.3 the list includes the trace context headers (`traceparent`, `tracestate`, `baggage`) used by [client-side tracing](/docs/guides/observability/client-side-tracing) — functions deployed with an older version need a redeploy before browsers can call them with trace propagation enabled.

Note: The allow-list only states what a browser *may* send — it doesn't change what the SDK sends. Trace context headers are sent exclusively by clients that explicitly opt in to trace propagation (`tracePropagation: true`, disabled by default). Clients that haven't opted in send exactly the same headers as before.

The full list, and when each header is sent:

| Header                                 | Sent                                                                                                                                           |
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `authorization`                        | Every request (session token or API key)                                                                                                       |
| `apikey`                               | Every request                                                                                                                                  |
| `x-client-info`                        | Every request (SDK name and version)                                                                                                           |
| `content-type`                         | Requests with a body                                                                                                                           |
| `x-retry-count`                        | Only on automatic retry attempts (`postgrest-js` retries failed idempotent requests by default)                                                |
| `traceparent`, `tracestate`, `baggage` | **Only when [trace propagation](/docs/guides/observability/client-side-tracing) is explicitly enabled** — never by default |

### For versions before 2.95.0

If you're using `@supabase/supabase-js` before v2.95.0, you'll need to hardcode the CORS headers. Add a `cors.ts` file within a [`_shared` folder](/docs/guides/functions/development-environment#recommended-project-structure). The list must cover every header your calling clients send — include the trace context headers if any client enables `tracePropagation`:

```ts _shared/cors.ts
export const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers':
    'authorization, x-client-info, apikey, content-type, x-retry-count, traceparent, tracestate, baggage',
  'Access-Control-Allow-Methods': 'GET, POST, PUT, PATCH, DELETE, OPTIONS',
}
```

Then import it in your function:

```ts index.ts
import { corsHeaders } from '../_shared/cors.ts'

// ... rest of your function code
```
