How do I dynamically load Google Analytics JavaScript? - javascript

Without using any other JS frameworks (dojo, jquery, etc), how would I dynamically load Google Analytic's javascript to be used on a web page for web-tracking?
The typical appropriate to dynamically loading JS is to do the following:
var gaJs = document.createElement("script");
gaJs.type = "text/javascript";
gaJs.src = "http://www.google-analytics.com/ga.js";
document.body.appendChild(gaJs);
var pageTracker = _gat._getTracker("UA-XXXXXXXXX");
pageTracker._initData();
pageTracker._trackPageview();
But that doesn't work.
The ga.js file isn't loaded in time for _gat._getTracker & _initData/TrackPageview to function.
Any ideas on how to properly dynamically load ga.js.
UPDATE: Seems like someone has attempted to address this problem at the following link. However, it's for use with the old Urchin code and not Google Analytics.
Any ideas on how to get this to work with ga.js instead of urchin.js?
http://20y.hu/20070805/loading-google-analytics-dynamically-on-document-load.html

You could use this snippet from HTML5 Boilerplate.
<!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
<script>
var _gaq=[['_setAccount','UA-XXXXX-X'],['_trackPageview']];
(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
s.parentNode.insertBefore(g,s)}(document,'script'));
</script>

Server side programming would be easier I guess, but I found this some time ago. Notice that it specifically sets it to the html head.
Also check on the first link down on 'Adding Javascript Through Ajax'.

Try using the exact JavaScript code provided by Google and then conditionally display that section of code based on a construct in your UI framework. You didn't say what platform this is running on, if it's ASP.NET you could put the code in a PlaceHolder or UserControl and then set Visible to true or false based on a config file setting if the script should be included. I've used this approach on multiple sites to prevent the Analytics script from being included in pre-production environments.

function loadGA()
{
if(typeof _gat == 'function') //already loaded
{
//innitGA();
// you may want the above line uncommented..
// I'm presuming that if the _gat object is there
// you wouldn't want to.
return;
}
var hostname = 'google-analytics.com';
var protocol = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
js = document.createElement('script');
js.setAttribute('type', 'text/javascript');
js.setAttribute('src', protocol+hostname+'/ga.js');
document.body.appendChild(js);
//2 methods to detect the load of ga.js
//some browsers use both, however
loaded = false; // so use a boolean
js.onreadystatechange = function () {
if (js.readyState == 'loaded')
{
if(!loaded)
{
innitGA();
}
loaded = true;
}
};
js.onload = function ()
{
if(!loaded)
{
innitGA();
}
loaded = true;
};
}
function innitGA()
{
//var pageTracker = _gat._getTracker('GA_ACCOUNT/PROFILE_ID');
//pageTracker._initData();
//pageTracker._trackPageview();
alert('oh hai I can watch plz?');
}
just call loadGA()... tested on IE6/7/8, FF3, Chrome and Opera
sorry if I'm a bit late to this party.

I've literally just put something together that does this... using jquery. The trick is to add a load event to the script tag with the tracking code in it.
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
var gaScript = document.createElement('script');
var loaded = false;
gaScript.src = gaJsHost + "google-analytics.com/ga.js";
$(gaScript).load(function(){
loaded = true;
var pageTracker = _gat._getTracker(Consts.google_analytics_uacct);
pageTracker._initData();
pageTracker._trackPageview();
});
document.body.appendChild(gaScript);
// And to make it work in ie7 & 8
gaInterval = setInterval(function() {
if (!loaded && typeof _gat != 'undefined') {
$(gaScript).load();
clearInterval(gaInterval);
}
},50);
The thing i'm trying to work out is... is this allowed by google.

Related

Can I use JavaScript to change the JavaScript files a HTML document accesses?

