Custom Tracking Domain in Bloomreach Engagement

Teal cover. Headline — Custom Tracking Domain, NS not CNAME. Right side — two DNS record panels, NS delegation marked correct and CNAME marked incorrect. Subheadline — DNS for a subdomain that carries events.

Why your Bloomreach Engagement cookies expire after 7 days on Safari, what a Custom Tracking Domain does about it, and how to set one up properly, with the DNS tradeoff that most guides skip.

The problem

Bloomreach Engagement's default tracking cookie (__exponea_etc__) is a first-party cookie. That sounds safe, but on Safari it's not. Apple's Intelligent Tracking Prevention (ITP), introduced in its current aggressive form in 2019, caps the lifespan of any first-party cookie set via JavaScript to seven days.

Seven days of visitor inactivity on Safari → the BR cookie expires → the returning visitor looks like a brand-new anonymous user, even if they subscribed to your newsletter weeks ago. Their customer profile, their session history, their consent state, all untethered from their next visit.

For e-commerce, this breaks a specific, high-value flow: cart and browse abandonment emails. Someone subscribes Monday, comes back the following Wednesday (9 days later), adds a product to cart, leaves. No recovery email fires because BR sees them as a new anonymous visitor with no email address.

Safari accounts for roughly 55% of US mobile browser use at the end of 2024 per StatCounter, and about a third of US browser traffic across all devices. For any retailer with meaningful Safari traffic, this is real revenue loss.

What CTD does

A Custom Tracking Domain (CTD) is Bloomreach Engagement's answer to this. Instead of serving the BR tracking API from api.exponea.com (or api.eu1.exponea.com, eu2-api.eng.bloomreach.com, etc.), you serve it from a subdomain you own, typically something like cx.yourdomain.com or analytics-api.yourdomain.com.

The technical magic: when tracking requests come from your own subdomain, the BR server can set cookies directly via HTTP response headers (using Set-Cookie), instead of the JavaScript SDK setting them client-side. Safari ITP treats HTTP-set cookies differently, they're not capped at 7 days the way JavaScript-set ones are.

Result: the BR tracking cookie persists for the full expiration you configure (up to 3 years by default), even on Safari. Returning visitors after 8, 30, 90 days still resolve to the same BR profile.

This is a real, measurable win. We've seen CTD-enabled projects consistently resolve Safari visitors to the same BR profile across 8+ day gaps, where the default JavaScript-cookie setup would have lost them. The business impact flows directly to abandonment campaigns: cart and browse recovery emails reach subscribers who would otherwise have been seen as brand-new anonymous visitors.

When CTD is worth implementing

CTD is not a default recommendation. Setting it up involves DNS changes, SDK reconfiguration, and a migration path for existing cookies. Worth the effort when:

  • You have a non-trivial share of Safari traffic (iOS-heavy markets: US, UK, Nordics, Australia)

  • Your BR use cases depend on returning visitor recognition: cart abandonment, browse abandonment, lifecycle triggers, behavioral segmentation across multiple sessions

  • Your customer journey spans days or weeks, not just a single session

  • You have measurable revenue dependent on abandonment emails or long-tail retargeting

Not worth it when:

  • Your BR use cases are single-session only (transactional emails triggered by immediate actions)

  • Safari traffic is < 10% of your users (think B2B or heavily Android markets)

  • You're on a free or trial BR Engagement plan that doesn't support custom domains

  • You don't control the DNS for your main domain

There's a second benefit worth mentioning: ad blocker resistance. Many ad blocker lists include Bloomreach's default tracking domains (api.exponea.com, bloomreach.com). When BR is loaded from your own subdomain, it's less likely to be blocked outright. This isn't bulletproof (determined ad blockers match content signatures, not just URLs), but it raises the floor.

The DNS decision that matters: NS vs CNAME

This is where most implementation guides get vague, and it's the choice that determines whether your CTD actually survives Safari ITP or falls back into the 7-day cap.

CNAME records. The easier setup. You create a CNAME record on your DNS pointing your subdomain (e.g., cx.yourdomain.com) at Bloomreach's infrastructure. DNS-wise, this works. Your BR SDK serves from your domain. Problem: Safari ITP detects CNAME cloaking and, in its latest versions, still caps cookies at 7 days even when set via HTTP. The CNAME setup partially mitigates ITP but not fully.

NS records. The harder setup, with more moving parts. Instead of CNAME, you delegate the entire subdomain's DNS zone to Bloomreach's name servers using NS records. Effectively you're telling the global DNS system: "for cx.yourdomain.com, ask Bloomreach's DNS servers, not mine." This makes Bloomreach's infrastructure authoritative for that subdomain, which avoids the CNAME-cloaking signal Safari uses to trigger the 7-day cap.

