Here's my pick on the problem. The solution simply patches the default scripts to return function which then adds the script
tag only after the consent is granted. Have a look:
// for GoogleAnalytics
var loadGA = (function(i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function() {
(i[r].q = i[r].q || []).push(arguments)
},
i[r].l = 1 * new Date();
// call this function after receiving consent
return function loadGA() {
a = s.createElement(o),
m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
}
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
// for Facebook
window.fbAsyncInit = function() {
FB.init({
appId: 'your-app-id',
autoLogAppEvents: true,
xfbml: true,
version: 'v2.10'
});
FB.AppEvents.logPageView();
};
var loadFB = (function(d, s, id) {
//- call this function after receiving consent
return function loadFB() {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {
return;
}
js = d.createElement(s);
js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}
}(document, 'script', 'facebook-jssdk'));
// for HotJar
var loadHJ = (function(h, o, t, j, a, r) {
h.hj = h.hj || function() {
(h.hj.q = h.hj.q || []).push(arguments)
};
h._hjSettings = {
hjid: 1,
hjsv: 5
};
return function loadHJ() {
a = o.getElementsByTagName('head')[0];
r = o.createElement('script');
r.async = 1;
r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
a.appendChild(r);
}
})(window, document, '//static.hotjar.com/c/hotjar-', '.js?sv=');
// finally when you receive the consent
function onConsentReceived() {
loadGA();
loadFB();
loadHJ();
}
//- meanwhile you can continue using ga(), hj() whatever here...
Each of the loader can be in it's own script
tag but make sure about the ordering of those tags.