First-Party ClickID Attribution with Google Tag Manager
Modern AI tools and LLM-based agents rely heavily on user context. To deliver personalization, automation, and full-funnel attribution, these systems often require their own first-party identifiers - even when your team has no dedicated developers you sometimes have to implement.
This quick guide shows how to deploy a first-party click_id
using Google Tag Manager. It works on any site (including SPAs), requires no coding skills, and supports downstream systems like InsightArc, email tools, or custom backend logic - all while staying privacy-first.
Requirements
- Google Tag Manager is installed on your website.
- You have “Edit” access to the GTM container.
- (Optional) Tag Assistant extension in Chrome for debugging.
Step 1: Generate and Persist ClickID
This script creates a unique ID per visitor and stores it in both localStorage and a first-party cookie.
- In GTM, go to Tags → New
- Name it: [InsightArc] Generate & Persist ClickID
- Tag type: Custom HTML
- Paste the code:
<script> (function () { var KEY = 'click_id'; var cid = localStorage.getItem(KEY); if (!cid) { cid = (Date.now()).toString(36) + Math.random().toString(36).substr(2); localStorage.setItem(KEY, cid); document.cookie = KEY + '=' + cid + ';path=/;SameSite=Lax;Secure'; } window.__CLICK_ID__ = cid; })(); </script>
After that Trigger: Page View – All Pages And turn on Save and Publish
To verify, open the browser console and run the command (not in filter, run as command):
window.__CLICK_ID__
Step 2: Append ClickID to All Links
This script adds the click_id to all outbound links and supports SPAs like React, Vue, or Gatsby.
Create a new tag: [InsightArc] Append ClickID to Links
Tag type: Custom HTML
Paste the code:
(function(){
// 1) History API, to dispatch locationchange
(function(history){
var push = history.pushState;
history.pushState = function(){
var ret = push.apply(this, arguments);
window.dispatchEvent(new Event('locationchange'));
return ret;
};
window.addEventListener('popstate', function(){
window.dispatchEvent(new Event('locationchange'));
});
})(window.history);
// 2) Function checks all <a> and adds click_id
function rewriteLinks(){
var KEY = 'click_id';
var cid = window.__CLICK_ID__ || localStorage.getItem(KEY);
if (!cid) return;
var as = document.getElementsByTagName('a');
for (var i = 0; i < as.length; i++) {
var a = as[i];
var href = a.getAttribute('href');
if (!href || href.indexOf('javascript:') === 0) continue;
var parts = href.split('?'),
base = parts[0],
qs = parts[1] || '',
params = qs ? qs.split('&') : [],
found = false;
for (var j = 0; j < params.length; j++) {
if (params[j].indexOf(KEY + '=') === 0) {
params[j] = KEY + '=' + cid;
found = true;
break;
}
}
if (!found) params.push(KEY + '=' + cid);
a.setAttribute('href', base + '?' + params.join('&'));
}
}
// 3) First launch
rewriteLinks();
// 4) Repeat while SPA-navigation
window.addEventListener('locationchange', rewriteLinks);
// 5) If case of dynamic embeddings (filters inside the page etc.)
var mo = new MutationObserver(function(muts){
muts.forEach(function(m){
if (m.addedNodes.length) rewriteLinks();
});
});
mo.observe(document.body, { childList: true, subtree: true });
})();
</script>
Add all three triggers:
Page View – All Pages
DOM Ready
History Change (built-in trigger for SPA navigation)
Save and publish.
To test it, open browser DevTools and run:
$$('a[href*="click_id="]')
Step 4: Testing and Validation
Make sure everything works as expected.
Check the value Open console:
window.__CLICK_ID__
Should return a valid string.
###Check the links Open console:
$$('a[href*="click_id="]')
Navigate SPA pages
Click through internal links. New links should still contain click_id.