I am trying to write a HTML page that asks users a series of questions. The answers to these questions are evaluated by my JavaScript code and used to determine which additional JavaScript file the user needs to access. My code then adds the additional JavaScript file to the head tag of my HTML page. I don't want to merge the code into a single JavaScript file because these additional files are large enough to be a nightmare if they're together, and I don't want to add them all to the head when the page first loads because I will have too many variable conflicts. I'm reluctant to redirect to a new webpage for each dictionary because this will make a lot of redundant coding. I'm not using any libraries.
I begin with the following HTML code:
<head>
<link rel="stylesheet" type="text/css" href="main.css">
<script src="firstSheet.js" type="text/JavaScript"></script>
</head>
//Lots of HTML.
<div id="mainUserMenu">
</div>
And I have the following JavaScript function:
function thirdLevelQuestions(secondLevelAnswer) {
//Code here to calculate the variables. This part works.
activeDictionary = firstKey + secondKey + '.js';
//Changing the HTML header to load the correct dictionary.
document.head.innerHTML = '<link rel="stylesheet" type="text/css" href="main.css"><script src="' + activeDictionary + '" type="text/JavaScript"></script><script src="firstSheet.js" type="text/JavaScript"></script>';
//for loop to generate the next level of buttons.
for (var i = 0; i < availableOptions.length; i++) {
document.getElementById('mainUserMenu').innerHTML += '<button onclick="fourthLevelQuestions(' + i + ')">' + availableOptions[i] + '</button>';
}
}
This creates the buttons that I want, and when I inspect the head element I can see both JavaScript files there. When I click on any of the buttons at this level they should call a function in the second file. Instead Chrome tells me "Uncaught ReferenceError: fourthLevelQuestions is not defined" (html:1). If I paste the code back into firstSheet.js the function works, so I assume the problem is that my HTML document is not actually accessing the activeDictionary file. Is there a way to do this?
What Can be done
You are trying to load Javascript on Demand. This has been a well thought out problem lately and most of the native solutions didn't work well across bowser implementations. Check a study here with different solutions and background of the problem explained well.
For the case of large web applications the solution was to use some javascript library that helped with modularising code and loading them on demand using some script loaders. The focus is on modularizing code and not in just script loading. Check some libraries here. There are heavier ones which includes architectures like MVC with them.
If you use AJAX implementation of jQuery with the correct dataType jQuery will help you evaluate the scripts, they are famous for handling browser differences. You can as well take a look at the exclusive getScript() which is indeed a shorthand for AJAX with dataType script. Keep in mind that loading script with native AJAX does not guarantee evaluation of the javascript included, jQuery is doing the evaluation internally during the processing stage.
What is wrong
What you have done above might work in most modern browsers (not sure), but there is an essential flaw in your code. You are adding the script tags to your head using innerHTML which inserts those lines to your HTML. Even if your browser loads the script it takes a network delay time and we call it asynchronous loading, you cannot use the script right away. Then what do you do? Use the script when its ready or loaded. Surprisingly you have an event for that, just use it. Can be something like:
var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.type= 'text/javascript';
script.onreadystatechange= function () {
if (this.readyState == 'complete') helper();
}
script.onload= helper;
script.src= 'helper.js';
head.appendChild(script);
Check this article for help with implementation without using external libraries
From the variable name activeDictionary If I guess that you are loading some data sets as opposed to javascript programs, you should try looking into JSON and loading and using them dynamically.
If this Question/Answer satisfies your needs, you should delete your question to avoid duplicate entries in SO.
The best way to achieve this would be with jQuery:
$(document).ready(function() {
$('#button').click(function() {
var html = "<script src='newfile.js' type='text/javascript'></script>";
var oldhtml = "<script src='firstSheet.js' type='text/javascript'></script>";
if ($(this).attr('src') == 'firstSheet.js') {
$('script[src="firstSheet.js"]').replace(html);
return;
}
$('script[src="newfile.js"]').replace(oldhtml);
});
});
I would suggest you create the elements how they should be and then append them. Also, if you are dynamically adding the firstSheet.js you shouldn't include it in your .html file.
function thirdLevelQuestions(secondLevelAnswer) {
var mainUserMenu = document.getElementById('mainUserMenu');
activeDictionary = firstKey + secondKey + '.js';
var css = document.createElement('link');
css.rel = 'stylesheet';
css.type = 'text/css';
css.href = 'main.css';
var script1 = document.createElement('script');
script1.type = 'text/javascript';
script1.src = 'firstSheet.js';
var script2 = document.createElement('script');
script2.type = 'text/javascript';
script2.src = activeDictionary;
document.head.appendChild(css);
document.head.appendChild(script1);
document.head.appendChild(script2);
for (var i = 0; i < availableOptions.length; i++) {
var btn = document.createElement('button');
btn.onclick = 'fourthLevelQuestions(' + i + ')';
var val = document.createTextNode(availableOptions[i]);
btn.appendChild(val);
mainUserMenu.appendChild(btn);
}
}

