The Website
Saritias
The Situation
My client wishes to track Google Adwords conversions. A conversion is reached when a customer clicks on an ad, arrives on the website and then books a table using the 3rd Party booking widget (ResDiary).
The Problem
The widget is within an iframe, so as I understand it, this means that the tag manager code inserted into the widget cannot see the Adwords related cookie set by Google in the parent window.
How can I get this to work?
MY SOLUTION
I created 2 accounts in the Tag Manager.
For the Main Site
One for the widget site
The widget site contained a Custom HTML tag that sent an event to the parent iframe:
<script>
var topOrigin = 'http://www.saritas.com.au';
if (window.postMessage) {
window.parent.postMessage('confirmation', topOrigin);
}
</script>
I set the trigger for this to fire on the desired confirmation page in the widget.
For the main site I again used a Custom HTML tag that contained an event listener that makes use of the Google Async Conversion Library and fires the event when the listener is triggered.
<script type="text/javascript" src="http://www.googleadservices.com/pagead/conversion_async.js" charset="utf-8"></script>
<script>
/* <![CDATA[ */
var google_conversion_id = 952604500;
var google_conversion_language = "en";
var google_conversion_format = "3";
var google_conversion_color = "ffffff";
var google_conversion_label = "eMKnCNzU5F8Q1K6exgM";
var google_remarketing_only = false;
/* ]]> */
function trackConv(google_conversion_id, google_conversion_label) {
window.google_trackConversion({
google_conversion_id: google_conversion_id,
google_remarketing_only: false
});
}
// Replace with your domain here.
var allowedOrigins = ['https://widget-au.resdiary.com'];
function xDomainHandler(event) {
event = event || window.event;
var origin = event.origin;
// Check for the whitelist.
var found = false;
for (var i = 0; i < allowedOrigins.length; i++) {
if (allowedOrigins[i] == origin) {
found = true;
break;
}
}
if (!found) return;
// Might be a different message.
if (event.data != 'confirmation') return;
trackConv(google_conversion_id, google_conversion_label);
}
if (window.addEventListener) {
window.addEventListener('message', xDomainHandler, false);
} else if (window.attachEvent) {
window.attachEvent('onmessage', xDomainHandler);
}
</script>
I set the trigger for this to be for the single page the the widget appears.
Related
I'm trying to setup a send event from a iframe originated on my domain and placed on other domain (not mine). I placed the analytics code on the iframe.
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXX-XX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-XXXXXXXX-XX',{ 'anonymize_ip': true });
</script>
Bellow that analytics code (with the UA-XXXXXXXX-XX from my parentdomain.com), I do a check to see if the iframe is not on my parentdomain.com and then, I set the tracker attribute to the div id ads_close:
<script>
ref = document.referrer;
whitelist = ["parentdomain.com"];
match = false;
for( var i = whitelist.length - 1; i >= 0; i-- ) {
if( ref.indexOf( whitelist[ i ] ) > -1 ) { match = true; }
}
// If is not the parent domain, then add the onClick atributte to the ID "ads_close"
if( ! match ) {
refer = document.referrer;
var str1 ="gtag(\'event\', \'External\', {\'event_category\': \'yes\',\'event_label\': ";
var str2 = "'";
var str3 = refer;
var str4 = "'";
var str5 = "});";
var tracker = str1.concat(str2) + str3 + str4 + str5;
ads_close.setAttribute("onClick", tracker);
}
</script>
The above code renders this way, IF NOT, on parentdomain.com:
<div class="adspop_close" id="adspop_close" onclick="gtag('event', 'Externos', {'event_category': 'yes','event_label': 'https://www.theotherdomain.com/post/'});"></div>
The problem:
Every time i click on the the div with the ID adspop_close, I cannot see the event on my parentdomain.com google analytics account...
The question:
What am'I doing wrong?
If you try to track data from the iframe itself it will appear as if the interaction is happening on another domain in another session, which is what I think you're trying to avoid. If you want to track interactions in an iframe and act as if they were part of the parent container then the best way is by using postMessage to communicate the event to the parent, where it can be handled naturally. The containing page does not have script access to the iframe for security reasons, but the iframe can send communicate to the containing page via postMessage.
solution 1
The Google Development Guide shows us an approach for this cross-domain interaction (scroll down to the IFRAME section).
To link the interactions into the same session you need to share client id's. Unortunately, iframes typically initalize with the HTML of the page, long before google tracking has the client ID ready. So we can't just pass it on load, but need to wait for everything and then use postMessage.
Here's the containing page code example:
<iframe id="destination-frame" src="https://destination.com"></iframe>
<script>
ga('create', 'UA-XXXXX-Y', 'auto');
ga(function(tracker) {
// Gets the client ID of the default tracker.
var clientId = tracker.get('clientId');
// Gets a reference to the window object of the destionation iframe.
var frameWindow = document.getElementById('destination-frame').contentWindow;
// Sends the client ID to the window inside the destination frame.
frameWindow.postMessage(clientId, 'https://destination.com');
});
</script>
And here's the listener that would be in the iframe:
window.addEventListener('message', function(event) {
// Ignores messages from untrusted domains.
if (event.origin != 'https://destination.com') return;
ga('create', 'UA-XXXXX-Y', 'auto', {
clientId: event.data
});
});
That page also has some extra logic to handle the situation where a client id never comes through postMessage. If you need to pass through the 'UA' string as well and wait to initialize gtag in the iframe completely, that's doable as well. Once you recieve the data you need, initialize gtag and track away. You won't need to rewrite any DOM.
solution 2
You can invert the logic of the postMessage communication instead. Rather than doing any tracking in the iframe at all, you can set up any events to trigger a postMessage instead, passing the information like category, action, and label up to the containing page. In the containing page you would add a listener for the postMessage and handle it by triggering a gtag event.
For instance, from the iframe:
<script>
try {
var postObject = JSON.stringify({
event: 'iframeClickEvent',
category: 'someCategory',
action: 'someAction',
label: 'someLabel'
});
parent.postMessage(postObject, 'https://www.YOURWEBSITE.com');
} catch(e) {
window.console && window.console.log(e);
}
</script>
and the containing page:
window.addEventListener('message', function(message) {
try{
var data = JSON.parse(message.data);
var dataLayer = window.dataLayer || (window.dataLayer = []);
if (data.event === 'iframeClickEvent') {
dataLayer.push({ 'event': 'someEvent', .... });
}
} catch(e){}
});
I found this script in the head of a website:
<script type="text/javascript" >
function Ext_Detect_NotInstalled(ExtName,ExtID) {
}
function Ext_Detect_Installed(ExtName,ExtID) {
alert("We have found unwanted extension. Please contact support")
window.location = "logout.php"
}
var Ext_Detect = function(ExtName,ExtID) {
var s = document.createElement('script');
s.onload = function(){Ext_Detect_Installed(ExtName,ExtID);};
s.onerror = function(){Ext_Detect_NotInstalled(ExtName,ExtID);};
s.src = 'chrome-extension://' + ExtID + '/captured.js';
document.body.appendChild(s);
}
var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
function displayErrorAndLogout() {
alert("Please use chrome browser to view the content");
window.location = "logout.php"
}
if (is_chrome==true)
{
window.onload = function() { Ext_Detect('Chrome','ngpampappnmepgilojfohadhhmbhlaek');};
} else {
is_chrome = navigator.userAgent.toLowerCase().indexOf('crios') > -1;
if (is_chrome == false){
if (detectIE()){
displayErrorAndLogout()
}
if (navigator.userAgent.indexOf('UCBrowser') > -1) {
displayErrorAndLogout()
}
This script check internet download manager extension and popup a logout message.
Is this possible to remove or alter this inline java script using Greasemonkey?
If you want to disable the check for the Chrome addon, it's easy: the script assigns a function to onload, so if you simply assign something else to onload, Ext_Detect will never run, and your extension will not be detected:
window.onload = () => null;
Unfortunately, the other part that checks for crios and UCBrowser and runs detectIE runs synchronously, presumably at the beginning of page load, and userscripts cannot reliably run at the very beginning of page load, so that behavior may not be possible to alter, though you could try it with #run-at document-start: displayErrorAndLogout calls alert before assigning to window.location, so if you make it so that alert throws an error, the location will not change:
#run-at document-start
// ==/UserScript==
window.alert = function() {
throw new Error();
};
Good day,
I'm trying to configure the AdWords conversion code for my website and I can't find any of the information I'm looking for in Google documentation. Ultimatly, I want to track a onClick event on the submit input of the form.
I want to know what should I include in my onClick event, since the send button doesn't lead to another page, but have an AJAX loading?
My AdWords tracking code is :
<script type="text/javascript">
/* <![CDATA[ */
goog_snippet_vars = function() {
var w = window;
w.google_conversion_id = 12345678;
w.google_conversion_label = "abcDeFGHIJklmN0PQ";
w.google_remarketing_only = false;
}
// DO NOT CHANGE THE CODE BELOW.
goog_report_conversion = function(url) {
goog_snippet_vars();
window.google_conversion_format = "3";
window.google_is_call = true;
var opt = new Object();
opt.onload_callback = function() {
if (typeof(url) != 'undefined') {
window.location = url;
}
}
var conv_handler = window['google_trackConversion'];
if (typeof(conv_handler) == 'function') {
conv_handler(opt);
}
}
/* ]]> */
</script>
<script type="text/javascript"
src="//www.googleadservices.com/pagead/conversion_async.js">
</script>
Ultimately, I was looking for the conversion to be saved only if the form is sucessfully sent (After Javascript validation). I could not use the onClick on the button, because it would save the conversion even if the form has not submited due to an invalid value in a field.
The easiest way to do so, was to add this in jQuery :
$('#contactform').submit(function(e){
if( $( this ).valid() ) {
goog_report_conversion ('http://example.com/your-link') // Change for your page link.
alert("Conversion!"); // Confirmation that the conversion has been sent. Remove after testing.
}
});
I guess it's too late, but for the future generations. There is a built-in way for AdWords to do this.
It is described in this article.
In brief you would need to change setting in AdWords it would generate you async tag, which you load with the DOM, and activate with onClick handler.
Example:
<a onclick="goog_report_conversion ('http://example.com/your-link')"
href="http://example.com/your-link">Download now!</a>
You can load de of the noscript version.
So, in you onClick event, append the img to some element on the page and it will load it and will count the conversion.
I have some code on my tumblr blog that makes it so the links in the "notes" div open in a new tab — it works fine but once i click "Show More Notes" (which loads more links), it stops working on those links. Here is my code.
<script type="text/javascript">
$(function(){
$("#notes a").attr("target","_blank");
});
</script>
Here is what tumblr says on this issue: "Notes are paginated with AJAX. If your theme needs to manipulate the Notes markup or DOM nodes, you can add a Javascript callback that fires when a new page of Notes is loaded or inserted"
tumblrNotesLoaded(notes_html) "If this Javascript function is defined, it will be triggered when a new page of Notes is loaded and ready to be inserted. If this function returns false, it will block the Notes from being inserted."
tumblrNotesInserted() "If this Javascript function is defined, it will be triggered after a new page of Notes has been inserted into the DOM."
the newly loaded links wont have target set to _blank ... what you should do, when you've loaded the new links is execute
$("#notes a").attr("target","_blank");
again - as you've shown no code regarding the loading of these links, that's the best I can do
edit: I just looked at your page - I think this should do the trick
this.style.display = 'none';
document.getElementById('notes_loading_121152690941').style.display = 'block';
if (window.ActiveXObject) var tumblrReq = new ActiveXObject('Microsoft.XMLHTTP');
else if (window.XMLHttpRequest) var tumblrReq = new XMLHttpRequest();
else return false;
tumblrReq.onreadystatechange = function() {
if (tumblrReq.readyState == 4) {
var notes_html = tumblrReq.responseText.split('<!-- START ' + 'NOTES -->')[1].split('<!-- END ' + 'NOTES -->')[0];
if (window.tumblrNotesLoaded)
if (tumblrNotesLoaded(notes_html) == false) return;
var more_notes_link = document.getElementById('more_notes_121152690941');
var notes = more_notes_link.parentNode;
notes.removeChild(more_notes_link);
notes.innerHTML += notes_html;
if (window.tumblrNotesInserted) tumblrNotesInserted(notes_html);
// ************************************************
$("#notes a").attr("target","_blank");
// ************************************************
}
};
tumblrReq.open('GET', '/notes/121152690941/lhtXynZtK?from_c=1433902641', true);
tumblrReq.send();
return false;
the added line is surrounded by // ************************************************
You could set target attribute on mousedown delegated event, e.g:
$(function () {
$('#notes').on('mousedown', 'a:not([target])', function () {
this.target = "_blank";
});
});
Use this:
$('ol.notes').on('click', 'a', function (e) {
if (e.which > 1 || e.shiftKey || e.altKey || e.metaKey || e.isDefaultPrevented()) {
return;
}
window.open(this.href);
e.preventDefault();
});
This attaches an event handler on the notes container, making sure that it only gets clicks on a elements and that the clicks are not middle-clicks, alt-clicks, …
Once all of those superfluous clicks are filtered out, it simply opens a new tab via Javascript; there's no need to set target="_blank"
I read this article about tracking outbound links on banners and such:
http://seogadget.co.uk/how-to-count-your-outbound-click-stats-with-onclick-in-google-analytics/
So I added this code to the onClick event of my href:
javascript: pageTracker._trackPageview('/outbound/top_banners/banner_name');
Is this enough?
Because I have read some places I need a "link delay" function or something in the HEAD of my document as well, before any javascript is executed!
Also, where exactly in GA (in the interface) will I be able to view the clicks?
Thanks
Here's the problem: every item of data recorded & reported by Google Analytics is sent to the GA Servers in the Request URL component of a Request by the client for the __utm.gif. The function _.trackPageview() provokes the collection/concatenation of the data into a Request URL, as well as the Request itself. In other words, if _trackPageview() isn't called, no data is sent to the GA Servers.
So the question is whether the GA Request (above) is processed before the Request associated with the outbound link. If it is not, then the click on the outbound link is not recorded by GA, which is not what you want.
So what you want to is delay, just slightly--long enough for the GA Request to occur but short enough so that the user doesn't notice the delay--the outbound link Request.
There are a few differences between the code posted in your Q, and the code below--all diffs are directed to this 'race condition'.
First, notice that the return value from the onClick handler is set to "false"--preventing the client browser from (immediately) navigating to http://www.outbound-link.com
The second diff is the call to setTimeout. The third argument passed in, '100' is the number of milliseconds delay.
Third, the onclick handler (fnx) creates its own tracking object, and therefore doesn't rely on a pageTracker object to have been initialized elsewhere.
Your second question is, where in the GA Browser do you view these clicks? Using GA, you can track events in two distinct ways--using _trackEvent() or _trackPageView().
By tracking outbound links the second way (as you did and therefore as i did below) the 'click' shows up not as an event, but as a pageview ('virtual pageview' is the term most often used by the GA Consultants, et al. to indicate something tracked as a page view but which is actually not). So you will see these clicks reported along with other page views--i.e., in Content (along with Traffic and Visitors, the three main headings in the left-hand panel). How can you tell which lines in that report refer to the these outbound clicks? The value of the Page field (usually the left-most column heading) will be the url of the outbound link. Once you know this, of course, you can create an Advanced Segment or Custom Report or even a new Profile, to report these separately.
<script type="text/javascript">
function fnx(that) {
try {
var pageTracker=_gat._getTracker("UA-YOURACCOUNTHERE-PROFILE");
pageTracker._trackPageview("http://www.outbound_link.com");
setTimeout('document.location = "' + that.href + '"', 100)
}catch(err){}
}
</script>
<a href="www.outbound_link.com" onclick='fnx(this);return false;'>"Take Me Here"</a>
This is my 100%-working solution for tracking all outbound links (I love jQuery, so you need to add jquery.js script to page).
function isLinkExternal(link) {
var r = new RegExp('^https?://(?:www.)?' + location.host.replace(/^www./, ''));
return !r.test(link);
}
$(document).ready(function() {
$(document).bind('click', function(e) {
var target = (window.event) ? e.srcElement : e.target;
while (target) {
if (target.href) break;
target = target.parentNode;
}
if (!target || !isLinkExternal(target.href)) return true;
var link = target.href;
link = '/outgoing/' + link.replace(/:\/\//, '/');
_gaq.push(['_trackPageview', link]);
});
});
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-YOURCODE-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
This script give all outbound links to GA like: /outgoing/http/www.example.com.
For better experience you need to create advanced segment for this links. Create it with parameters: "Page" "Starts with" "/outgoing/http".
That's all! Now you have full statistics for your outbound links.
This solution will allow you to click links with target='_blank' and additionally, will allow you to set data attributes on any link and have those automatically send up to GA.
$('a').bind('click', function( event ) {
var target = $(this).attr('href');
if ($(this).attr("data-event-category") !== undefined && $(this).attr("data-event-label") !== undefined) {
gtag('event', 'click', {
'event_category': $(this).attr("data-event-category"),
'event_label': $(this).attr("data-event-label"),
'event_callback': function(){handle_redirect($(this), event);}
});
} else {
handle_redirect($(this), event);
}
});
function handle_redirect(element, event) {
var target = element.attr('href');
var regExp = new RegExp("//" + location.host + "($|/)");
var isLocal = (target.substring(0,4) === "http") ? regExp.test(target) : true;
var url = target;
if(isLocal===true) {
return;
} else {
event.preventDefault();
gtag('event', 'click', {
'event_category': 'outbound',
'event_label': window.location.href + ' --> ' + url,
'transport_type': 'beacon',
'event_callback': function(){element.unbind( "click"); element[0].click();}
});
}
}