How to add Google Analytics cross-domain linker parameters to an URL with javascript (using GTM)? - google-analytics

On our site, we have a couple of buttons that will take you to a different domain but not before we've composed the actual URL with appropriate query parameters in Javascript. What is the best way to add Google Analytic's linker parameter to this URL? We're using the universal script injected by Google Tag Manager.

Ah... found it. Documentation suggests:
ga(function(tracker) { var linkerParam = tracker.get('linkerParam'); })
But the tracker is undefined in my case.
I found the solution in this blog post:
if (typeof(window["ga"]) !== "undefined") {
var firstTracker = ga.getAll()[0];
if (firstTracker) { return firstTracker.get("linkerParam"); }
}
But... on further investigation, I found the root cause: using GTM means that there are potentially multiple trackers active on a page. Hence the single ga-function won't work. I haven't found the exact GTM-compatible way of doing this, but I'll stick with this workaround for now.

Related

Is YouTube IFrame API already loaded

I want to know if the API has already been loaded. I can't find anything about it here:
YouTube Player API Reference for iframe Embeds
https://developers.google.com/youtube/iframe_api_reference
Is there anyone here who knows how to find out? (There is a global variable YT, but that does not seem to be an official way to check it.)
Currently I am using undocumented solution to check if onYouTubeIframeAPIReady was reached:
if (typeof YT !== 'undefined' && YT.loaded) {
//API is ready
}
There is nothing in the documentation, but looking at the code this is what is used:
window["YT"]

Google translate has stopped working in Chrome

Google translate has stopped working in Chrome but still working in Firefox. The code is below and it was working for long time before now:
<script>
function googleSectionalElementInit() {
new google.translate.SectionalElement({
sectionalNodeClassName: 'can-translate',
controlNodeClassName: 'translation-control',
background: '#ffffcc'
}, 'google_sectional_element');
}
var url = top.location.href,
pos = url.search(/\/\w\w(\W|$)/),
lang = url.substring(pos+1,pos+3),
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = false;
ga.src = 'https://translate.google.com/translate_a/element.js?cb=googleSectionalElementInit&ug=section&hl='+lang;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
})();
</script>
At the moment here is error:
Cross-Origin Read Blocking (CORB) blocked cross-origin response https://translate.googleapis.com/translate_a/l?client=te&alpha=true&hl=en&cb=_callbacks____0jtqeel7c with MIME type application/json. See https://www.chromestatus.com/feature/5629709824032768 for more details.
If it go to the proposed link, here is suggestion:
Make sure these resources are served with a correct "Content-Type" response header from the list below, as well as a "X-Content-Type-Options: nosniff" response header.
Also there is message at https://translate.google.com/intl/en/about/website/
We no longer provide new access to Google Translate's Website Translator. This change does not affect existing use of the Website Translator.
This has affect in Chrome only, code above is Google only and I've no idea where and how to add "X-Content-Type-Options: nosniff".
UPD: there are both of two necessary headers.
Does Google blocked itself and does anyone know how to fix it?
UPD1: Google translate error began to appear and in Firefox 66.0.1 too. It is
The resource from “https://translate.googleapis.com/translate_a/l?client=te&alpha=true&hl=en&cb=_callbacks____0jttrta1j” was blocked due to MIME type (“application/json”) mismatch (X-Content-Type-Options: nosniff).
It looks like some glitch of translation service, after one page refresh it works, after another - server returns incorrect data, json instead of javascript or something like this
At this point, if you manually delete a cookie with the name "NID" for the host .translate.googleapis.com, you can process the page(CORB error disappears)
By the way, repeated page calls also sometimes remove this error. But the solution to the problem is as strange as its occurrence.
Please open a bug via https://crbug.com/new and try to provide as many details as possible:
Did the issue work in Chrome 72 and stopped working in Chrome 73?
Is there a repro page that shows the problem? What is the expected VS observed behavior?
Does the issue repro without any Chrome extensions present?
Does the broken page use AppCache?
I've encountered this issue on multiple sites, it first started on Chrome on my Pixel 2.
The widget does appear on the first load sometimes, if not a reload is all that's required, not even a hard reload. My guess would be that Google are trying to phase the widget out.
The widget does still work without any issues on all other browsers.

Need to include a helper html page in my meteor project

I have a helper.html page that I need to include in my Meteor app to assist with using an api. Looks like this.
<head>
<script type="text/javascript" src="https://www.example.com/api-helper.js"> </script>
</head>
<body>
</body>
Right now I just have it in the root directory of my app. As it is now, here are the problems: the other api script which I have included in main.html, can't find the helper.html. Second, I get this error in the console: Error: Oh no! No route found for path: "/helper.html?. So my question is how do I properly include this helper html page into my Meteor project? Help greatly appreciated.
Thanks
Just put your html file into a folder called public in the root folder.
Error: Oh no! No route found for path: "/helper.html"
This is an error from iron:router, it's complaining that it can't find any route for path "helper.html".
I suppose you get this error message when typing directly http://localhost:3000/helper.html in your browser address bar, which is WRONG because this is not how iron:router is supposed to work.
iron:router manages pure client-side routing using HTML5 push state API contrary to classic server-side routing involved when requesting "/helper.html" to Apache or nginx means the server is going to send you an actual HTML response page displayed by the browser.
In Meteor "single-page apps", the server does not send any HTML responses to the client, it only sends data. It means that the routing takes place entirely in the client, the URL in the address bar gets parsed and iron:router provides utilities to respond accordingly, which usually involves rendering a different template based on which path (route) you hit.
I hope you really understand the difference in nature between these two approaches because this is very important to be aware of when developing with Meteor.
As far as your problem is concerned, I'll take DISQUS integration as an example which seems to be a similar issue.
DISQUS integration on standard PHP solutions is straightforward, you just need to copy-paste this so-called universal embed code :
<div id="disqus_thread"></div>
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = '<example>'; // Required - Replace example with your forum shortname
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the comments powered by Disqus.</noscript>
blog comments powered by <span class="logo-disqus">Disqus</span>
This is fine because once a page gets sent to the client in a traditional website, javascript code gets executed once and we are done : if the user click on another page on the website, the all process of generating the HTML response, sending it to the client and executing JS code will be started from scratch.
However we can't just copy-paste this code inside a Meteor template, because Meteor webapps are "single-page apps", no page reloading process should ever happen in these type of websites.
When we navigate to another page in a Meteor app, the javascript context stays the same and we don't want the DISQUS script to reexecute. What we need to do instead is loading the script only once in the rendered callback of our template.
So we come up with the following Meteor template logic to integrate DISQUS comments loading :
<template name="disqus">
<div id="disqus_thread"></div>
<a href="http://disqus.com" class="dsq-brlink">
blog comments powered by <span class="logo-disqus">Disqus</span>
</a>
</template>
Template.disqus.rendered=function(){
// assumes we get identifier and title as data context
var identifier=this.data.identifier;
var title=this.data.title;
// we need a way to tell if the script has already been loaded or if it's
// the first time, we can check for the existence of the DISQUS variable on
// the global window object to make the difference
if(window.DISQUS){
// DISQUS API has our back, see this resource
// https://help.disqus.com/customer/portal/articles/472107-using-disqus-on-ajax-sites
window.DISQUS.reset({
reload:true,
config:function(){
this.page.identifier=identifier;
this.page.title=title;
}
});
}
else{
// first initialization
window.disqus_shortname = "disqus-shortname";
window.disqus_identifier = identifier;
window.disqus_title = title;
window.disqus_developer = 1;
// load the script via JS instead of embedding it in the HTML
var script = $("<script>",{
type:"text/javascript",
async:true,
src:"//" + disqus_shortname + ".disqus.com/embed.js"
});
$("head").append(script);
}
};
This example demonstrates the way to go when you need to embed API code (google-analytics, DISQUS, etc...) in a Meteor website.

Upgrading to new asynchrous Google Analytics code - should you do it?

I had read somewhere and have now forgotten that upgrading to the new asynchronous code will not enable one to track actual clicks for downloading items when user stays on the same page and that for tracking that you need to use the old version of GA code.
My question is, is that still the case and does anyone have any other reasons for not upgrading to use the newer asynchronous tracking?
thanks
Hmm...are you sure the "old" version of GA automatically tracked downloads? AFAIK GA never automatically tracked download links, that you always had to attach GA code (like a _trackEvent call) to your links yourself. But in any case, it's pretty easy to do it yourself, so it's really not a big deal. Plus, you get lots of benefits upgrading, and one day it may not even be an option to stick with the old version...
If you have jQuery you can for example do this:
// file types you want to consider a download
var downloadFileTypes = ['pdf','doc','docx','mp4'];
$(document).ready(function() {
$('a').filter(function() {
var ext = $(this).attr('href').split('.').pop().toLowerCase();
return ( $.inArray(ext, downloadFileTypes )>-1 );
})
.click(function() {
_gaq.push(['_trackEvent', 'Downloads', $(this).attr('href')]);
});
});
If you do not have a framework like jQuery, you can still do this easy enough with .getElementsByTagName() and using regular loops and conditions instead of the jQuery conveniences like .filter and .inArray
edit: Some things to note about that example:
the jQuery code was an example to hook the GA code to standard links pointing to the file types you specify in downloadFiletypes. It will only apply to links that exist at the time the code is executed. If you have links that may be dynamically generated on the page later, consider looking into .on() instead of .click()
you will need to make tweaks to matching links you want to consider downloads if they do not point to regular files with extensions. For instance, some websites have a controller script that expects a parameter with an ID and it dynamically serves up a pdf or whatever..if your files are like this, you will have to alter the logic to look for that instead.

