Wistia Event Listener
How to track Wistia Video Engagements with google tag manager
If you have a Wistia video embedded on your website, you can measure how users consume your video content.
Use the data to build a marketing audience, segmentation analysis on how the video engagement impacts your conversions, website engagement metrics, marketing funnel, and other KPIs.
To implement this, start by creating a new custom HTML tag type in Google Tag Manager, copy and paste the Wistia event listener code in this tag, fire it on DOM Ready or Window loaded (Recommended)
What this code does is listen for Wistia video activities such as;
- Play and Pause
- Video Progress (0, 10, 25, 50, 75, 90, 100) percent
To fire your tags when this event happens, you can create a custom event trigger with the name
🚨 This event
gets fired for all Wistia video interactions.
Using Google Tag Manager dataLayer variables, you can get more data about the Wistia video, which includes;
[videoProvider] –> returns the Wistia all time
[videoAction] –> returns the video actions, pause play, percent, etc.
[videoLabel] –> gets the video name
[videoHashedID] –> gets the Wistia video ID
[videoURL] –> this is the video URL
To have these data available in your analytics tool or advertising platform, you’ll have to create the needed tag and attach the Wistia video trigger.
💡 You can streamline the event to fire on specific Wistia interactions by using the dataLayer variables and trigger conditions
You can customize the event listener to fire on a specific percentage and what interval you want by either watching the demonstration in the video or following the steps;
at the bottom of the Wistia video event listener javascript code, you should see a code like this;
‘every’: 25,
‘each’: [0, 10, 90]
}
});
</script>
‘every’: 25 means it should happen every 25%,
while the ‘each’: [0, 10, 90] meaning it should also fire on 0% (meaning the video just started), 10% and 90% video progress
To customize this, change the value to your needs and the Wistia video progress events are triggered based on your customizations.
🏆CREDIT:
Bounteous (Formely LunaMetrics) created the script, all we did was customize the progress, including the Wistia video ID and video URL variable to the dataLayer.
<script type="text/javascript" id="gtm-wistia-tracking"> ; (function(document, window, config) { 'use strict'; config = cleanConfig(config); var _wq = window._wq = window._wq || []; var handle = getHandler(config.syntax); var f, s; _wq.push({ id: '_all', onReady: listenTo }); if (isUndefined_(window.Wistia)) { f = document.getElementsByTagName('script')[0]; s = document.createElement('script'); s.src = '//fast.wistia.net/assets/external/E-v1.js'; s.async = true; f.parentNode.insertBefore(s, f); } function listenTo(video) { var percentages = config._track.percentages; var eventNameDict = { 'Played video': 'play', 'Paused video': 'pause', '100%': 'end' }; var cache = {}; forEach_(['Played video', '100%'], function(key) { if (config.events[key]) { video.bind(eventNameDict[key], function() { handle(key, video); }); } }); if (config.events.Pause) { video.bind('pause', function() { if (video.percentWatched() !== 1) handle('Paused video', video); }); } if (percentages) { video.bind('secondchange', function(s) { var percentage = video.percentWatched(); var key; for (key in percentages) { if (percentage >= percentages[key] && !cache[key]) { cache[key] = true; handle(key, video); } } }); } } function cleanConfig(config) { config = extend_({}, { events: { 'Played video': true, 'Paused video': true, '100%': true }, percentages: { each: [], every: [] } }, config); var key; var vals; forEach_(['each', 'every'], function(setting) { var vals = config.percentages[setting]; if (!isArray_(vals)) vals = [vals]; if (vals) config.percentages[setting] = map_(vals, Number); }); var points = [].concat(config.percentages.each); if (config.percentages.every) { forEach_(config.percentages.every, function(val) { var n = 100 / val; var every = []; var i; for (i = 1; i < n; i++) every.push(val * i); points = points.concat(filter_(every, function(val) { return val > 0.0 && val < 100.0; })); }); } var percentages = reduce_(points, function(prev, curr) { prev[curr + '%'] = curr / 100.0; return prev; }, {}); config._track = { percentages: percentages }; return config; } function getHandler(syntax) { syntax = syntax || {}; var gtmGlobal = syntax.name || 'dataLayer'; var uaGlobal = syntax.name || window.GoogleAnalyticsObject || 'ga'; var clGlobal = '_gaq'; var dataLayer; var handlers = { 'gtm': function(state, video) { dataLayer.push({ event: 'video', videoProvider: 'Wistia', videoAction: state, videoLabel: video.name(), videoHashedID: video.hashedId(), videoURL: document.location.origin + document.location.pathname + '?' + video.hashedId() }); }, 'cl': function(state, video) { window[clGlobal].push(['_trackEvent', 'Videos', state, video.name()]); }, 'ua': function(state, video) { window[uaGlobal]('send', 'event', 'Videos', state, video.name()); } }; switch(syntax.type) { case 'gtm': dataLayer = window[gtmGlobal] = window[gtmGlobal] || []; break; case 'ua': window[uaGlobal] = window[uaGlobal] || function() { (window[uaGlobal].q = window[uaGlobal].q || []).push(arguments); }; window[uaGlobal].l = +new Date(); break; case 'cl': window[clGlobal] = window[clGlobal] || []; break; default: if (!isUndefined_(window[gtmGlobal])) { syntax.type = 'gtm'; dataLayer = window[gtmGlobal] = window[gtmGlobal] || []; } else if (uaGlobal&& !isUndefined_(window[uaGlobal])) { syntax.type = 'ua'; } else if (!isUndefined_(window[clGlobal]) && !isUndefined_(window[clGlobal].push)) { syntax.type = 'cl'; } break; } return handlers[syntax.type]; } function extend_() { var args = [].slice.call(arguments); var dst = args.shift(); var src; var key; var i; for (i = 0; i < args.length; i++) { src = args[i]; for (key in src) { dst[key] = src[key]; } } return dst; } function isArray_(o) { if (Array.isArray_) return Array.isArray_(o); return Object.prototype.toString.call(o) === '[object Array]'; } function forEach_(arr, fn) { if (Array.prototype.forEach_) return arr.forEach.call(arr, fn); var i; for (i = 0; i < arr.length; i++) { fn.call(window, arr[i], i, arr); } } function map_(arr, fn) { if (Array.prototype.map_) return arr.map.call(arr, fn); var newArr = []; forEach_(arr, function(el, ind, arr) { newArr.push(fn.call(window, el, ind, arr)); }); return newArr; } function filter_(arr, fn) { if (Array.prototype.filter) return arr.filter.call(arr, fn); var newArr = []; forEach_(arr, function(el, ind, arr) { if (fn.call(window, el, ind, arr)) newArr.push(el); }); return newArr; } function reduce_(arr, fn, init) { if (Array.prototype.reduce) return arr.reduce.call(arr, fn, init); var result = init; var el; var i; for (i = 0; i < arr.length; i++) { el = arr[i]; result = fn.call(window, result, el, arr, i); } return result; } function isUndefined_(thing) { return typeof thing === 'undefined'; } })(document, window, { 'events': { 'Played video': true, 'Paused video': true, '100%': true }, 'percentages': { 'every': 25, 'each': [0, 10, 90] } }); </script>