---
title: "Custom Tracking Domains | HitKeep"
description: "Configure team-level custom tracking domains in HitKeep Cloud or self-hosted HitKeep, including DNS ownership, DNS target checks, TLS readiness, and optional Caddy on-demand TLS."
canonical: "https://hitkeep.com/guides/tracking/custom-tracking-domains/"
---

# Custom Tracking Domains

Ad blockers and restrictive network filters are more likely to block shared analytics hostnames than a first-party subdomain controlled by the site owner.

HitKeep custom tracking domains let team admins verify multiple tracker hostnames for a team. Every active team domain can serve tracker assets and browser ingest for every site in that team. When users generate tracking code for a site, Site Settings lets them choose the instance URL or any active team domain for the `hk.js` snippet. Cloud and self-hosted deployments use the same database model, dashboard flow, API, and tracker behavior. The difference is TLS operations: HitKeep Cloud issues certificates on demand with Caddy, while self-hosted operators either use the optional Caddy profile or terminate TLS in their own reverse proxy.

```
HITKEEP_CUSTOM_TRACKING_TLS_MODE=caddy-on-demand
HITKEEP_CADDY_TLS_ASK_TOKEN=$(openssl rand -hex 32)
HITKEEP_PUBLIC_URL=https://hitkeep.example.com
```

