Created
July 21, 2012 22:33
-
-
Save igrigorik/3157441 to your computer and use it in GitHub Desktop.
Analytics patch to enable "time on slide" and "outbound click" tracking with Google Analytics, for http://code.google.com/p/io-2012-slides/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 4a3bb99fe5eecd06e77f4fedb5729466df09750f Mon Sep 17 00:00:00 2001 | |
From: Ilya Grigorik <[email protected]> | |
Date: Fri, 18 May 2012 06:41:34 +0800 | |
Subject: [PATCH] add outbound click tracking + time on slide analytics | |
plugins for GA | |
--- | |
js/analytics/outbound-clicks.js | 102 +++++++++++++++++++++++++++++++++++++++ | |
js/analytics/time-on-slide.js | 25 ++++++++++ | |
js/slide-deck.js | 5 ++ | |
3 files changed, 132 insertions(+), 0 deletions(-) | |
create mode 100644 js/analytics/outbound-clicks.js | |
create mode 100644 js/analytics/time-on-slide.js | |
diff --git a/js/analytics/outbound-clicks.js b/js/analytics/outbound-clicks.js | |
new file mode 100644 | |
index 0000000..950cd7b | |
--- /dev/null | |
+++ b/js/analytics/outbound-clicks.js | |
@@ -0,0 +1,102 @@ | |
+/** | |
+ * A little script to handle outbound link tracking in Google Anlaytics. | |
+ * Links are tracked as events. | |
+ * @author nickski15@ (Nick Mihailovski) | |
+ */ | |
+ | |
+// Namespace. | |
+var _gaq = _gaq || []; | |
+ | |
+function trackOutboundLinks(options) { | |
+ return function() { | |
+ var debug = options.debug || false; | |
+ var element = options.element || document; | |
+ var eventName = options.eventName || 'click'; | |
+ | |
+ var traverseDepth = 1; | |
+ var anchorUrl = ''; | |
+ var anchorTarget = ''; | |
+ var cleanUrl = ''; | |
+ | |
+ if (element.addEventListener) { | |
+ element.addEventListener(eventName, checkEvent); | |
+ } else { | |
+ element.attachEvent('on' + eventName, checkEvent); | |
+ } | |
+ | |
+ function checkEvent(event) { | |
+ var event = event || window.event; | |
+ var targetElement = event.target || event.srcElement; | |
+ | |
+ var anchor = getParentAnchor(targetElement, traverseDepth); | |
+ if (anchor && isOutbound(anchor)) { | |
+ | |
+ // prevent default behavior. | |
+ if (event.preventDefault) { | |
+ event.preventDefault(); | |
+ } else { | |
+ event.returnValue = false; | |
+ } | |
+ anchorUrl = anchor.href; | |
+ anchorTarget = anchor.target; | |
+ | |
+ track(); | |
+ } | |
+ }; | |
+ | |
+ function getParentAnchor(targetElement, depth) { | |
+ if (targetElement.tagName == 'A') { | |
+ return targetElement; | |
+ } else if (targetElement.tagName == 'BODY' || depth < 0) { | |
+ return; | |
+ } else { | |
+ targetElement = targetElement.parentNode; | |
+ return getParentAnchor(targetElement, --depth); | |
+ } | |
+ } | |
+ | |
+ function isOutbound(anchor) { | |
+ var anchorParts = anchor.href.split('//'); | |
+ | |
+ // "//" must be present to continue. | |
+ if (anchorParts.length < 2) { | |
+ return false; | |
+ } | |
+ cleanUrl = anchorParts[1]; | |
+ | |
+ // Remove port, then remove path. | |
+ var hostname = cleanUrl.split(':')[0].split('/')[0]; | |
+ if (document.location.hostname != hostname) { | |
+ return true; | |
+ } | |
+ return false; | |
+ } | |
+ | |
+ function track() { | |
+ window._gaq.push(['_set', {'hitCallback': hitCallback}]); | |
+ var command = ['_trackEvent', 'outboundLink', cleanUrl]; | |
+ if (debug) { | |
+ console.log(command); | |
+ } else { | |
+ window._gaq.push(command); | |
+ } | |
+ } | |
+ | |
+ function hitCallback() { | |
+ if (debug) { | |
+ return; | |
+ } | |
+ if (anchorTarget == '_blank') { | |
+ window.open(anchorUrl); | |
+ } else if (anchorTarget == '_top') { | |
+ window.top.location = anchorUrl; | |
+ } else if (anchorTarget == '_parent') { | |
+ window.parent.location = anchorUrl; | |
+ } | |
+ // If no target or _self. | |
+ window.location = anchorUrl; | |
+ } | |
+ } | |
+}; | |
+ | |
+_gaq.push(trackOutboundLinks({'debug': false})); | |
\ No newline at end of file | |
diff --git a/js/analytics/time-on-slide.js b/js/analytics/time-on-slide.js | |
new file mode 100644 | |
index 0000000..66c62df | |
--- /dev/null | |
+++ b/js/analytics/time-on-slide.js | |
@@ -0,0 +1,25 @@ | |
+/** | |
+ * Simple analytics plugin to track time on slide (via user timings). | |
+ * To view the reports: Content > Site Speed > User Timings | |
+ * @author: igrigorik (Ilya Grigorik) | |
+ */ | |
+ | |
+var slideStartTime = new Date(), | |
+ oldSlideNum = window.slidedeck.curSlide_ + 1, | |
+ timeOnSlide; | |
+ | |
+document.addEventListener('slideenter', function(e) { | |
+ timeOnSlide = new Date() - slideStartTime; | |
+ slideStartTime = new Date(); | |
+ | |
+ if (document.location.hostname == 'localhost') { | |
+ console.log('slide enter: ' + e.slideNumber + ", was on slide: " + oldSlideNum + ", time: " + timeOnSlide); | |
+ } else { | |
+ // filter out transitions under 2s and over 20 minutes | |
+ if (timeOnSlide >= 2000 && timeOnSlide <= 120000) { | |
+ _gaq.push(['_trackTiming', 'slide', String(oldSlide), timeOnSlide, 'slide ' + oldSlide, 100]); | |
+ } | |
+ } | |
+ | |
+ oldSlideNum = window.slidedeck.curSlide_ + 1; | |
+}, false); | |
\ No newline at end of file | |
diff --git a/js/slide-deck.js b/js/slide-deck.js | |
index 696767e..94be785 100644 | |
--- a/js/slide-deck.js | |
+++ b/js/slide-deck.js | |
@@ -737,6 +737,11 @@ SlideDeck.prototype.loadAnalytics_ = function() { | |
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); | |
})(); | |
+ | |
+ // load analytics plugins | |
+ Modernizr.load({ | |
+ load: ['js/analytics/time-on-slide.js', 'js/analytics/outbound-clicks.js'] | |
+ }) | |
}; | |
-- | |
1.7.7.5 (Apple Git-26) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment