---
title: Allowed Origins
description: Control which domains can make browser requests to the Notiflows User API
---

# Allowed Origins

Allowed origins control which domains can make browser requests to the Notiflows User API. When you embed the in-app inbox widget or use a client-side SDK, the browser sends an `Origin` header with each request. Notiflows checks this header against your project's allowed origins list and blocks requests from unlisted domains.

<Callout type="warn">
If no allowed origins are configured, all browser requests to the User API will be blocked. You must add at least one origin before your client-side integration will work.
</Callout>

## How It Works

1. A user visits your app at `https://app.example.com`
2. Your frontend makes a request to the Notiflows User API
3. The browser includes `Origin: https://app.example.com` in the request
4. Notiflows checks the origin against your project's allowed origins
5. If the origin matches, the request proceeds. Otherwise, the browser blocks the response.

Non-browser requests (server-side SDKs, cURL, etc.) don't send an `Origin` header and are not affected by this setting.

## Configuring Allowed Origins

Navigate to your project settings in the Notiflows dashboard:

1. Go to **Projects** → **Settings** → **API Keys**
2. Find the **Allowed Origins** section
3. Enter an origin (e.g., `https://app.example.com`) and click the **+** button
4. Click **Save** to apply

You can add multiple origins for different environments (staging, production, etc.).

## Origin Format

An origin is the combination of scheme, hostname, and port. It must not include a path, query string, or fragment.

### Valid Origins

| Origin | Notes |
|--------|-------|
| `https://app.example.com` | Production domain (HTTPS required) |
| `https://staging.example.com` | Staging domain |
| `http://localhost:3000` | Local development (HTTP allowed) |
| `http://localhost:5173` | Vite dev server |
| `http://127.0.0.1:8000` | Local IP with port |

### Invalid Origins

| Origin | Reason |
|--------|--------|
| `example.com` | Missing protocol (`https://`) |
| `https://app.example.com/dashboard` | Contains a path |
| `http://app.example.com` | HTTP not allowed for non-localhost domains |

### Rules

- **HTTPS required** for all production domains
- **HTTP allowed** only for `localhost` and `127.0.0.1` (development)
- **No paths, query strings, or fragments** — origin only
- **Ports are part of the origin** — `https://example.com` and `https://example.com:8443` are different origins

## Development Setup

For local development, add your dev server's origin:

```
http://localhost:3000
http://localhost:5173
```

These origins use HTTP, which is only permitted for localhost and 127.0.0.1 addresses.

<Callout type="info">
Remember to add your production domain before deploying. A common mistake is to only configure localhost origins and then wonder why the widget doesn't work in production.
</Callout>

## Troubleshooting

### CORS errors in the browser console

If you see errors like `Access to fetch has been blocked by CORS policy`, check that:

1. Your domain is listed in **Settings** → **API Keys** → **Allowed Origins**
2. The origin matches exactly — including protocol and port
3. You've clicked **Save** after adding the origin

### Widget works locally but not in production

Your production domain is likely missing from allowed origins. Add `https://yourdomain.com` (with HTTPS) and save.

### Requests work from Postman/cURL but not the browser

This is expected. Non-browser tools don't enforce CORS. Add your frontend's origin to the allowed origins list.

## Next Steps

- [Client Authentication](/docs/learn/security/client-authentication) — Signing keys and security modes
- [JavaScript SDK](/docs/sdks/client-side/javascript) — Client-side notification integration
- [React SDK](/docs/sdks/client-side/react) — Pre-built React components and hooks
