> For the complete documentation index, see [llms.txt](https://lingojs.gitbook.io/lingojs-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lingojs.gitbook.io/lingojs-docs/allowed-domains-and-security.md).

# Allowed Domains & Security

Domain restriction controls which production websites can send translation detection requests to a project.

## Configure allowed domains

1. Open **Dashboard > Project > Project Settings**.
2. Enable **Domain restriction**.
3. Enter a hostname such as `example.com`.
4. Click **Add domain**.

The project's primary domain is always allowed. Pasted URLs are normalized to their hostname before they are saved. Each configured hostname also authorizes all of its subdomains: allowing `example.com` also allows `shop.example.com`.

## Restriction behavior

* **Disabled** — normal Pending detection is accepted from any domain, including local origins; Development Mode is unavailable and auto-publish is unavailable.
* **Enabled with no additional domains** — only the project's primary domain is accepted.
* **Enabled with additional domains** — the primary domain, every listed hostname, and their subdomains are accepted.

{% hint style="warning" %}
Domain restriction is mandatory for both auto-publish modes. Enabling either **Auto-publish Translations** or **Allow auto-publish for selected elements** enables Domain restriction automatically. It cannot be disabled until both auto-publish options are disabled.
{% endhint %}

The server validates the request origin before counting usage. Requests from rejected production domains do not consume project views.

## Verify the snippet installation

From **Dashboard > Project**, click **Check** next to a configured domain.

* **Snippet installed** confirms that the public website contains the current project key.
* **Snippet not found** means the key could not be detected on the public homepage or its same-domain JavaScript bundles.

Use **Check again** after deploying or clearing a website/CDN cache.

{% hint style="info" %}
The installation check is manual and informational. It never enables or disables translations.
{% endhint %}

## Security model

The browser supplies an HTTP `Origin` header that is checked against the primary and additional domains.

An origin allowlist is useful for browser traffic, but it is not a secret: HTTP headers can be forged outside a browser. For this reason, the public project key and an allowed origin are not sufficient to authorize auto-publishing.

Production auto-publish additionally requires a short-lived Turnstile-backed snippet session. When domain restriction is enabled, local development uses a named development token instead.

## Content Security Policy

With a strict Content Security Policy, account for every resource used by your installation:

* allow the snippet host, such as `https://cdn.jsdelivr.net`, in `script-src`;
* allow `https://api.lingojs.com` in `connect-src`;
* allow your inline initialization script with a nonce or hash;
* if the widget is enabled, allow its injected styles according to your `style-src` policy;
* when either auto-publish mode is enabled, allow `https://challenges.cloudflare.com` in both `script-src` and `frame-src`.

The exact directive depends on where you host the snippet and how your site authorizes inline scripts and styles. For example, the Turnstile origin is:

```
https://challenges.cloudflare.com
```

Websites using only the normal Pending workflow do not load Turnstile.
