A fully functional POC is up on calebjaquith.com — the code in this post is from that implementation.

- Make Tealium traffic first-party without needing changes to Tealium origins or CDN settings.
- Preserve consented state by storing server-side copies of specific first-party cookies and restoring them only when appropriate — mitigating Safari’s first-party cookie limits and letting us reliably respect consent.
- Centralize governance at the edge. Decide which cookies persist, their attributes and lifetimes, and which vendor cookies to write, since the headers are now in your control.
Review: architecture at a glance
As covered in Part 1, inside a reverse proxy on our main CDN (we used a Cloudflare Worker), we expose a small set of first-party paths that forward to Tealium services. The browser only sees the first-party domain, while the proxy dispatches to Tealium iQ, Tealium Collect, and Data Layer Enrichment (DLE) behind the scenes.
This creates one place to manage cookie persistence and similar edits — without needing to host new files — all while keeping a first-party footprint in the browser.

What we did in this POC
1Made all Tealium calls first-party using a Cloudflare Worker
This solution results in first-party, working path support for:
- The full
tags.tiqcdn.comTealium CDN collect.tealiumiq.comTealium Collection endpoints- Tealium’s Data Layer Enrichment (DLE) feature (used by Collect)
- A simple cookie sync endpoint to enable step 2 to restore cookies in time
- And more
This helps with cosmetic concerns and CSP complexity, and thwarts some adblockers that look for our CDN (more on that in step 3). It’s easy to add additional paths as we add new services, and the origin doesn’t need to change anything at all — no certs to exchange, no First-Party Domains (FPD) to activate, no ops tickets to log.
As a bonus, avoiding a subdomain with this path-based system also ensures Safari (or any other browser) recognizes the domain as first-party and owned by the site owner. And the whole CDN is accessible — unlike with a typical FPD product — so files used by Adobe Launch and Google Tag Manager are available too, for example:
Example first-party pathshttps://calebjaquith.com/fwd-tealcdn/libs/tealiumjs/latest/tealium_collect.min.js
https://calebjaquith.com/fwd-tealcdn/shared/tms/t.tealium_collect.1_0_3.js
2Persist specific cookies longer than Safari ITP would generally allow
We added functionality to copy specific cookies into a server-side version — continually restored to the client — which isn’t impacted by ITP. The demo uses:
utag_main_v_idcc_cookie(only visible if you make a decision oncalebjaquith.com?use_cmp=true)
Each is persisted using the same name with _copy appended, to keep the connection clear — we have nothing to hide, since we’re circumventing ITP for the right reasons. That means we can persist opt-outs for Californians, a critical capability that Safari’s ITP otherwise takes away without this kind of server-side-cookie workaround.
We also added an endpoint to delete those cookies and their copies, since server-side cookies can otherwise only be removed by the user in Developer Tools.
- Visit calebjaquith.com/?use_cmp=true and make a consent decision when prompted.
- Check Application → Cookies in DevTools. You’ll see
utag_main*cookies includingutag_main_v_idand a server-side-onlyutag_main_v_id_copy, pluscc_cookieandcc_cookie_copy. - Visit the deletion endpoint to remove specific cookies with a URL-encoded list:
/fwd-delete-cookies/?cookies=%5B%22utag_main_v_id%22%5D. After this,utag_main_v_idand its copy are gone, butcc_cookiestays intact. - Call
/fwd-delete-cookies/with no list to delete both cookies and their copies (an empty list is treated as no list). - Revisit the first page at any point to restore cookies and test other variants.
3Removed all instances of “utag” from file paths to thwart adblockers
utag in your reverse proxy. Tealium’s CDN only serves utag.js and utag.N.js files — this relies on the customer’s proxy renaming those strings in the path before forwarding to the CDN, or you’ll get page errors.We wanted to thwart string matching for “utag” on the path, a method some adblockers use. It took a small utag config update to rewrite path strings, with the reverse rename happening on the CDN side:
utag_cfg_ovrdwindow.utag_cfg_ovrd = window.utag_cfg_ovrd || {};
window.utag_cfg_ovrd.utag_cdn_rewrite = 'lkjdf';
That override, with an updated utag template, means even extreme adblock lists that look for “tealium” or “utag” in paths won’t recognize and block our requests. It turns the utag.js request on calebjaquith.com from:
https://calebjaquith.com/fwd-tealcdn/utag/services-caleb/personal-website/prod/utag.jshttps://calebjaquith.com/fwd-tealcdn/lkjdf/services-caleb/personal-website/prod/lkjdf.js…which is then transformed back by the Cloudflare Worker before it’s sent to the Tealium CDN. The browser never sees that the file is called utag.js, and the CDN only ever sees utag files, so it serves them as usual.
Two changes are needed. First, in the utag.loader.AS method, replace:
a.src = utag.cfg.path + ((typeof a.name != 'undefined') ? a.name : 'ut' + 'ag.' + a.id + '.js')
with:
a.src = utag.cfg.path.replaceAll('utag', (utag.cfg.utag_cdn_rewrite||'utag')) + ((typeof a.name != 'undefined') ? a.name : (utag.cfg.utag_cdn_rewrite || 'utag') + '.' + a.id + '.js')
to accommodate a different string in place of “utag” for subloaded tag files, set via utag_cfg_ovrd as described above.
Second, update the billing request. Replace:
v = utag.cfg.path;
if (b["cp.utag_main__ss"] == 1 && !utag.cfg.no_session_count) utag.ut.loader({ src: v + "ut" + "ag" + ".v.js?a=" + utag.cfg.utid + (utag.cfg.nocookie ? "&nocookie=1" : "&cb=" + (new Date).getTime()), id: "tiqapp" })
with:
Rewrite the billing call// CUSTOM - add support for rewriting the billing call
v = utag.cfg.path + "utag";
v = v.replaceAll('utag', (utag.cfg.utag_cdn_rewrite || 'utag'));
if (b["cp.utag_main__ss"] == 1 && !utag.cfg.no_session_count) utag.ut.loader({ src: v + ".v.js?a=" + utag.cfg.utid + (utag.cfg.nocookie ? "&nocookie=1" : "&cb=" + (new Date).getTime()), id: "tiqapp" })
4Removed the TAPID cookie
TAPID is used for cross-domain tracking, which isn’t useful in a first-party context, so we removed it. There’s a client-side flag we could have used instead, but doing it in the Worker was simpler — no other changes required.
Putting it all together
Together, these choices give you a durable, first-party surface: consented state survives Safari inactivity windows via server-side copies, Tealium traffic stays reliably first-party through path-based forwarding, and cookie policy moves into one place you control at the edge.
You can roll this out incrementally — route iQ and Collect through your domain first, persist consent and a small set of IDs, then expand as your legal team allows.
No changes to Tealium origins, no certificate exchanges, and no ops tickets were required in our POC, because the Cloudflare Worker performs the forwarding and header work at the edge. The live demo on calebjaquith.com lets you dig into and test the approach end to end, including optional path rewriting to avoid list-based blocking, removal of TAPID where cross-domain linking isn’t needed, and a preview of CSP reporting — covered next in Part 3.