Brightcove Video Tracking

Gold Contributor
Gold Contributor

Hi, I'm trying to tackle Brightcove video tracking for Google Analytics. I saw the great post for SiteCatalyst but found it hard to adapt to my needs.

 

I found a separate Brightcove event listener at http://www.analytics-ninja.com/blog/2016/03/tracking-brighcove-videos-with-gooogle-analytics.html which I've adapted for Tealium:

 

// Tracking for BrightCove Player
// David Vallejo (@thyng)

try {
    // CODE START
    Number.prototype.padLeft = function(base, chr) {
        var len = (String(base || 10).length - String(this).length) + 1;
        return len > 0 ? new Array(len).join(chr || '0') + this : this;
    }

    jQuery(function() {
        var $ = jQuery;
        var placeholder = '<div></div>';
        
        // Loop thru all players in the page and reload them with needed params
        jQuery('object.BrightcoveExperience').each(function() {
            // Let's grab the videoId, playerKey, PlayerId, width and heigh values to create an updated player object later.
            var flashvars = $(this).attr('data').replace(/(^\?)/, '').split("&").map(function(n) {
                return n = n.split("="), this[n[0]] = n[1], this
            }.bind({}))[0];
            var playerTemplate = '<object class="BrightcoveExperience"><param name="@videoPlayer" value="' + flashvars['%40videoPlayer'] + '" /><param name="playerID" value="' + flashvars.playerID + '" /><param name="playerKey" value="' + flashvars.playerKey + '" /><param name="width" value="' + flashvars.width + '" /><param name="height" value="' + flashvars.height + '" /><param name="bgcolor" value="#FFFFFF" /><param name="isVid" value="true" /><param name="isUI" value="true" /> <param name="dynamicStreaming" value="true" /> <param name="includeAPI" value="true" /> <param name="templateLoadHandler" value="onTemplateLoad" />  </object>';
            var $p = $(placeholder);
            var $orig = $(this).replaceWith($p);
            $p.replaceWith(playerTemplate);

        });

        brightcove.createExperiences();
        return true;
    });

    // onTemplateLoad function, here is where the listeners are added.
    function onTemplateLoad() {
        var bcPlayers = [];
        var APIModules = brightcove.api.modules.APIModules;

        // Let's grab all the players in the page, and set the listeners for them
        for (expId in brightcove.experiences) {
            if (expId.indexOf('bcExperienceObj') > -1) {
                var player = brightcove.api.getExperience(expId);

                bcPlayers[expId] = player.getModule(APIModules.VIDEO_PLAYER);
                bcPlayers[expId]["progress_already_fired"] = {};
                bcPlayers[expId].addEventListener(brightcove.api.events.MediaEvent.BEGIN, self.onMediaEventFired);
                bcPlayers[expId].addEventListener(brightcove.api.events.MediaEvent.COMPLETE, onMediaEventFired);
                bcPlayers[expId].addEventListener(brightcove.api.events.MediaEvent.PLAY, onMediaEventFired);
                bcPlayers[expId].addEventListener(brightcove.api.events.MediaEvent.STOP, onMediaEventFired);
                bcPlayers[expId].addEventListener(brightcove.api.events.MediaEvent.COMPLETE, onMediaEventFired);
                bcPlayers[expId].addEventListener(brightcove.api.events.MediaEvent.SEEK_NOTIFY, onMediaEventFired);
                bcPlayers[expId].addEventListener(brightcove.api.events.MediaEvent.PROGRESS, onMediaProgressFired);

            }
        }



        // This is gonna be fired on every Begin, Play, Complete, Stop, Pause, Seek Events
        function onMediaEventFired(e) {
            var d = e.media.publishedDate;
            var c = e.media.creationDate;          
            var action = e.type.replace("media", "").toLowerCase();
            if (action == "stop") action = "pause";
            if (Math.floor(100 * e.position / e.duration) > 99 && action == "pause") {
                return;
            }
            utag.link({
                'eventName': 'video interaction',
                'video_interaction': 'video ' + action,
                'video_id': e.media.id,
                'video_name': e.media.displayName,
                'video_description': e.media.shortDescription,
                'video_length': e.duration,
                'video_creation_date': [c.getFullYear(), (c.getMonth() + 1).padLeft(), c.getDate().padLeft()].join('-') + ' ' + [c.getHours().padLeft(), c.getMinutes().padLeft(), c.getSeconds().padLeft()].join(':'),              
                'video_publish_date': [d.getFullYear(), (d.getMonth() + 1).padLeft(), d.getDate().padLeft()].join('-') + ' ' + [d.getHours().padLeft(), d.getMinutes().padLeft(), d.getSeconds().padLeft()].join(':'),
                'video_category': null,
                'video_publisher_id': e.media.publisherId,
                'video_publisher_name': e.media.publisherName,
                'video_thumbnail': e.media.customFields.imagepath,
                'video_codec': e.rendition.videoCodec,
                'video_size': e.rendition.size,
                'video_provider': 'brightcove'

            });
        }

         // Video Progress Tracking
         function onMediaProgressFired(e) {
            var divisor = 25;
            var pct = Math.floor(100 * e.position / e.duration);

            var progress_point = divisor * Math.floor(pct / divisor);

            if (progress_point == 0) { //dont sent event on 0% progress
                return;
            }
            if (bcPlayers[expId]["progress_already_fired"][progress_point]) {
                return;
            }

            bcPlayers[expId]["progress_already_fired"][progress_point] = true;
            var d = e.media.publishedDate;
            var c = e.media.creationDate;          
            utag.link({
                'eventName': 'video interaction',
                'video_interaction': 'video percent ' + progress_point,
                'video_id': e.media.id,
                'video_name': e.media.displayName,
                'video_description': e.media.shortDescription,
                'video_length': e.duration,
                'video_creation_date': [c.getFullYear(), (c.getMonth() + 1).padLeft(), c.getDate().padLeft()].join('-') + ' ' + [c.getHours().padLeft(), c.getMinutes().padLeft(), c.getSeconds().padLeft()].join(':'),              
                'video_publish_date': [d.getFullYear(), (d.getMonth() + 1).padLeft(), d.getDate().padLeft()].join('-') + ' ' + [d.getHours().padLeft(), d.getMinutes().padLeft(), d.getSeconds().padLeft()].join(':'),
                'video_category': null,
                'video_publisher_id': e.media.publisherId,
                'video_publisher_name': e.media.publisherName,
                'video_thumbnail': e.media.customFields.imagepath,
                'video_codec': e.rendition.videoCodec,
                'video_size': e.rendition.size,
                'video_provider': 'brightcove'
            });
        }
    }
    // CODE END

} catch (e) {}

