Zeno doiciméadú
Faigh eochracha API

Brabhsálaí

Custom domain

Serve the agent from a subdomain of your site with one DNS record, so blocklists aimed at third-party domains miss it: setup, naming, status, Safari cookies and CSP.

A custom domain is a subdomain of your site, like metrics.example.com, that we serve the agent and the identify call from instead of https://zenocdn.net. You add it in the dashboard, create one DNS record, and start the agent with it as its endpoint. There's nothing to run on your side. It's the setup we recommend for every live site.

Why your own domain

  • Blocklists. Ad and tracker blocklists match third-party domains. Once the agent's domain is on a list, an integration that calls it directly loses identifications without telling you: the agent can't load or can't send, your server gets no request ID, and it challenges real users it would otherwise let through. A subdomain of your own site isn't on those lists, and a list that names our domain doesn't touch it.
  • Your site's requests. The agent and every request it makes go to your own domain, so browser protections aimed at third-party trackers have less to act on.
  • The socket proof works. The subdomain carries the agent's WebSocket too, so events keep their socket proof.

Your own domain changes where the agent's requests go, not what they're for or when they may happen: your visitors' consent and the Acceptable Use Policy apply exactly as they do without one. Start the agent where your consent rules allow it.

Set it up

  1. Open Settings › Custom domain on the dashboard and add a subdomain of your site, like metrics.example.com. One custom domain serves the whole project.
  2. At your DNS provider, add the CNAME record the page shows: your subdomain as its name, the target we give as its value. Keep it unproxied (in Cloudflare, "DNS only"), so the request reaches us as it is.
  3. Wait for the certificate. Once the record resolves we issue a TLS certificate for the subdomain, usually within minutes, and the status turns active.
  4. Start the agent with your subdomain as its endpoint:
TypeScript
import { start } from 'zeno-id'

const agent = start({ publicKey: 'pk_...', endpoint: 'https://metrics.example.com' })

The page's own origin doesn't change, so the project's allowed origins stay as they are. There's one endpoint and nothing else is tried: until the domain is active, get() rejects with script_load_failed, so switch the endpoint once the status says so.

Choose a subdomain

Pick a plain name that fits your site, like metrics, stats or m. Don't put fp, fingerprint or the name of this service in it: blocklists carry rules for telling names too, and a name that says what it is is the first one a list adds. Use a subdomain of the site the agent runs on, not a separate domain, or it's a third party again. The apex (example.com itself) can't take a CNAME record, so it has to be a subdomain.

Status

StatusMeaning
pendingWe're waiting for the CNAME record to resolve and the certificate to be issued. The agent can't use the domain yet: keep the endpoint you had.
activeThe certificate is issued and the subdomain serves the agent and identify. Set it as the agent's endpoint.
failedThe certificate couldn't be issued, most often because the record is missing, has a typo, points elsewhere, or a CAA record at your domain doesn't allow our certificate authority. Fix the record and try again from the same page.

Keep the record in place for as long as the agent uses the domain: we renew the certificate through it. The dashboard's home ticks Serve from your own domain once the domain is active.

Cookies in Safari

Safari caps cookies at 7 days when they're set through a subdomain whose CNAME points at another company's servers, and it caps cookies and storage written by scripts at 7 days too. So in Safari the visitor id's cookie and localStorage entry may be gone after a week without a visit. The visitor id survives anyway: the API matches the device's hardware and signals on the server and gives the returning browser the same id, so a lost cookie costs nothing but the shortcut. Other browsers keep the cookie for its full year.

Content Security Policy

A page with a Content Security Policy needs the subdomain for the agent's code, its request and its WebSocket:

Content-Security-Policy
script-src 'self' https://metrics.example.com;
connect-src 'self' https://metrics.example.com wss://metrics.example.com;
worker-src 'self' blob:

Without the wss: address the socket fails and no event gets the socket proof; without worker-src blob: the agent skips its worker check and the event loses one of its tampering signals.