Soundcloud How to Separate Tags When Uploading
According to their website, SoundCloud is "the globe'south leading social sound platform where anyone can create sounds and share them everywhere". For artists, it's a aqueduct for distributing previews of their tracks, and for people like me it's a nice way to exercise some API tinkering. To each their ain, I judge!
I saw a number of requests in the Google+ Google Tag Manager customs about a SoundCloud integration, and so I decided to look into it to run across if I could just build 1.
SoundCloud has something called the Widget API, which listens for window.postMessage calls from within the embedded SoundCloud iframes. The benefit of this versus, for example, the YouTube API is that you don't need to practise anything to the iframe itself to brand this work. All you need to practise is load the Widget API, and so signal which iframe(south) you want to listen to for interactions.
X The Simmer Newsletter Subscribe to the Simmer newsletter to become the latest news and content from Simo Ahava into your electronic mail inbox!
The setup
For this to work, you will need the following:
-
Custom HTML Tag which loads the Widget API, adds the listeners, and does the
dataLayer.push button()calls -
Custom Result Trigger which fires your Tag when a SoundCloud event is registered
-
Data Layer Variables for Issue Category, Outcome Action, and Event Label
-
Event Tag which fires when the Trigger is activated, and sends the outcome hitting to Google Analytics
The most circuitous component is the Custom HTML Tag, so let'due south start at that place.
The Custom HTML Tag
Here's the total Tag code. Re-create-paste it into a new Custom HTML Tag:
<!-- Load the SoundCloud API synchronously --> <script src="https://w.soundcloud.com/player/api.js"></script> <!-- Initiate the API integration --> <script> (function() { try { // initWidget is chosen when a SoundCloud iframe is found on the page var initWidget = role(w) { var currentSound, act, pos, q1, q2, q3, get, lab; var true cat = 'SoundCloud'; var widget = SC.Widget(w); // Events.READY is dispatched when the widget has been loaded widget.demark(SC.Widget.Events.Gear up, function() { // Get the title of the currently playing sound widget.getCurrentSound(function(cs) { lab = cs['title']; }); // Fire a dataLayer event when Events.PLAY is dispatched widget.bind(SC.Widget.Events.PLAY, function() { human action = 'Play'; sendDl(true cat, human action, lab); }); // Burn down a dataLayer event when Events.Pause is dispatched // The merely exception is when the sound ends, and the machine-pause is not reported widget.bind(SC.Widget.Events.PAUSE, function(obj) { pos = Math.round(obj['relativePosition'] * 100); if (pos !== 100) { act = 'Pause'; sendDl(cat, act, lab); } }); // Every bit the play progresses, transport events at 25%, 50% and 75% widget.bind(SC.Widget.Events.PLAY_PROGRESS, function(obj) { go = false; pos = Math.round(obj['relativePosition'] * 100); if (pos === 25 && !q1) { human action = '25%'; q1 = true; get = true; } if (pos === 50 && !q2) { act = 'l%'; q2 = true; go = truthful; } if (pos === 75 && !q3) { act = '75%'; q3 = true; become = true; } if (go) { sendDl(cat, human action, lab); } }); // When the sound finishes, transport an event at 100% widget.bind(SC.Widget.Events.FINISH, function() { act = '100%'; q1 = q2 = q3 = simulated; sendDl(cat, act, lab); }); }); }; // Generic method for pushing the dataLayer event // Utilise a Custom Issue Trigger with "scEvent" every bit the result name // Remember to create Data Layer Variables for eventCategory, eventAction, and eventLabel var sendDl = function(cat, act, lab) { window.dataLayer.push({ 'event' : 'scEvent', 'eventCategory' : cat, 'eventAction' : human action, 'eventLabel' : lab }); }; // For each SoundCloud iFrame, initiate the API integration var i,len; var iframes = certificate.querySelectorAll('iframe[src*="api.soundcloud.com"]'); for (i = 0, len = iframes.length; i < len; i += 1) { initWidget(iframes[i]); } } grab(due east) { console.log('Error with SoundCloud API: ' + e.message); } })(); </script> Make sure this Custom HTML Tag fires upon a Page View Trigger, where the Trigger Blazon is DOM Ready. If it doesn't piece of work, try changing the Trigger Type to Window Loaded. It's possible a race condition emerges, where the Custom HTML Tag is fired before your SoundCloud widgets are loaded, and shifting the Trigger to fire on Window Loaded should remedy that.
Let's chop it up into pieces so we'll sympathise what's happening. This time, we'll get-go from the end!
// For each SoundCloud iFrame, initiate the API integration var i,len; var iframes = certificate.querySelectorAll('iframe[src*="api.soundcloud.com"]'); for (i = 0, len = iframes.length; i < len; i += 1) { initWidget(iframes[i]); } The code above goes through all the iframes on the folio. If it encounters an iframe that loads an embedded SoundCloud Widget, it calls the initWidget method, using the iframe object every bit a parameter. This is as simple as it gets. The absurd thing is that each iframe gets its ain bindings, then you tin run the script with multiple SoundCloud widgets on the page!
var initWidget = function(w) { var currentSound, act, pos, q1, q2, q3, go, lab; var true cat = 'SoundCloud'; var widget = SC.Widget(westward); // Events.Fix is dispatched when the widget has been loaded widget.bind(SC.Widget.Events.READY, office() { // Get the title of the currently playing audio widget.getCurrentSound(function(cs) { lab = cs['title']; }); The initWidget office is called for all the SoundCloud iframes on the folio. First, it declares some utility variables. Next, it uses the Widget API SC.Widget constructor to create a new widget object the API uses for the bindings.
On the post-obit lines, the SC.Widget.Events.READY event is bound to the widget object. This event is fired when the embedded SoundCloud object has loaded and is set to exist interacted with. All the listeners are put into this function callback, every bit we don't desire to start listening for events earlier the embedded file has loaded, right?
The showtime thing we do is get the title of the audio, and for that nosotros demand to use the asynchronous getCurrentSound function, whose callback returns the sound object. Then, we admission this object's championship key and store it in a variable. Now we accept all the static variables divers, and nosotros can create our four listeners.
// Fire a dataLayer result when Events.PLAY is dispatched widget.bind(SC.Widget.Events.PLAY, role() { deed = 'Play'; sendDl(cat, act, lab); }); The start listener is bound to the SC.Widget.Events.PLAY consequence, which, surprisingly, is dispatched when a "Play" event is recorded in the widget. Once that happens, we set up the act variable to "Play", and invoke the sendDl (see below) method, which does the dataLayer.push button(). Parameters are the cat ("SoundCloud"), human action ("Play"), and lab (Sound championship) variables.
// Fire a dataLayer event when Events.Intermission is dispatched // The only exception is when the sound ends, and the automobile-interruption is non reported widget.bind(SC.Widget.Events.PAUSE, part(obj) { pos = Math.circular(obj['relativePosition'] * 100); if (pos !== 100) { human action = 'Intermission'; sendDl(cat, act, lab); } }); The side by side event nosotros'll bind is SC.Widget.Events.Pause, which is dispatched when a "Pause" event is recorded in the widget. Information technology's practically the same as the "Play" upshot, merely we need to add ane extra check there. SoundCloud auto-pauses the sound when it's completed, so GA would receive a number of "Pause" events that were not initiated by the user. That'southward why we accept the check on the first line of the callback, where we basically see if the "Suspension" event occurred when the position of the sound is at 100%. This would point that it's an auto-pause, and we won't invoke sendDl in that case.
// Every bit the play progresses, send events at 25%, fifty% and 75% widget.demark(SC.Widget.Events.PLAY_PROGRESS, function(obj) { become = false; pos = Math.round(obj['relativePosition'] * 100); if (pos === 25 && !q1) { act = '25%'; q1 = true; get = truthful; } if (pos === 50 && !q2) { act = '50%'; q2 = true; go = true; } if (pos === 75 && !q3) { human activity = '75%'; q3 = true; become = true; } if (go) { sendDl(true cat, act, lab); } }); The adjacent binding is for the SC.Widget.Events.PLAY_PROGRESS. This event is dispatched every few milliseconds, and the object it returns has the relative position of the audio at the time of the event. This relative position is actually a per centum of how far the user has listened to the track. And so, because I've called to send an effect at 25%, 50%, 75% and 100%, I need to check if the relative position is at these milestones. I also employ a couple of booleans, q1 q2 q3 get, which prevent the same milestone from beingness sent multiple times. The go variable ensures that the GA Event is simply fired when the milestones are reached, and non for every unmarried iteration of the PLAY_PROGRESS event.
// When the sound finishes, send an event at 100% widget.bind(SC.Widget.Events.FINISH, function() { human action = '100%'; q1 = q2 = q3 = false; sendDl(cat, act, lab); }); Finally, when the sound finishes, we send the 100% event, and we likewise reset the utility variables. If we don't reset them, repeated listenings would not be recorded.
// Generic method for pushing the dataLayer effect // Use a Custom Effect Trigger with "scEvent" equally the event name // Call back to create Data Layer Variables for eventCategory, eventAction, and eventLabel var sendDl = office(cat, act, lab) { window.dataLayer.push({ 'consequence' : 'scEvent', 'eventCategory' : cat, 'eventAction' : act, 'eventLabel' : lab }); }; And here'south the sendDl method. It just takes the parameters, and pushes them into a dataLayer object.
The Trigger
To activate GTM Tags when a SoundCloud consequence is registered, create a new Custom Issue Trigger that looks like this:
Information technology's a uncomplicated 1. This Trigger volition fire your Tags when the sendDl method we built above is invoked.
The Data Layer Variables
Next, make sure you have iii Data Layer Variables. One for eventCategory, one for eventAction, and ane for eventLabel. They'd await something like this:
These are pretty generic, then you might observe them useful elsewhere too.
The Event Tag
Finally, you demand an Event Tag to carry this information to Google Analytics. Set it up every bit you would any other Effect Tag, and make sure information technology fires with the Trigger yous created before (Event - scEvent). And so, add together the 3 Variables you created to their respective fields:
And that's it! Now your site should be ready to collect hits from SoundCloud widgets.
Summary and caveats
First, some caveats.
Every now and then I noticed an annoying race condition, where the widget had loaded before the GTM Custom HTML Tag had time to complete. This means that the SC.Widget.Events.READY was dispatched too early for the listener to catch it. This race condition could be fixed by having a timeout of a 2nd or something, which then does the bindings anyhow. I didn't write information technology into this solution, but information technology should be pretty trivial to implement in one case y'all empathise how the Widget API works.
Some other things I noticed were quota errors from the API. There'due south nix you tin practice about these, though I believe yous can subscribe to some Premium account where these errors don't crop upwardly. As far every bit I could tell, however, they had no touch on on this tracking solution, and the events were sent yet.
Anyhow, this is a pretty unproblematic solution for tracking SoundCloud widgets on your site. I've tried to mirror the first-class YouTube tracking guide by Cardinal Path.
The Widget API has a number of other interfaces you tin tap into if y'all desire to make the solution fifty-fifty better. Let me know if you encountered any bug, or if you have ideas how to meliorate this solution!
Source: https://www.simoahava.com/analytics/google-tag-manager-soundcloud-integration/
0 Response to "Soundcloud How to Separate Tags When Uploading"
Post a Comment