Skip to content
This repository has been archived by the owner on Jan 17, 2023. It is now read-only.

Fixes #5067 - add custom dimension for login type to GA #5152

Merged
merged 2 commits into from
Nov 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions docs/METRICS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ This document is a summary of the metrics Firefox Screenshots will record, how w

Additionally, it's important to recognize that Firefox Screenshots is an add-on in a browser as well as a server-side service.

## deviceId / user ID
## accountId / deviceId / user ID

Each device that uses Screenshots (browser, profile, computer) generates a random UUID ID. We call this the deviceId. In addition a random secret is generated. The two together are used to register and authenticate with the server.
Each device that takes Screenshots (browser, profile, computer) generates a random UUID ID. We call this the deviceId. In addition a random secret is generated. The two together are used to register and authenticate with the server.

The deviceId is only registered with the screenshots.firefox.com server when the user first saves a shot. Starting Screenshots or downloading does not cause registration.

Each event is sent to the server with its deviceId. The server hashes this ID (combining it with a random server string that is rotated occasionally) before sending it to Google Analytics. This hashed ID is generally called `cid` (customer ID, a Google Analytics term).
An alternate way to authenticate with server is by successful signin to firefox account. An accountId which is a uid returned by fxa-auth-server is assigned once a user login with firefox account and its value is reset on signout from settings.

Each event is sent to the server with its accountId or deviceId. The server hashes this ID (combining it with a random server string that is rotated occasionally) before sending it to Google Analytics. This hashed ID is generally called `cid` (customer ID, a Google Analytics term).

For web page views (viewing and interacting with individual shots or My Shots) we serve up `/ga-activation.js` or `/ga-activation-hashed.js` (the latter for pages with private URLs). This file is generated *per user* and includes the `cid`, if the user is authenticated with the service.

Expand Down Expand Up @@ -83,6 +85,15 @@ Event label: exactly what control invoked the action, such as toolbar-button. T
* `selection`: anything that happens during the selection phase, that doesn't happen in the topbar
* `keyboard`: any keyboard shortcut used

#### Login status custom dimension

The `cd9` dimension holds the "login type". The values can be:

* `non-login`: visitor is not logged in
* `extension`: logged in via the extension, with no FxA login
* `extension-fxa`: logged in via the extension, With a FxA login
* `browser-fxa`: using a non-Firefox browser, with a FxA login

#### A/B tests

##### Test alternate share panel
Expand Down
5 changes: 4 additions & 1 deletion server/src/ga-activation.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ const gaJs = `

window.sendEvent = function (action, label, options) {
var event = "web";
var loginType = "__LOGIN_TYPE__" || null;
if (typeof label == "object") {
if (options) {
console.error("Error: got label and options");
Expand All @@ -146,14 +147,15 @@ window.sendEvent = function (action, label, options) {
options[window.abTests[testName].gaField] = window.abTests[testName].value;
}
}
options.cd9 = loginType;
console.debug("sendEvent", event + "/" + action + (label ? "/" + label : "") || "none", options || "no-options");
ga("send", "event", event, action, label, options);
};
`;

const idRegex = /^[a-zA-Z0-9_.,-]{1,1000}$/;

exports.makeGaActivationString = function(gaId, userId, abTests, hashLocation) {
exports.makeGaActivationString = function({gaId, userId, abTests, hashLocation, loginType}) {
if (gaId === "") {
// Don't enable ga if no id was provided
return stubGaJs.replace(/__ABTESTS__/g, JSON.stringify(abTests));
Expand All @@ -171,5 +173,6 @@ exports.makeGaActivationString = function(gaId, userId, abTests, hashLocation) {
let script = gaJs.replace(/__GA_ID__/g, gaId).replace(/__USER_ID__/g, userId);
script = script.replace(/__HASH_LOCATION__/g, hashLocation ? "true" : "false");
script = script.replace(/__ABTESTS__/g, JSON.stringify(abTests));
script = script.replace(/__LOGIN_TYPE__/g, loginType || "");
return script;
};
22 changes: 19 additions & 3 deletions server/src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,16 +328,32 @@ app.get("/ga-activation-hashed.js", function(req, res) {

function sendGaActivation(req, res, hashPage) {
let promise;
let loginType = "non-login";
if (req.accountId) {
if (req.deviceId) {
loginType = "extension-fxa";
} else {
loginType = "browser-fxa";
}
} else if (req.deviceId) {
loginType = "extension";
}
setMonthlyCache(res, {private: true});
if (req.deviceId) {
promise = hashUserId(req.deviceId).then((uuid) => {
if (req.accountId || req.deviceId) {
promise = hashUserId(req.accountId || req.deviceId).then((uuid) => {
return uuid.toString();
});
} else {
promise = Promise.resolve("");
}
promise.then((userUuid) => {
const script = gaActivation.makeGaActivationString(config.gaId, userUuid, req.abTests, hashPage);
const script = gaActivation.makeGaActivationString({
gaId: config.gaId,
userId: userUuid,
abTests: req.abTests,
hashLocation: hashPage,
loginType,
});
jsResponse(res, script);
}).catch((e) => {
errorResponse(res, "Error creating user UUID:", e);
Expand Down