This works great in the console when I try it, and I can see the utag.link calls go by for the video progression in debug mode in the console. However, when I put this code in a Javascript Extension scoped to DOM Ready, nothing happens; the utag.link calls are not sent.


Am I missing something?

 

Thanks!

7 REPLIES 7

Brightcove Video Tracking

Gold Contributor
Gold Contributor

It sounds like you are using GA @audrey_poulin. Have you seen this video? 

 

https://community.tealiumiq.com/t5/Tags-and-Client-side/Video-Event-Tracking-with-Google-Universal-A...

 

Hoping this helps. 

Brightcove Video Tracking

Employee Emeritus

Hello @audrey_poulin. Have you seen this video?

 

https://community.tealiumiq.com/t5/Tags-and-Client-side/Video-Event-Tracking-with-Google-Universal-A...

 

Let's see if this will work for you. 

Remember to give me a kudo if you like my post! Accepting my post as a solution is even better! Also remember that search is your friend.

Brightcove Video Tracking

Employee Emeritus

@Paul Jinx!

Remember to give me a kudo if you like my post! Accepting my post as a solution is even better! Also remember that search is your friend.

Brightcove Video Tracking

Gold Contributor
Gold Contributor

Hi,

Yes, and I did implement event tracking for several other things for my GA tag.

 

My issue is with the video listener in the Javascript extension.

When I use the listener directly in the console with the Tealium debug cookie, my utag.link fires without a hitch :

 

video.PNG

 

However, when I implement the same code that I pasted in my first post in a Javascript extension scoped to DOM ready, the utag.link calls are not sent (I do not see them in my console in debug mode as I do when I paste the listener in my console).

Thanks

Brightcove Video Tracking

Tealium Employee

Hey @audrey_poulin,

When setting up video tracking in the past, I've had similar experiences. Whenever I was having the same behavior, wherein the code works just fine when pasted and run in console, but doesn't run when loaded in a JS Code extension, it was because of a timing issue. Specifically the JS Code extension was running before the video player had loaded on the page. When I was running the code in console, I had no problem because that was usually well after the page had finished loading. I'm not familiar with the exact circumstances you're working in, but you can try changing the scope of the JS Code extension to DOM Ready, so it waits for the DOMReady signal before trying to run your tracking code. However, if the videos are being loaded in an AJAX fashion, that is the video player isn't loaded until some action by the visitor is taken, you might have to use something like a SetTimeOut or SetInterval function to check for the presence of the video player.

Brightcove Video Tracking

Tealium Employee
Edit: I just saw your comment about moving the code to a DOM Ready-scoped extension. Apologies!

Brightcove Video Tracking

Gold Contributor
Gold Contributor

Hi @Seth,

Yes, my extension was scoped to DOM Ready, and the videos are static (loaded on page load).

I opened a ticket with support, hopefully they can see what's wrong there.

Thanks!

Public