ga-plugin
Version:
Google Analytics plugin for Brightcove Player in Video Cloud
266 lines (222 loc) • 9.05 kB
text/coffeescript
##
# ga
# https://github.com/mickey/videojs-ga
#
# Copyright (c) 2013 Michael Bensoussan
# Licensed under the MIT license.
##
registerPlugin = videojs.registerPlugin || videojs.plugin;
registerPlugin 'ga', (options = {}) ->
referrer = document.createElement('a')
referrer.href = document.referrer
if (self != top && window.location.host == 'preview-players.brightcove.net' && referrer.hostname == 'studio.brightcove.com')
videojs.log('Google analytics plugin will not track events in Video Cloud Studio')
return
player = @
# this loads options from the data-setup attribute of the video tag
dataSetupOptions = {}
if @options_["data-setup"]
parsedOptions = JSON.parse(@options()["data-setup"])
dataSetupOptions = parsedOptions.ga if parsedOptions.ga
defaultsEventsToTrack = [
'player_load', 'video_load', 'percent_played', 'start',
'end', 'seek', 'play', 'pause', 'resize',
'volume_change', 'error', 'fullscreen'
]
eventsToTrack = options.eventsToTrack || dataSetupOptions.eventsToTrack || defaultsEventsToTrack
percentsPlayedInterval = options.percentsPlayedInterval || dataSetupOptions.percentsPlayedInterval || 10
eventCategory = options.eventCategory || dataSetupOptions.eventCategory || 'Brightcove Player'
# if you didn't specify a name, it will be 'guessed' from the video src after metadatas are loaded
defaultLabel = options.eventLabel || dataSetupOptions.eventLabel
#override the send beacon method - in our case, we need to do data layer pushes
sendbeaconOverride = options.sendbeaconOverride || false
# if debug isn't specified
options.debug = options.debug || false
# if a named tracker should be used
options.trackerName = options.trackerName || null
trackerName = ''
if typeof options.trackerName == 'string'
trackerName = options.trackerName + '.'
# init a few variables
percentsAlreadyTracked = []
startTracked = false
endTracked = false
seekStart = seekEnd = 0
seeking = false
eventLabel = ''
currentVideo = ''
eventNames = {
"video_load": "Video Load",
"percent_played": "Percent played",
"start": "Media Begin",
"seek_start": "Seek start",
"seek_end": "Seek end",
"play": "Media Play",
"pause": "Media Pause",
"error": "Error",
"fullscreen_exit": "Fullscreen Exited",
"fullscreen_enter": "Fullscreen Entered",
"resize": "Resize",
"volume_change": "Volume Change",
"player_load": "Player Load",
"end": "Media Complete"
}
getEventName = ( name ) ->
if options.eventNames && options.eventNames[name]
return options.eventNames[name]
if dataSetupOptions.eventNames && dataSetupOptions.eventNames[name]
return dataSetupOptions.eventNames[name]
if eventNames[name]
return eventNames[name]
return name
# load ga script if in iframe and tracker option is set
if window.location.host == 'players.brightcove.net' || window.location.host == 'preview-players.brightcove.net' || trackerName != ''
tracker = options.tracker || dataSetupOptions.tracker
if tracker
((i, s, o, g, r, a, m) ->
i["GoogleAnalyticsObject"] = r
i[r] = i[r] or ->
(i[r].q = i[r].q or []).push arguments
i[r].l = 1 * new Date()
a = s.createElement(o)
m = s.getElementsByTagName(o)[0]
a.async = 1
a.src = g
m.parentNode.insertBefore a, m
) window, document, "script", "//www.google-analytics.com/analytics.js", "ga"
ga('create', tracker, 'auto', options.trackerName)
ga(trackerName + 'require', 'displayfeatures')
adStateRegex = /(\s|^)vjs-ad-(playing|loading)(\s|$)/
isInAdState = ( player ) =>
return adStateRegex.test( player.el().className )
loaded = ->
if !isInAdState( player )
# Event label is Video Cloud ID | Name, or filename (Perform), or overridden
if defaultLabel
eventLabel = defaultLabel
else
if player.mediainfo && player.mediainfo.id
eventLabel = player.mediainfo.id + ' | ' + player.mediainfo.name
else
eventLabel = @currentSrc().split("/").slice(-1)[0].replace(/\.(\w{3,4})(\?.*)?$/i,'')
if player.mediainfo && player.mediainfo.id && player.mediainfo.id != currentVideo
currentVideo = player.mediainfo.id
percentsAlreadyTracked = []
startTracked = false
endTracked = false
seekStart = seekEnd = 0
seeking = false
if "video_load" in eventsToTrack
sendbeacon( getEventName('video_load'), true )
return
timeupdate = ->
if !isInAdState( player )
currentTime = Math.round(@currentTime())
duration = Math.round(@duration())
percentPlayed = Math.round(currentTime/duration*100)
for percent in [0..99] by percentsPlayedInterval
if percentPlayed >= percent && percent not in percentsAlreadyTracked
if "percent_played" in eventsToTrack && percentPlayed != 0
sendbeacon( getEventName('percent_played'), true, percent )
if percentPlayed > 0
percentsAlreadyTracked.push(percent)
if "seek" in eventsToTrack
seekStart = seekEnd
seekEnd = currentTime
# if the difference between the start and the end are greater than 1 it's a seek.
if Math.abs(seekStart - seekEnd) > 1
seeking = true
sendbeacon( getEventName('seek_start'), false, seekStart )
sendbeacon( getEventName('seek_end'), false, seekEnd )
return
end = ->
if !isInAdState( player ) && !endTracked
sendbeacon( getEventName('end'), true )
endTracked = true
return
play = ->
if !isInAdState( player )
currentTime = Math.round(@currentTime())
sendbeacon( getEventName('play'), true, currentTime )
seeking = false
return
start = ->
if !isInAdState( player )
if "start" in eventsToTrack && !startTracked
sendbeacon( getEventName('start'), true )
startTracked = true
pause = ->
if !isInAdState( player )
currentTime = Math.round(@currentTime())
duration = Math.round(@duration())
if currentTime != duration && !seeking
sendbeacon( getEventName('pause'), true, currentTime )
return
# value between 0 (muted) and 1
volumeChange = ->
volume = if @muted() == true then 0 else @volume()
sendbeacon( getEventName('volume_change'), false, volume )
return
resize = ->
sendbeacon( getEventName('resize') + ' - ' + @width() + "*" + @height(), true )
return
error = ->
currentTime = Math.round(@currentTime())
# XXX: Is there some informations about the error somewhere ?
sendbeacon( getEventName('error'), true, currentTime )
return
fullscreen = ->
currentTime = Math.round(@currentTime())
if @isFullscreen()
sendbeacon( getEventName('fullscreen_enter'), false, currentTime )
else
sendbeacon( getEventName('fullscreen_exit'), false, currentTime )
return
sendbeacon = ( action, nonInteraction, value ) ->
# videojs.log action, " ", nonInteraction, " ", value
if sendbeaconOverride
sendbeaconOverride(eventCategory, action, eventLabel, value, nonInteraction)
else if window.ga
ga trackerName + 'send', 'event',
'eventCategory' : eventCategory
'eventAction' : action
'eventLabel' : eventLabel
'eventValue' : value
'nonInteraction' : nonInteraction
else if window._gaq
_gaq.push(['_trackEvent', eventCategory, action, eventLabel, value, nonInteraction])
else if options.debug
videojs.log("Google Analytics not detected")
return
@ready ->
@on("loadedmetadata", loaded) # use loadstart?
@on("timeupdate", timeupdate)
@on("ended", end) if "end" in eventsToTrack
@on("play", play) if "play" in eventsToTrack
@on("playing", start) if "start" in eventsToTrack
@on("pause", pause) if "pause" in eventsToTrack
@on("volumechange", volumeChange) if "volume_change" in eventsToTrack
@on("resize", resize) if "resize" in eventsToTrack
@on("error", error) if "error" in eventsToTrack
@on("fullscreenchange", fullscreen) if "fullscreen" in eventsToTrack
if "player_load" in eventsToTrack
unless self == top
href = document.referrer
iframe = 1
else
href = window.location.href
iframe = 0
if sendbeaconOverride
sendbeaconOverride(eventCategory, getEventName('player_load'), href, iframe, true)
else if window.ga
ga trackerName + 'send', 'event',
'eventCategory' : eventCategory
'eventAction' : getEventName('player_load')
'eventLabel' : href
'eventValue' : iframe
'nonInteraction' : true
else if window._gaq
_gaq.push(['_trackEvent', eventCategory, getEventName('player_load'), href, iframe, false])
else
videojs.log("Google Analytics not detected")
return 'sendbeacon': sendbeacon