Skip to content

Commit

Permalink
feat(FEC-11195): Google Analytics 4 support (#55)
Browse files Browse the repository at this point in the history
Add support to send analytics to both Universal Analytics and Google Analytics 4 or to one of them

Solves FEC-11195
  • Loading branch information
yairans authored Jun 20, 2021
1 parent 0b10fdf commit 4ec0b8b
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 60 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ Finally, add the bundle as a script tag in your page, and initialize the player
player: {
plugins: {
googleAnalytics: {
trackingId: 'UA-1234567-89'
trackingId: 'UA-1234567-89',
trackingGA4Id: 'G-0123456789'
}
...
}
Expand Down
15 changes: 13 additions & 2 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The configuration uses the following structure:
```js
{
trackingId: string,
trackingGA4Id: string,
tracking: {
category: string | function,
label: string | function,
Expand Down Expand Up @@ -35,9 +36,19 @@ The configuration uses the following structure:
>
> ##### Type: `string`
>
> ##### required: `true`
> ##### required: `false`
>
> ##### Description: The Universal Analytics Account ID (Can be configured in addition to the `trackingGA4Id`, one of them is mandatory).

##

> ### trackingGA4Id
>
> ##### Type: `string`
>
> ##### required: `false`
>
> ##### Description: The Google Analytics tracking ID.
> ##### Description: The GA4 data stream ID (Can be configured in addition to the `trackingId`, one of them is mandatory).

##

Expand Down
12 changes: 10 additions & 2 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,18 @@ const customLaunchers = {
}
};

const launchers = {
Chrome_browser: {
base: 'Chrome',
flags: ['--no-sandbox', '--autoplay-policy=no-user-gesture-required']
}
};

module.exports = config => {
const karmaConf = {
logLevel: config.LOG_INFO,
browsers: ['Chrome', 'Firefox'],
customLaunchers: launchers,
browsers: ['Chrome_browser', 'Firefox'],
concurrency: 1,
singleRun: true,
colors: true,
Expand All @@ -34,7 +42,7 @@ module.exports = config => {
client: {
mocha: {
reporter: 'html',
timeout: 10000
timeout: 2000
}
}
};
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
"flow-bin": "^0.129.0",
"husky": "^4.2.5",
"istanbul": "^0.4.5",
"kaltura-player-js": "https://github.com/kaltura/kaltura-player-js.git#v1.0.0",
"kaltura-player-js": "https://github.com/kaltura/kaltura-player-js.git#v1.7.5",
"karma": "^5.1.0",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^3.1.0",
Expand All @@ -100,7 +100,7 @@
},
"peerDependencies": {
"@playkit-js/playkit-js": "0.63.0",
"kaltura-player-js": "https://github.com/kaltura/kaltura-player-js.git#v1.0.0"
"kaltura-player-js": "https://github.com/kaltura/kaltura-player-js.git#v1.7.5"
},
"publishConfig": {
"access": "public"
Expand Down
8 changes: 5 additions & 3 deletions src/google-analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export default class GoogleAnalytics extends BasePlugin {
*/
constructor(name: string, player: Player, config: Object) {
super(name, player, config);
if (this.config.trackingId) {
if (this.config.trackingId || this.config.trackingGA4Id) {
this._init();
this._addBindings();
this._sendEvent({
Expand Down Expand Up @@ -92,15 +92,17 @@ export default class GoogleAnalytics extends BasePlugin {
*/
_init(): void {
if (!window.google_tag_manager) {
Utils.Dom.loadScriptAsync(`${GoogleAnalytics.GTAG_LIB_URL}?id=${this.config.trackingId}`).then(() => {
Utils.Dom.loadScriptAsync(`${GoogleAnalytics.GTAG_LIB_URL}?id=${this.config.trackingId || this.config.trackingGA4Id}`).then(() => {
this.logger.debug('Google gtag library has loaded successfully');
});
}
window.dataLayer = window.dataLayer || [];
// $FlowFixMe
this._gtag('js', new Date());
// $FlowFixMe
this._gtag('config', this.config.trackingId);
this.config.trackingId && this._gtag('config', this.config.trackingId);
// $FlowFixMe
this.config.trackingGA4Id && this._gtag('config', this.config.trackingGA4Id);
}

/**
Expand Down
124 changes: 120 additions & 4 deletions test/src/google-analytics.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import '../../src/index.js';
import GoogleAnalytics from '../../src/index.js';
import {core, setup} from 'kaltura-player-js';
import * as TestUtils from './utils/test-utils';
const {FakeEvent, Error} = core;
const {FakeEvent, Error, Utils} = core;

const targetId = 'player-placeholder_google-analytics.spec';

Expand All @@ -17,7 +17,7 @@ describe('Google Analytics Plugin', function () {
const CMuiConfId = 654321;
const CMentryName = 'change media name';

let config;
let config, sandbox;

const CMconfig = {
CMid,
Expand Down Expand Up @@ -85,6 +85,7 @@ describe('Google Analytics Plugin', function () {
after(function () {
TestUtils.removeElement(targetId);
});

describe('default events', () => {
beforeEach(function () {
config = {
Expand Down Expand Up @@ -534,7 +535,10 @@ describe('Google Analytics Plugin', function () {
player.addEventListener(player.Event.MUTE_CHANGE, () => {
try {
verifyEventName(dataLayer[dataLayer.length - 1], 'mute 25');
verifyEventParams(dataLayer[dataLayer.length - 1], {category: 'custom category 25', label: 'custom label 25'});
verifyEventParams(dataLayer[dataLayer.length - 1], {
category: 'custom category 25',
label: 'custom label 25'
});
verifyEventValue(dataLayer[dataLayer.length - 1], 25);
done();
} catch (e) {
Expand Down Expand Up @@ -566,4 +570,116 @@ describe('Google Analytics Plugin', function () {
player.load();
});
});

describe('UA and GA4', () => {
beforeEach(function () {
window.dataLayer = null;
sandbox = sinon.createSandbox();
});

afterEach(function () {
sandbox.restore();
Utils.Dom.loadScriptAsync.restore();
});

it('Should send for both UA and GA4', done => {
sinon.stub(Utils.Dom, 'loadScriptAsync').callsFake(url => {
try {
url.should.equal(`${GoogleAnalytics.GTAG_LIB_URL}?id=UA-1234567-89`);
} catch (e) {
done(e);
}
return Promise.resolve();
});
config = {
targetId,
provider: {},
id,
sources: {
progressive: [
{
mimetype: 'video/mp4',
url: 'https://www.w3schools.com/tags/movie.mp4'
}
]
},
plugins: {
googleAnalytics: {
trackingId: 'UA-1234567-89',
trackingGA4Id: 'G-0123456789'
}
}
};
setupPlayer(config);
Array.from(dataLayer[1]).should.deep.equal(['config', 'UA-1234567-89']);
Array.from(dataLayer[2]).should.deep.equal(['config', 'G-0123456789']);
done();
});

it('Should send for UA only', done => {
sinon.stub(Utils.Dom, 'loadScriptAsync').callsFake(url => {
try {
url.should.equal(`${GoogleAnalytics.GTAG_LIB_URL}?id=UA-1234567-89`);
} catch (e) {
done(e);
}
return Promise.resolve();
});
config = {
targetId,
provider: {},
id,
sources: {
progressive: [
{
mimetype: 'video/mp4',
url: 'https://www.w3schools.com/tags/movie.mp4'
}
]
},
plugins: {
googleAnalytics: {
trackingId: 'UA-1234567-89'
}
}
};
setupPlayer(config);
Array.from(dataLayer[1]).should.deep.equal(['config', 'UA-1234567-89']);
dataLayer[2][0].should.not.equal('config');
done();
});

it('Should send for GA4 only', done => {
sinon.stub(Utils.Dom, 'loadScriptAsync').callsFake(url => {
try {
url.should.equal(`${GoogleAnalytics.GTAG_LIB_URL}?id=G-0123456789`);
} catch (e) {
done(e);
}
return Promise.resolve();
});
config = {
targetId,
provider: {},
id,
sources: {
progressive: [
{
mimetype: 'video/mp4',
url: 'https://www.w3schools.com/tags/movie.mp4'
}
]
},
plugins: {
googleAnalytics: {
trackingGA4Id: 'G-0123456789'
}
}
};
setupPlayer(config);
Array.from(dataLayer[1]).should.deep.equal(['config', 'G-0123456789']);
dataLayer[2][0].should.not.equal('config');
done();
});
});
});
Loading

0 comments on commit 4ec0b8b

Please sign in to comment.