The Safari 16.4 caveat you have to test for. In April 2023, Safari 16.4 extended the 7-day cap beyond CNAME cloaking. It now also caps cookies when a subdomain's A/AAAA records resolve to an IP address whose first half does not match the first half of the main site's IP (for IPv4, that's the first two octets; for IPv6, the first four groups). The rule is implemented in WebKit and was not documented in the public Safari 16.4 release notes. NS delegation to Bloomreach does not automatically escape it, because the final resolution still produces Bloomreach's IPs, which typically sit in a different /16 range than your main site's IPs.

Before trusting CTD on Safari, verify the IP alignment:

dig A cx.yourdomain.com +short
dig A yourdomain.com +short
dig A cx.yourdomain.com +short
dig A yourdomain.com +short
dig A cx.yourdomain.com +short
dig A yourdomain.com +short

If the first two octets match on both, Safari 16.4 treats the cookies as first-party and the full expiry holds. If they don't match, cookies are still capped at 7 days on Safari 16.4+, even with NS delegation. This is infrastructure-dependent: it can change as Bloomreach routes traffic through different edges or as your own hosting changes.

The tradeoff:


CNAME

NS

DNS setup complexity

Low (single record)

Medium (four records, zone delegation)

CNAME-cloaking detection by Safari

Triggers the 7-day cap

Avoided

Safari 16.4+ IP-match rule

Still applies

Still applies (depends on Bloomreach IPs vs your IPs)

Cookie lifespan on Safari

Capped at 7 days

Full expiry only if the A-record IPs align with your site's IPs

Revocability

Easy (delete the CNAME)

Requires coordination with BR support

Use NS records over CNAME, and verify IP alignment after setup. NS avoids one Safari rule (CNAME cloaking) but does not automatically clear the second (IP match). If the IPs don't align, consider whether server-side tracking or a different hosting topology is the better path for Safari-heavy traffic.

Implementation

Step 1: Choose the subdomain

Pick a subdomain name. Common conventions:

  • cx.yourdomain.com (short, opaque, Bloomreach's example: works well)

  • analytics-api.yourdomain.com (descriptive, longer)

  • track.yourdomain.com (clear but flags the domain as tracking-related, which some ad blockers target)

Use something unused, the subdomain must not serve any other content. It belongs to BR now.

Step 2: Add the domain in Bloomreach Engagement

In the BR Engagement webapp:

  1. Open your project

  2. Navigate to Project settings → Custom domains (or Domains depending on tenant version)

  3. Click Add custom domain

  4. Enter the subdomain you chose (e.g., cx.yourdomain.com)

  5. Select the type: Tracking Domain

  6. Save

Bloomreach will generate the DNS records you need to add on your side. For NS setup, you'll see four NS records.

Step 3: Add DNS records on your side

In your DNS provider (Cloudflare, Route 53, GoDaddy, whichever):

  1. Go to the DNS zone for your main domain

  2. Add the four NS records Bloomreach provided, targeted at the subdomain (e.g., cx.yourdomain.com, record type: NS, values: the four name servers Bloomreach gave you)

  3. Important: don't add these as NS records on your root domain, only on the specific subdomain. Delegating the root to Bloomreach would break your main site.

  4. Save

DNS propagation typically takes 5-30 minutes but can be up to 48 hours depending on TTL. Test propagation using a DNS checker tool or command line:

dig NS cx.yourdomain.com
dig NS cx.yourdomain.com
dig NS cx.yourdomain.com

You should see the four Bloomreach name servers listed as authoritative.

Step 4: Verify domain activation in Bloomreach

Back in the BR Engagement webapp:

  1. Return to Project settings → Custom domains

  2. Wait for the domain status to change to Active or Verified

  3. If it stays pending for more than an hour, check your DNS records are correct, most failures are typos in the NS record values

Step 5: Update your tracking SDK snippet

Once the domain is verified, BR Engagement will provide an updated SDK snippet. The change is minimal, just the target URL in the exponea.start() config switches from the default to your new subdomain:

exponea.start({
  target: 'https://cx.yourdomain.com',  // was: 'https://api.exponea.com'
  token: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
  // ... rest of config unchanged
});
exponea.start({
  target: 'https://cx.yourdomain.com',  // was: 'https://api.exponea.com'
  token: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
  // ... rest of config unchanged
});
exponea.start({
  target: 'https://cx.yourdomain.com',  // was: 'https://api.exponea.com'
  token: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
  // ... rest of config unchanged
});

(The config key for the project token varies between BR-generated snippets, usually token in current docs and projectToken or project_token in older integrations. Keep whatever your live snippet already uses; the change that matters is only the target URL.)

And the SDK script source URL changes the same way:

<!-- Was: https://api.exponea.com/js/exponea.min.js -->
<script src="https://cx.yourdomain.com/js/exponea.min.js"></script>
<!-- Was: https://api.exponea.com/js/exponea.min.js -->
<script src="https://cx.yourdomain.com/js/exponea.min.js"></script>
<!-- Was: https://api.exponea.com/js/exponea.min.js -->
<script src="https://cx.yourdomain.com/js/exponea.min.js"></script>

Update this in:

  • Your GTM Bloomreach Engagement init tag (if loaded via GTM)

  • Any direct <script> tags in your site's head (if loaded directly)

  • Mobile SDK configuration (if you use iOS or Android BR SDKs)

Step 6: Deploy and verify

After deploying the updated snippet:

  1. Open your site in a fresh browser window

  2. DevTools → Network tab → filter by exponea

  3. Confirm the SDK is loaded from your subdomain (cx.yourdomain.com/js/exponea.min.js) not from api.exponea.com

  4. DevTools → Application → Cookies → check that __exponea_etc__ (or similar BR cookie) is set under your domain

  5. On Safari: the cookie's Expires/Max-Age column often shows the full multi-year horizon even when ITP is capping the cookie in practice, because Safari enforces the 7-day cap at storage-access time, not at write-time. The Expires value is not a reliable diagnostic on its own.

  6. The real test is whether the same __exponea_etc__ value survives an 8+ day gap without visiting your site in Safari. If it doesn't, re-run the dig IP-match check from the DNS section; you are likely hitting Safari 16.4's IP-mismatch cap.

Step 7: Monitor migration

Existing visitors who had a JavaScript cookie from the old domain won't automatically transfer to the HTTP cookie. They'll appear as new visitors once, then the new HTTP cookie takes over from that point forward. This creates a one-time inflation in "new visitor" counts for a few days post-migration. Expected, not a bug. Document it in your reporting so analysts don't panic.

Common mistakes

Using CNAME instead of NS. The most common mistake, because CNAME is easier. Setup completes, everything looks fine in testing, Safari visitors still expire at 7 days. If you're doing this at all, use NS.

Using a subdomain that's already in use. If cx.yourdomain.com already has an A record or CNAME pointing somewhere, the NS delegation conflicts and the setup fails silently. Use a genuinely unused subdomain.

Leaving the BR SDK snippet pointing at the old domain. DNS works, domain is verified, but nobody updated the target in the SDK config. The cookies still come from the old domain. Verify in the Network tab.

Forgetting GTM vs direct snippet in a client's setup. Some clients load BR in two places, once via GTM for some pages, once as a direct script tag for others (legacy pages, checkout flows, whatever). Update all instances. One missed snippet means a chunk of traffic still gets the 7-day cap.

Assuming it fixes cross-domain tracking. It doesn't. CTD restores first-party tracking on a single domain. If your traffic spans multiple domains (e.g., main site + checkout on a different subdomain + help center on a different domain entirely), CTD doesn't bridge them. You need different strategies for cross-domain, typically manual cookie-sharing or server-side tracking.

Relationship to the other manuals

CTD pairs with the GA4 client ID capture pattern we cover in a separate manual. The two serve different purposes and complement each other:

  • CTD keeps the BR customer profile stable across time on Safari (beyond 7 days)

  • GA4 client ID capture links the BR profile to the GA4 session identity at the moment of visit

For a retailer with Safari traffic and cross-tool analytics needs, you'd want both. CTD alone gives you stable BR identity but no link to GA4. Capture alone gives you a GA4 link per visit but loses the BR identity after 7 days of Safari inactivity.

What this doesn't solve

  • Cross-device tracking. A user on iPhone Safari and then laptop Safari still has two separate BR profiles unless they identify themselves (login, form submission) on both. CTD stabilizes per-device identity; it doesn't bridge devices.

  • Cookie clearance. If a user clears their cookies or browses in Private/Incognito mode, BR sees them as fresh. CTD doesn't help here and nothing really can at the browser level.

  • Consent denial. If a visitor denies analytics_storage consent, BR shouldn't be tracking them at all. CTD doesn't bypass consent; it just makes the tracking more reliable for visitors who have granted it.

  • Server-side tracking gaps. CTD is a frontend solution. If you also want server-side tracking (for checkout confirmation, backend events, payment webhooks), that's a separate setup: see Bloomreach's documentation on server-side tracking for the full pattern.

Further reading

Bloomreach's own documentation covers the mechanics thoroughly: Custom Tracking Domain (CTD) and Custom Domain Management. Both are worth reading for the full setup reference. Where those guides stop short is on the NS-vs-CNAME question and on Safari 16.4's A-record IP-match rule, which together determine whether CTD actually delivers long-lived cookies on Safari. That's what this manual exists to cover.

For deeper context on how Bloomreach handles anonymous identity across the full flow, see Server-side anonymous identity management. CTD is one of three approaches Bloomreach documents there, alongside server-side GTM and fully custom server-side identity handling.

Related manuals