How to prevent cross domain javascript loading with .htaccess?

The company which developped my website just added this javascript code on the Zend Guard encrypted index.php file (I saw it with "View source") :
(function ()
{
var smrs = document.createElement("script");
smrs.type = "text/javascript";
smrs.async = true;
smrs.src = document.location.protocol + "//www.domain.com/file.js";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(smrs, s);
})();
It injects a very agressive javascript code which adds a image link to their website (with a SetInterval each 10sec), at the bottom of the page.
The problem ? A local competitor, which is currently being accused of significant fraud, have the same CMS and the same image link.
Being associated with that competitor is prejudicial for me. I would like to know if there is a way to block the "www.domain.com/file.js" loading with a .htaccess.
Thanks.
You can't (using htaccess). This javascript creates a script tag to load the external javascript. The call never passes through the server. So apache (htaccess) can't block that.
The easiest way is to search in the source code and remove the script (if you have access).
UPDATE:
I see the script is encrypted... If you can insert a script at the very beginning (before the code gets executed you can create a hook on the insertBefore method. Here is a working fiddle
var ALLOWED_DOMAINS = ['www.klaartjedevoecht.be', 'jsfiddle.net'];
function creatHook(){
function getDomain(url) {
return url.match(/:\/\/(.[^/]+)/)[1];
}
var insertBefore = Element.prototype.insertBefore;
Element.prototype.insertBefore = function(new_node,existing_node){
if(new_node.tagName.toLowerCase() === 'script' && ALLOWED_DOMAINS.indexOf(getDomain(new_node.src)) > -1){
insertBefore.call(this, new_node, existing_node);
}
}
}
creatHook();
//TESTING CODE:
var smrs = document.createElement("script");
smrs.type = "text/javascript";
smrs.async = true;
smrs.src = document.location.protocol + "//www.klaartjedevoecht.be/test.js";
//var smrs = document.createElement("img");
// smrs.src= "http://img52.imageshack.us/img52/7653/beaverl.gif";
var s = document.getElementsByTagName("div")[0];
s.parentNode.insertBefore(smrs, s);
​I agree it's a bit hacking, but at least its cleaner then the timer solution. If you can't remove it, there is no clean solution.

JavaScript - function to load external JS files is needed

Recently I added to my website facebook like button, twitter follow us button and google +1 button. I want their JS scripts to load when I tell them to load.
Therefore, I need a function that load external JS files. I don't need to know when the file finished to load (callback is not needed).
I found some methods/functions on the Internet, but I want to know which would be the best choice for this situation?
4 ways to dynamically load external JavaScript
Dynamically loading JS libraries and detecting when they're loaded
The best way to load external JavaScript
Thanks.
Edit:
Added the methods/function I found.
I would recommend using jQuery's getScript(). For the twitter-button, you would load the corresponding script like that:
$.getScript("//platform.twitter.com/widgets.js")
Of course you would have to load jquery in your script first and do not forget to add the markup needed for the twitter-button in your html.
This might be helpful:
function loadScript(url, callback){
var script = document.createElement("script")
script.type = "text/javascript";
if (script.readyState){ //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" ||
script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
};
} else { //Others
script.onload = function(){
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
Something like
function getScript(url) {
e = document.createElement('script');
e.src = url;
document.body.appendChild(e);
}
getScript('jstoload.js');
this?
The YUI Loader sounds like a good choice for you. It will also allow you to add your own custom modules, so you can load on demand, as well as load all other JS files that are required as well.

Javascript pixel tracking done from an external js file

I'm adding a javascript pixel tracker onto a website, but I'm only trying to have it display on a specific circumstance. That circumstance is being tested for in an external javascript file which then creates the HTML code to echo out.
My question is can the pixel tracking script just stay within that external javascript file? As in not be apart of the echoed out HTML Code that would display in a View Source of the page, and just stay hidden within that external js.
Here is the bulk of the tracking code:
(function () {
var oldonload = window.onload;
window.onload = function(){
__adx_loaded=true;
var scr = document.createElement("script");
var host = (("https:" == document.location.protocol) ? "https://adx.com" : "http://adx.com");
scr.setAttribute('async', 'true');
scr.type = "text/javascript";
scr.src = host + "/j/roundtrip.js";
((document.getElementsByTagName('head') || [null])[0] ||
document.getElementsByTagName('script')[0].parentNode).appendChild(scr);
if(oldonload){oldonload()}};
}());
Yes it can be in an external javascript file.

IE6 does not parse the loaded JavaScript file (Recaptcha hosted by Google)

This is a really strange issue, I am trying to use the Recaptcha on one of the website, and it works for all browsers tested except for IE6.
I have made a reference to the google's js:
http://www.google.com/recaptcha/api/challenge?k=the_key
and it is loaded according to fiddler2 & the 'onreadystatechange' event (which have a readystate == 'loaded')
The normal work flow should be the loaded JS been parsed, and another js been requested, then the image loaded from google. my problem is that the first loaded JS file (content similar to below):
var RecaptchaState = {
site : 'xxxxxxxxxxxx',
challenge : 'xxxxxxxxxxxxxxxxxxxxxxxxx',
is_incorrect : false,
programming_error : '',
error_message : '',
server : 'http://www.google.com/recaptcha/api/',
timeout : 18000
};
document.write('<scr'+'ipt type="text/javascript" s'+'rc="' + RecaptchaState.server + 'js/recaptcha.js"></scr'+'ipt>');
is not parsed. First, the following JS test:
typeof RecaptchaState == 'undefined'
Secondly, there is no second script request (according to fiddler2), not to say the recaptcha image...
The script tag is put inside the body, after the recaptcha markups, and I have even tried to load the JS dynamically:
function GetJavaScript(url, callback) {
var script = document.createElement('script');
script.src = url;
var head = document.getElementsByTagName('head')[0];
var done = false;
// Attach handlers for all browsers
script.onload = script.onreadystatechange = function () {
if (!done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) {
done = true;
callback();
// remove the hanlder
script.onload = script.onreadystatechange = null;
head.removeChild(script);
}
};
head.appendChild(script);
}
which gives same behaviour... what confuses me most is:
this issue occurs occasionally only when the page is redirectly from another page. (open the url directly in new browser window or refresh the page always works fine, however refresh page using JavaScript does not work...)
Please help, any advice and/or idea would be appreciated...
Double check that your script's src in the page source isn't api.recaptcha.net (some libraries use that, I know the Java one I was using did). If it is, that gets forwarded to www.google.com/recaptcha/api, and that seems to cause issues with IE6. Once I switched to using www.google.com/recaptcha/api as the actual script src, IE6 was completely happy. Good luck!
I solved this problem by using the https call, as per this thread in reCaptcha's Google Group.
This is not a solve, just an workaround.
Request the first js file: http://www.google.com/recaptcha/api/challenge?k=the_key
on the server site, and inject the first part of the script on the page directly:
var RecaptchaState = {
site : 'xxxxxxxxxxxx',
challenge : 'xxxxxxxxxxxxxxxxxxxxxxxxx',
is_incorrect : false,
programming_error : '',
error_message : '',
server : 'http://www.google.com/recaptcha/api/',
timeout : 18000
};
Then, using the GetJavaScript function and/or JQuery.getScript() function to load the second script:
http://www.google.com/recaptcha/api/js/recaptcha.js
This solution works for IE6 based on my test, and to make the server less load, I detect the user's browser at server end as well as client end to inject different logic.
I know this is dirty workaround, just in case this might help someone.
NOT ANSWER (or is it?):fo_Ok ie6. Seriously, forget it. Without this attitude ie6 will live forever. It is like ancient evil spirit which will be alive until someone believe in it.

Categories