How can I apply GA download tracking with Sitecore?

I'm posting this question to Stackflow b/c after doing much research into an answer to this very question online, I did not come across a straight forward answer and had to do my own sleuthwork to resolve this.
Basically, Sitecore uses a handler file .ASHX for all files uploaded to the Media Library. Since the 3rd party GA tracking tool I was using (entourage.js or gatags.js) does not recognize .ashx as a whitelisted download file, it was not adding the appropriate GA tracking syntax to the GA pixel tracker (__utm.gif).
So the solution turns out to be simple but sadly, not retroactive, meaning all files previously uploaded to the Media Library in the Sitecore content tree will continue to use the ashx extension unless you reupload the image. In your web.config file, search for the "Media.RequestExtension" setting. If you change the value associated with this setting from "ashx" to a blank string, this will force Sitecore to use the originalextension of the file and image in the Sitecore Media Library.
Aside from interfering with GA analytics, this method of turning every downloadable file extension into an ashx file is poor SEO practice. AND, Sitecore will not point you in the right direction of getting around this other than a round-about way (google Sitecore dynamic linking and configuration) because they want you to use their Sitecore OMS download tracking capability. And that's it! Two days of research led me to this conclusion.
So the solution turns out to be simple but sadly, not retroactive,
meaning all files previously uploaded to the Media Library in the
Sitecore content tree will continue to use the ashx extension unless
you reupload the image.
Not sure where you got this information, but it's incorrect. You can blank out the Media.RequestExtension setting and all existing files will use their original extension. In IIS7 Integrated Mode, you should be able to make this change without having to make other server configuration changes.
Edit: More Info
If you analyze Sitecore.Configuration.Settings.Media.RequestExtension (the API equivalent to this settings) in a decompiler, you can see that it's only used by the MediaProvider when constructing the Media URL. Sitecore should remember the original extension of the media and can serve it with its original URL, regardless of what this setting was when it was uploaded. That's my experience, anyway, and it seems to be validated by looking into Sitecore.Kernel.
You could use this script to track download events via Google Analytics.
if (typeof jQuery != 'undefined') {
jQuery(document).ready(function($) {
var filetypes = /\.(zip|pdf|doc*|xls*|ppt*|jpg|ashx)$/i;
var baseHref = '';
if (jQuery('base').attr('href') != undefined) baseHref = jQuery('base').attr('href');
jQuery('a').each(function() {
var href = jQuery(this).attr('href');
if (href) {
if (href.indexOf('?') != '-1') {
href = href.substring(0, href.indexOf('?'));
}
if (href.match(filetypes)) {
jQuery(this).click(function() {
var extension = String((/[.]/.exec(href)) ? /[^.]+$/.exec(href) : undefined);
var filePath = String(href);
_gaq.push(['_trackEvent', 'Download', extension, filePath]);
if (jQuery(this).attr('target') != undefined && jQuery(this).attr('target').toLowerCase() != '_blank') {
setTimeout(function() {
location.href = baseHref + href;
}, 200);
return false;
}
});
}
}
});
});
}
Just add in the required file types here at this line -
var filetypes = /.(zip|pdf|doc*|xls*|ppt*|jpg|ashx)$/i;
Having done a quick google for gatags.js, I can see that you can add an extension to the whitelist on line 24:
var isDoc = path.match(/\.(?:doc|eps|jpg|png|svg|xls|ppt|pdf|xls|zip|txt|vsd|vxd|js|css|rar|exe|wma|mov|avi|wmv|mp3)($|\&|\?)/);
Change it to:
var isDoc = path.match(/\.(?:ashx|doc|eps|jpg|png|svg|xls|ppt|pdf|xls|zip|txt|vsd|vxd|js|css|rar|exe|wma|mov|avi|wmv|mp3)($|\&|\?)/);
Alternatively, you could attach the Google Analytics _trackEvent yourself with a dom selector and a click event.
Either way, I think OMS can track media library files regardless of extension - removing the default ashx extension doesn't stop the file being handled by Sitecore.

Resources