How to integrate a self-developed cookie consent banner with Hubspot tracking code?
On https://diversifier.witty.works we have a simple consent banner that we custom developed. If the user gives their consent we use Google Tag Manager to dynamically load Google Analytics etc.
Now we want to integrate the Hubspot tracking code, mainly to track form submissions but also do possibly track other aspects.
Note we have configured Hubspot according to EU GDPR laws, ie. opt-in.
However looking over the API I only see a way to opt-out but not to opt-in:
How to integrate a self-developed cookie consent banner with Hubspot tracking code?
Yeah we are using this integration for www.witty.works .. diversifier.witty.works is a legacy website and I am just trying to find the cheapest (both in USD and time) path to integrate hubspot replacing mailchimp
How to integrate a self-developed cookie consent banner with Hubspot tracking code?
Thank you. This would mean we need to customize the cookie banner setup for diversifier.witty.works (since we have a cookiebot based setup for www.witty.works), so that we can have a different configuration there. This could then indeed work but it is incredibly hacky, quite dissapointing that Hubspot doesn't support this use case but once again thank you for outlining how it can at least be done!
The way I managed this was by customising the Hubspot cookie banner like this:
And creating a custom global module that looks like this:
And wrote some JS to simultaneously set local session storage and push to GTM dataLayer to set users' cookie preferences. To set the users Hubspot preferences I basically fake a click of accept or decline.
// set session storage cookie function (e.g. for cookie consent)
var consentArr = ['consent_functionality', 'consent_analytics', 'consent_advertising'];
var cookieToggles = document.getElementsByClassName('cookie-toggle');
function setLocalCookie(name, value) {
localStorage.setItem(name, value);
dataLayer.push({
event: name+'_event',
[`${name}`]: value,
});
}
// mutation observer to detect when HS cookie banner is added to the DOM, then add event listeners when it is
const observer = new MutationObserver(mutations => {
mutations.forEach(({ addedNodes }) => {
addedNodes.forEach(node => {
// For each added node
if(node.nodeType === 1 && node.tagName === 'DIV' && node.classList.contains('hs-cookie-notification-position-bottom')) {
document.getElementById('hs-eu-confirmation-button').onclick = function(e) {
// if click is a real click: when the user clicks on a button the event has a real screenX and screenY based on the button position but when you 'click' the button via code the event's position is 0
if(e.screenX && e.screenX != 0 && e.screenY && e.screenY != 0){
for (i = 0; i < consentArr.length; i++) {
setLocalCookie(consentArr[i], true);
}
for (i = 0; i < cookieToggles.length; i++) {
cookieToggles[i].checked = true;
}
observer.disconnect();
}
}
document.getElementById('hs-eu-decline-button').addEventListener('click', function(e) {
for (i = 0; i < consentArr.length; i++) {
setLocalCookie(consentArr[i], false);
}
});
var cookieLink = document.querySelector('#hs-eu-policy-wording a[href="http://www.mews.com/#cookieCentre"]');
if (cookieLink != null) {
cookieLink.addEventListener('click', function(e) {
e.preventDefault();
document.getElementById('preferences-modal').classList.remove('hide');
observer.disconnect();
});
}
// if website is in iframe decline cookies
if (inIframe() === true) {
document.getElementById('hs-eu-decline-button').click();
}
}
})
})
})
window.addEventListener('load', (event) => {
// Starts the monitoring
observer.observe(document.documentElement, {
childList: true,
subtree: true
})
// open modal from privacy settings link in footer
var footerCookie = document.getElementById('footer-cookie');
if (footerCookie != null) {
footerCookie.addEventListener('click', function() {
document.getElementById('preferences-modal').classList.remove('hide');
});
}
// cookie preferences centre scripts
var acceptAll = document.getElementById('accept_all');
var acceptSelect = document.getElementById('accept_select');
// on page load change toggles to 'checked'/on if the cookie consent item exists and is true in session storage
for (i = 0; i < consentArr.length; i++) {
let cookieBool = localStorage.getItem(consentArr[i]);
if (cookieBool === 'true') {
var type = consentArr[i].replace('consent_','');
document.querySelector('.cookie-toggle[data-id='+type+']').checked = true;
}
}
// when accept all button is clicked in preferences modal, set all consent items in session storage to true and toggle toggles to true
acceptAll.addEventListener('click', function() {
for (i = 0; i < consentArr.length; i++) {
setLocalCookie(consentArr[i], true);
}
for (i = 0; i < cookieToggles.length; i++) {
cookieToggles[i].checked = true;
}
document.getElementById('preferences-modal').classList.add('hide');
// fake 'click' the HS cookie banner accept button
if (document.getElementById("hs-eu-confirmation-button") != null) {
document.getElementById('hs-eu-confirmation-button').click();
}
});
// when accept select button is clicked in preferences modal, set only the chosen consent items in session storage to true and toggle those toggles to true
acceptSelect.addEventListener('click', function() {
for (i = 0; i < cookieToggles.length; i++) {
var cookieToggle = cookieToggles[i];
var id = cookieToggle.dataset.id;
if (cookieToggle.checked) {
setLocalCookie('consent_'+id, true);
// if analytics is a selected option, 'click' the HS cookie banner accept button
if (id === 'analytics' && document.getElementById('hs-eu-confirmation-button') != null) {
document.getElementById('hs-eu-confirmation-button').click();
}
} else {
setLocalCookie('consent_'+id, false);
// if analytics is NOT a selected option, 'click' the HS cookie banner decline button
if (document.getElementById('hs-eu-decline-button') != null) {
document.getElementById('hs-eu-decline-button').click();
}
}
}
document.getElementById('preferences-modal').classList.add('hide');
});
var close = document.querySelectorAll('.close-modal, .overlay');
close.forEach(el => el.addEventListener('click', function(e){
e.preventDefault();
document.getElementById('preferences-modal').classList.add('hide');
document.body.style.overflow = 'auto';
}));
});
In GTM I set up custom JS variables to read local storage e.g.
function() {
var consent_advertising = localStorage.getItem('consent_advertising');
return consent_advertising;
}
and triggers based on those variables (for persisting choices in a session), and triggers based on the dataLayer events (to change permissions based on choices the instant preferences are selected, i.e. before session storage is useful).