# Custom Domains (https://eulabel.eu/docs/knowledge-base/guides/custom-domains)

> Fetch the complete documentation index at: https://eulabel.eu/docs/llms.txt
> Use this file to discover all available pages before exploring further.
> Full content: https://eulabel.eu/docs/llms-full.txt
> Append .md to any page URL for markdown, or send Accept: text/markdown.



By default, QR codes resolve through `eulabel.eu`. With custom domains, your products resolve through your own branded URL (e.g., `labels.yourbrand.com`).

At a glance [#at-a-glance]

* Bring-your-own domain for passports (e.g. `labels.yourbrand.com`).
* Configure a CNAME to `resolver.eulabel.eu`.
* EUlabel provisions TLS automatically after verification.

How it works [#how-it-works]

When a consumer scans a QR code, the request flows through:

|DNS CNAME| B[resolver.eulabel.eu]:::blue
    B --> C[EUlabel resolver identifies your tenant]:::blue
    C --> D[Passport served under your domain]:::green"
/>

Setup steps [#setup-steps]

Choose your subdomain [#choose-your-subdomain]

    Pick a subdomain that clearly indicates product information:

    * `labels.yourbrand.com`
    * `products.yourbrand.com`
    * `dpp.yourbrand.com`
Add a CNAME record [#add-a-cname-record]

    In your DNS provider, create a CNAME record pointing to EUlabel's resolver:

    | Type    | Name     | Value                 |
    | ------- | -------- | --------------------- |
    | `CNAME` | `labels` | `resolver.eulabel.eu` |

    
> **Note**
> DNS propagation typically takes 5-30 minutes, but can take up to 48 hours depending on your DNS provider and TTL settings.

Register the domain in EUlabel [#register-the-domain-in-eulabel]

    
### CURL

```bash
export EULABEL_API_KEY="sk_live_..."

curl -X POST https://api.eulabel.eu/v1/domains \
  -H "Authorization: Bearer $EULABEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "labels.yourbrand.com"
  }'
```
### JavaScript

```javascript
const EULABEL_API_KEY = process.env.EULABEL_API_KEY;

const domain = await fetch('https://api.eulabel.eu/v1/domains', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${EULABEL_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ domain: 'labels.yourbrand.com' }),
}).then(r => r.json());
```
Verify ownership [#verify-ownership]

    EUlabel will attempt to verify the CNAME record. You can check the status:

    Trigger verification via the API or the Dashboard settings page:
```bash
curl -X POST https://api.eulabel.eu/v1/domains/DOMAIN_ID \
  -H "Authorization: Bearer $EULABEL_API_KEY"
```
    Possible statuses:

    | Status     | Meaning                                              |
    | ---------- | ---------------------------------------------------- |
    | `pending`  | Verification not yet attempted or CNAME not detected |
    | `verified` | Domain is active and serving                         |
    | `failed`   | DNS misconfiguration detected                        |
SSL certificate provisioning [#ssl-certificate-provisioning]

    EUlabel automatically provisions a TLS certificate via Let's Encrypt once the CNAME is verified. This typically completes within 2-5 minutes.
Troubleshooting [#troubleshooting]

> **Idea**
> Go-live checklist: confirm CNAME, wait for `verified`, confirm HTTPS works, then roll out QR codes in production print runs.

### Domain stuck in pending

Cause: CNAME not propagated.

    Fix: wait up to 48h and verify with `dig labels.yourbrand.com CNAME`.

  
### SSL certificate error

Cause: CNAME points to the wrong target.

    Fix: ensure the CNAME value is exactly `resolver.eulabel.eu`.

  
### QR code shows the wrong product

Cause: domain assigned to the wrong organization.

    Fix: check domain ownership in the dashboard.

  
### Mixed content warnings

Cause: the passport page loads HTTP resources.

    Fix: ensure all assets are HTTPS; EUlabel serves passport pages over HTTPS.

After setup [#after-setup]

Once verified, your existing QR codes continue to work through `eulabel.eu`, and new products can use your custom domain:
```text
# Both resolve to the same passport:
https://eulabel.eu/01/05601012012200
https://labels.yourbrand.com/01/05601012012200
```
Next steps [#next-steps]

- [Resolver concepts](https://eulabel.eu/docs/knowledge-base/concepts/resolver) — Understand how scans route to different audiences
- [Linkset](https://eulabel.eu/docs/documentation/integrations/linkset) — Discover all resources available for a product
- [Webhooks](https://eulabel.eu/docs/webhooks) — Sync product data from your PIM and keep passports up to date

