General Information
Analytics is now served as a standalone service and you can integrate this component into any javascript-based project other than the empPlayer. Android/iOS libraries already send analytics by themselves. Also, for the empPlayer, analytics are sent automatically aswell. If your project is using an old analytics setup: for instance via plugin or calling the method setAnalytics, you can remove that code from your project as it is no longer necessary.
Being a standalone component, EMPAnalytics can now be integrated with more products other than EMPPlayer.
This tutorial will show you how to use EMP Analytics. When using the new component, please do not forget to remove the old video.js analytics plugin from your setup, otherwise the EMPPlayer might send duplicated analytics events.
The new analytics service is delivered with some important bug fixes.
We will no longer deliver new features or bug fixes to the old video.js analytics plugin.
This component collects playback events and sends them every 3s to EMP Exposure backend.
In case no event has been generated and a playback is taking place, a Heartbeat event is sent every 60 seconds.
Usage
Installation
npm install empanalytics
In browser, node or react-native
import EMPAnalytics from 'EMPAnalytics';
var EMPAnalytics = require('EMPAnalytics');
Configuration
The following configuration values are required when the plugin is created:
- customer & businessUnit values provided by EMP project team
- serverURL EMP exposure API analytics endpoint
- sessionToken token returned by EMP exposure login API
- userId unique user identifier
If you use the EntitlmentEngine provided by EMP, in order to have analytics, all you have to do is pass these values in as options when instantiating the player:
var exposureOptions = {
'customer': customer.customer,
'businessUnit': customer.businessUnit,
'sessionToken': session.sessionToken,
'exposureApiURL': apiUrl
};
var options = {
'ericssonexposure': exposureOptions,
}
If you use your own entitlment engine, just include these properties directly as options in your entitlement engine:
yourEMPPlayerObjec.entitlementEngine_.options_ = {
'customer': customer.customer,
'businessUnit': customer.businessUnit,
'sessionToken': session.sessionToken,
'exposureApiURL': apiUrl
}
Methods
Constructor
var deviceInfoData = {
deviceModel: DEVICE_MODEL_STRING,
userAgent: USER_AGENT_STRING,
screenHeight: SCREEN_HEIGHT,
screenWidth: SCREEN_WIDTH,
deviceName: DEVICE_NAME_STRING,
deviceOS: DEVICE_OS_STRING,
deviceOSVersion: DEVICE_OS_VERSION_STRING,
type: DEVICE_TYPE_STRING,
deviceManufacturer: DEVICE_MANUFACTURER_STRING,
deviceId: DEVICE_ID_STRING,
};
var properties = {
disableWebWorkers: DISABLE_BOOLEAN
}
constructor(serverURL, customer, businessUnit, sessionToken, userId, deviceInfoData, properties)
Init
init();
Clear
clear();
Debug
debug = true | false;
Created
var params = {
autoplay: true
techName: TECH_NAME,
version: TECH_VERSION,
player: PLAYER_IDENTIFIER,
deviceAppInfo: APP_INFO_STRING,
playMode: PLAY_MODE_STRING
};
created(sessionId, params);
Play
var params = {
techName: TECH_NAME,
version: TECH_VERSION,
deviceAppInfo: APP_INFO_STRING,
playMode: PLAY_MODE_STRING
};
play(sessionId, startTime, params);
Playing
var params = {
bitrate: BITRATE_IN_BYTES,
duration: DURATION_IN_SECONDS,
mediaLocator: MEDIA_URL
referenceTime: UNIX_TIME_OF_THE_BEGINNING_OF_STREAM_IN_MS,
playMode: PLAY_MODE_STRING
};
playing(sessionId, currentTime, params);
Paused
paused(sessionId, currentTime);
Seek
seek(sessionId, seekTime);
Start Casting
startCasting(sessionId, nowTime);
Stop Casting
stopCasting(sessionId, nowTime);
Set Current Time
setCurrentTime(sessionId, nowTime);
Handshake
var params = {
assetId: EMP_ASSET_ID,
programId: EMP_PROGRAM_ID
};
handshake(sessionId, params);
Resume
resume(sessionId, startTime, params);
Bitrate Changed
var params = {
bitrate: BITRATE_IN_BYTES
};
bitrateChanged(sessionId, nowTime, params);
DRM Session Update
var params = {
message: [WIDEVINE_CERTIFICATE_REQUEST, FAIRPLAY_CERTIFICATE_REQUEST
WIDEVINE_CERTIFICATE_RESPONS, FAIRPLAY_CERTIFICATE_RESPONSE
WIDEVINE_LICENSE_REQUEST, PLAYREADY_LICENSE_REQUEST, FAIRPLAY_LICENSE_REQUEST
WIDEVINE_LICENSE_RESPONS, PLAYREADY_LICENSE_RESPONSE, FAIRPLAY_LICENSE_RESPONSE
WIDEVINE_LICENSE_ERROR, PLAYREADY_LICENSE_ERROR, FAIRPLAY_LICENSE_ERROR]
code: 0,
info: 'info',
};
drmSessionUpdate(sessionId, params);
End Of Stream
endOfStream(sessionId, params = {});
Error
var params = {
errorCode: ERROR_CODE,
errorMessage: ERROR_MESSAGE
};
error(sessionId, nowTime, params = {});
Dispose
dispose(sessionId, nowTime, params = {});
Waiting
waiting(sessionId, nowTime, params = {});
Waiting Ended
waitingEnded(sessionId, nowTime, params = {});
Get Session State
getSessionState(sessionId);
Dispatch Now
dispatchNow(asyncCall = true);
Exit Ongoing Session
exitOngoingSession(nowTime);
Set Custom Attribute
setCustomAttribute(key, value);
Clear Custom Attributes
clearCustomAttributes();
Usage Example
HTML Code
index.html
<html>
<head>
<script src="emp-analytics.min.js"></script>
<script src="html5player-analytics-connector.js"></script>
</head>
<body>
<video id="sample-video" autoplay>
<source src=http://techslides.com/demos/sample-videos/small.webm type=video/webm>
<source src=http://techslides.com/demos/sample-videos/small.ogv type=video/ogg>
<source src=http://techslides.com/demos/sample-videos/small.mp4 type=video/mp4>
<source src=http://techslides.com/demos/sample-videos/small.3gp type=video/3gp>
</video>
<script>
var SERVER_URL = 'YOUR_ANALYTICS_SERVER_URL';
var CUSTOMER = 'YOUR_CUSTOMER';
var BUSINESS_UNIT = 'YOUR_BUSINESS_UNIT';
var SESSION_TOKEN = 'YOUR_SESSION_TOKEN';
var html5player = document.getElementById('sample-video');
var analytics = new empAnalytics (SERVER_URL, CUSTOMER, BUSINESS_UNIT, SESSION_TOKEN);
analytics.init();
var connector = new HTML5PlayerAnalyticsConnector(html5player, analytics);
connector.init();
</script>
</body>
</html>
Javascript Connector Code
html5player-analytics-connector.js
var HTML5PlayerAnalyticsConnector = function(html5player, analytics) {
this.player_ = html5player;
this.analytics_ = analytics;
this.onLoadStartBind = this.onLoadStart.bind(this);
this.onCanPlayBind = this.onCanPlay.bind(this);
this.onPlayingBind = this.onPlaying.bind(this);
this.onEndedBind = this.onEnded.bind(this);
this.onPauseBind = this.onPause.bind(this);
this.onSeekedBind = this.onSeeked.bind(this);
this.onErrorBind = this.onError.bind(this);
this.onAbortBind = this.onAbort.bind(this);
this.onWindowUnloadBind = this.onWindowUnload.bind(this);
this.init();
};
HTML5PlayerAnalyticsConnector.prototype.init = function() {
this.dispose();
this.rnd_ = Math.random();
this.player_.addEventListener('loadstart', this.onLoadStartBind);
this.player_.addEventListener('canplay', this.onCanPlayBind);
this.player_.addEventListener('playing', this.onPlayingBind);
this.player_.addEventListener('ended', this.onEndedBind);
this.player_.addEventListener('pause', this.onPauseBind);
this.player_.addEventListener('seeked', this.onSeekedBind);
this.player_.addEventListener('error', this.onErrorBind);
this.player_.addEventListener('abort', this.onAbortBind);
window.addEventListener('beforeunload', this.onWindowUnloadBind);
};
HTML5PlayerAnalyticsConnector.prototype.getSessionId = function() {
return 'ANALYTICS-DEMO-' + this.rnd_;
};
HTML5PlayerAnalyticsConnector.prototype.onLoadStart = function() {
this.onGeneric('HandShake', this.analytics_.handshake, function() {
var params = {
'assetId': 'YOUR_ASSET_ID',
'programId': 'YOUR_PROGRAM_ID'
};
this.analytics_.handshake(this.getSessionId(), params);
}.bind(this), false);
};
HTML5PlayerAnalyticsConnector.prototype.sendCurrentTime = function() {
var sessionId = this.getSessionId();
if (this.analytics_.getSessionState &&
this.analytics_.getSessionState(sessionId) === 'PLAYING') {
this.analytics_.setCurrentTime(sessionId, this.player_.currentTime);
}
};
HTML5PlayerAnalyticsConnector.prototype.clearTimers = function() {
if(this.currentTimeTimer_) {
clearInterval(this.currentTimeTimer_);
}
this.currentTimeTimer_ = null;
};
HTML5PlayerAnalyticsConnector.prototype.registerCurrentTimeTimer = function() {
this.clearTimers();
this.currentTimeTimer_ = setInterval(function() { this.sendCurrentTime(); }.bind(this), 1000);
};
HTML5PlayerAnalyticsConnector.prototype.onCanPlay = function() {
var currentSessionId = this.getSessionId();
this.onGeneric('Created', this.analytics_.created, function() {
var params = {
'autoplay': true
};
this.analytics_.created(currentSessionId, params);
this.onStartPlay();
}.bind(this), false);
};
HTML5PlayerAnalyticsConnector.prototype.onStartPlay = function() {
this.onGeneric('Play', this.analytics_.play, function() {
var params = {
'techName' : 'NativeHTML5',
'version' : '1.0',
'techVersion': '1.0'
};
this.analytics_.play(this.getSessionId(), 0.0, params);
this.registerCurrentTimeTimer();
}.bind(this), false);
};
HTML5PlayerAnalyticsConnector.prototype.onPause = function() {
this.onGeneric('Pause', this.analytics_.paused, function() {
this.analytics_.paused(this.getSessionId(), this.player_.currentTime);
}.bind(this), true);
};
HTML5PlayerAnalyticsConnector.prototype.onPlaying = function() {
this.onGeneric('Playing', this.analytics_.playing, function() {
let params = {
'bitrate': 'YOUR_BITRATE',
'duration': this.player_.duration,
'mediaLocator': 'MEDIA_URL'
};
this.analytics_.playing(this.getSessionId(), this.player_.currentTime, params);
}.bind(this), false);
};
HTML5PlayerAnalyticsConnector.prototype.onEnded = function() {
var currentSessionId = this.getSessionId();
this.onGeneric('End of Stream', this.analytics_.endOfStream, function() {
this.analytics_.endOfStream(currentSessionId);
}.bind(this), true, true);
};
HTML5PlayerAnalyticsConnector.prototype.onSeeked = function() {
this.onGeneric('Seeked', this.analytics_.seek, function() {
this.analytics_.seek(this.getSessionId(), this.player_.currentTime);
}.bind(this), true);
};
HTML5PlayerAnalyticsConnector.prototype.onError = function() {
this.onGeneric('Error', this.analytics_.error, function() {
const params = {
'code': 'YOUR_ERROR_CODE',
'errorMessage': 'YOUR_MESSAGE'
};
this.analytics_.error(this.getSessionId(), this.player_.currentTime, params);
}.bind(this), false);
};
HTML5PlayerAnalyticsConnector.prototype.onAbort = function() {
this.onGeneric('Dispose', this.analytics_.dispose, function() {
this.analytics_.dispose(this.getSessionId());
}.bind(this), true, true);
};
HTML5PlayerAnalyticsConnector.prototype.onWindowUnload = function() {
this.onGeneric('WindowClose', this.analytics_.dispose, function() {
this.analytics_.dispose(this.getSessionId(), this.player_.currentTime);
this.analytics_.dispatchNow(false);
}.bind(this), true);
};
HTML5PlayerAnalyticsConnector.prototype.onGeneric = function(eventName, eventFnc, callback) {
if (eventFnc && callback) {
callback();
}
else {
console.log('\'' + eventName + '\' was discarded.');
}
};
HTML5PlayerAnalyticsConnector.prototype.dispose = function() {
this.clearTimers();
this.player_.removeEventListener('loadstart', this.onLoadStartBind);
this.player_.removeEventListener('canplay', this.onCanPlayBind);
this.player_.removeEventListener('playing', this.onPlayingBind);
this.player_.removeEventListener('ended', this.onEndedBind);
this.player_.removeEventListener('pause', this.onPauseBind);
this.player_.removeEventListener('seeked', this.onSeekedBind);
this.player_.removeEventListener('error', this.onErrorBind);
this.player_.removeEventListener('abort', this.onAbortBind);
window.removeEventListener('beforeunload', this.onWindowUnloadBind);
};