See the [configuration reference](https://hitkeep.com/reference/configuration/#custom-tracking-domains/) for all custom-domain runtime switches.

## Domain model

- Domains belong to a team, not an individual site.
- A team can verify multiple domains.
- Every active team domain works for every site in that team.
- Site Settings does not assign domains to the site. It only chooses which available host to use in the generated snippet.
- The instance URL always remains available as a tracker endpoint.
- Hostnames are normalized as lowercase ASCII fully qualified domain names.
- Hostnames cannot conflict with the configured `HITKEEP_PUBLIC_URL` host, existing site domains, or another team’s custom tracking domain.

Custom tracking hosts are tracking-only. HitKeep serves only:

- `GET /hk.js`
- `GET /hk-vitals.js`
- `POST /ingest`
- `POST /ingest/event`
- `POST /ingest/web-vitals`
- matching `OPTIONS` preflight requests for ingest

Dashboard, API, auth, share links, MCP, QR redirects, and SPA fallback routes return `404` on a custom tracking host.

## Verification records

Add the domain in **Team Settings -> Tracking domains**. HitKeep shows the exact DNS records to create.

```
TXT    _hitkeep-tracking.analytics.example.com
Value  hitkeep-domain-verification=<token>

CNAME  analytics.example.com
Value  <target shown in HitKeep>
```

HitKeep checks three things before a domain can be used as a tracker endpoint:

1. DNS ownership TXT record exists and matches the generated token.
2. DNS routing target matches the deployment target. By default this is the host from `HITKEEP_PUBLIC_URL`; managed cloud uses the regional origin target shown in the dashboard.
3. `https://analytics.example.com/hk.js` returns the tracker asset with valid TLS.

The HTTPS probe is what turns a DNS-verified domain into an active tracker endpoint. Until then, the domain can exist in Team Settings, but Site Settings does not offer it as a snippet host.

## HitKeep Cloud flow

1. Open **Team Settings -> Tracking domains**.
2. Add a subdomain such as `analytics.example.com`.
3. Create the TXT ownership record.
4. Point the subdomain to the cloud target shown in the dashboard.
5. Click **Verify**.
6. Wait for TLS to become ready.
7. Open the site’s tracking settings and choose the instance URL or any active team tracker domain for the generated snippet.

The generated snippet changes from the regional cloud host to the selected domain:

```
<script async src="https://analytics.example.com/hk.js"></script>
```

Cloud uses Caddy on-demand TLS behind the same HitKeep allow endpoint described below. Teams do not need to configure Caddy themselves in the managed product.

## Self-hosted flow

Self-hosted HitKeep uses the same dashboard flow and verification checks, but the operator controls DNS, TLS, and the reverse proxy.

For a normal externally terminated proxy, set:

```
HITKEEP_CUSTOM_TRACKING_TLS_MODE=external
```

Then point each tracker hostname at the same host as `HITKEEP_PUBLIC_URL`, and configure your proxy to:

- terminate TLS for each verified tracking hostname
- forward requests to the HitKeep process
- preserve the original `Host` header
- publish `/hk.js`, `/hk-vitals.js`, and the ingest routes

HitKeep still enforces the tracking-only host boundary, so an accidentally proxied dashboard route on a custom tracking host returns `404`.

The HitKeep repository includes external-TLS examples for operators who manage certificates outside Caddy:

- [`examples/nginx.custom-tracking.conf`](https://github.com/PascaleBeier/hitkeep/blob/main/examples/nginx.custom-tracking.conf) and [`examples/compose.nginx-custom-tracking.yml`](https://github.com/PascaleBeier/hitkeep/blob/main/examples/compose.nginx-custom-tracking.yml)
- [`examples/traefik.custom-tracking.yml`](https://github.com/PascaleBeier/hitkeep/blob/main/examples/traefik.custom-tracking.yml) and [`examples/compose.traefik-custom-tracking.yml`](https://github.com/PascaleBeier/hitkeep/blob/main/examples/compose.traefik-custom-tracking.yml)

Kubernetes installs can use the official Helm chart’s `customTrackingDomains` values to set the HitKeep runtime mode and optionally create a tracking-only Ingress for static tracker hostnames. See the [Kubernetes guide](https://hitkeep.com/guides/installation/kubernetes/#custom-tracking-domains/).

In external mode, add each tracking hostname to the proxy before clicking **Verify**. The proxy must already present a valid certificate for `https://<hostname>/hk.js`; otherwise HitKeep keeps the domain inactive.

## Optional Caddy on-demand TLS

Use Caddy on-demand TLS when self-hosted teams should be able to add tracker domains from the dashboard without the operator editing a Caddyfile for every hostname.

Generate an ask token:

```
export HITKEEP_CADDY_TLS_ASK_TOKEN="$(openssl rand -hex 32)"
```

Enable Caddy mode on HitKeep:

```
HITKEEP_CUSTOM_TRACKING_TLS_MODE=caddy-on-demand
HITKEEP_CADDY_TLS_ASK_TOKEN=$HITKEEP_CADDY_TLS_ASK_TOKEN
```

Configure Caddy with a restricted `ask` endpoint:

```
{
  email ops@example.com
  on_demand_tls {
    ask http://hitkeep:8080/internal/caddy/on-demand-tls/{$HITKEEP_CADDY_TLS_ASK_TOKEN}
  }
}

https:// {
  tls {
    on_demand
  }

  reverse_proxy hitkeep:8080 {
    header_up Host {host}
    header_up X-Forwarded-Host {host}
    header_up X-Forwarded-Proto {scheme}
  }
}
```

Caddy calls the ask URL with `?domain=<hostname>` before issuing a certificate. HitKeep returns `204` only when the token matches and the hostname is an enabled, DNS-verified custom tracking domain. Unknown, disabled, malformed, or wrong-token requests are denied.

Do not enable Caddy on-demand TLS without `ask`. Caddy treats any 2xx ask response as allowed, and the `ask` gate is the control that prevents arbitrary certificate issuance. See Caddy’s official [on-demand TLS overview](https://caddyserver.com/on-demand-tls), [Automatic HTTPS](https://caddyserver.com/docs/automatic-https), and [global options](https://caddyserver.com/docs/caddyfile/options) documentation.

The HitKeep repository includes example files:

- [`examples/Caddyfile.custom-tracking`](https://github.com/PascaleBeier/hitkeep/blob/main/examples/Caddyfile.custom-tracking)
- [`examples/compose.caddy-on-demand.yml`](https://github.com/PascaleBeier/hitkeep/blob/main/examples/compose.caddy-on-demand.yml)

## Security notes

Browser ingest still resolves the tracked site from the page `Origin`, not from the tracker host. When the request host is a custom tracking domain, HitKeep additionally checks that the custom tracking domain and the resolved site belong to the same team. That prevents another team from reusing someone else’s verified tracker host.

The Go binary does not embed Caddy and does not require Caddy. The optional profile is an operational convenience for TLS automation; HitKeep remains a single-binary application when you terminate TLS elsewhere.

## Related

- [Tracker Architecture](https://hitkeep.com/guides/tracking/tracker-architecture/)
- [Docker Compose](https://hitkeep.com/guides/installation/docker-compose/)
- [Kubernetes](https://hitkeep.com/guides/installation/kubernetes/#custom-tracking-domains/)
- [Trusted Proxies](https://hitkeep.com/guides/installation/trusted-proxies/)
- [Configuration Reference](https://hitkeep.com/reference/configuration/#custom-tracking-domains/)
- [HitKeep Cloud](https://hitkeep.com/pricing/)

[Previous NPM package](https://hitkeep.com/guides/tracking/npm-package/)[Next Automatic events](https://hitkeep.com/guides/tracking/automatic-events/)
