Omit non-essential fields from RTAMO flow (Fixes #14482)

This commit is contained in:
Alex Gibson 2024-04-22 09:54:18 +01:00
Родитель df4d247018
Коммит 75cab111a3
7 изменённых файлов: 236 добавлений и 199 удалений

Просмотреть файл

@ -155,6 +155,14 @@ RTAMO initially worked for only a limited subset of addons recommended by Mozill
functionality was recently expanded by the AMO team to cover all publically listed addons, functionality was recently expanded by the AMO team to cover all publically listed addons,
under a project called `Extended RTAMO (ERTAMO)`. under a project called `Extended RTAMO (ERTAMO)`.
.. Important::
Because RTAMO is a user facing feature, expressly requested by the user from the AMO
page, we deem the RTAMO flow as an essential/necessary use of attribution data. We do
however limit the amount of data we collect to only what's essential for the RTAMO to
function as a feature. Non-essential fields such as the Google Analytics client ID are
omitted. We also continue to respect Do Not Track (DNT) as a valid opt-out signal.
How can visitors opt out? How can visitors opt out?
------------------------- -------------------------

Просмотреть файл

@ -38,40 +38,3 @@ Documentation
See `helpers.py`_ for documentation and supported parameters for both buttons. See `helpers.py`_ for documentation and supported parameters for both buttons.
.. _helpers.py: https://github.com/mozilla/bedrock/blob/main/bedrock/firefox/templatetags/helpers.py .. _helpers.py: https://github.com/mozilla/bedrock/blob/main/bedrock/firefox/templatetags/helpers.py
External referrers
------------------
Generally we encourage other websites in the Mozilla ecosystem to link to the `/firefox/new/`_ page when
prompting visitors to download Firefox, since it provides a consistent user experience and also benefits
:abbr:`SEO (Search Engine Optimization)`. In some circumstances however sites may want to provide a download button that initiates a file
download automatically when clicked. For cases like this, sites can link to the following URL:
.. code-block::
https://www.mozilla.org/firefox/download/thanks/?s=direct
.. Important::
Including the ``s=direct`` query parameter here will ensure that Windows download attribution is
collected and recorded correctly in Telemetry. Also, make sure to **not** include the locale in
the URL, so that bedrock can serve the most suitable language based on the visitor's browser
preference.
.. Note::
This download URL will not automatically trigger a download in older Internet Explorer browsers. If
that's important to your visitors, then you can use a `conditional comment`_ to provide a different link.
.. code-block:: html
<!--[if !IE]><!-->
<a href="https://www.mozilla.org/firefox/download/thanks/?s=direct">Download Firefox</a>
<!--<![endif]-->
<!--[if IE]>
<a href="https://www.mozilla.org/firefox/new/">Download Firefox</a>
<![endif]-->
.. _/firefox/new/: https://www.mozilla.org/firefox/new/
.. _conditional comment: https://en.wikipedia.org/wiki/Conditional_comment

Просмотреть файл

@ -456,19 +456,31 @@ if (typeof window.Mozilla === 'undefined') {
/** /**
* Gets utm parameters and referrer information from the web page if they exist. * Gets utm parameters and referrer information from the web page if they exist.
* @param {String} ref - Optional referrer to facilitate testing. * @param {String} ref - Optional referrer to facilitate testing.
* @param {Boolean} omitNonEssentialFields - Optional flag to omit fields that are nonEssential for RTAMO.
* @return {Object} - Stub attribution data object. * @return {Object} - Stub attribution data object.
*/ */
StubAttribution.getAttributionData = function (ref) { StubAttribution.getAttributionData = function (
ref,
omitNonEssentialFields
) {
var params = new window._SearchParams(); var params = new window._SearchParams();
var utms = params.utmParams(); var utms = params.utmParams();
var experiment = var experiment = omitNonEssentialFields
params.get('experiment') || StubAttribution.experimentName; ? null
var variation = : params.get('experiment') || StubAttribution.experimentName;
params.get('variation') || StubAttribution.experimentVariation; var variation = omitNonEssentialFields
? null
: params.get('variation') || StubAttribution.experimentVariation;
var referrer = typeof ref === 'string' ? ref : document.referrer; var referrer = typeof ref === 'string' ? ref : document.referrer;
var ua = StubAttribution.getUserAgent(); var ua = omitNonEssentialFields
var clientIDUA = StubAttribution.getUAClientID(); ? 'other'
var clientIDGA4 = StubAttribution.getGtagClientID(); : StubAttribution.getUserAgent();
var clientIDUA = omitNonEssentialFields
? null
: StubAttribution.getUAClientID();
var clientIDGA4 = omitNonEssentialFields
? null
: StubAttribution.getGtagClientID();
/* eslint-disable camelcase */ /* eslint-disable camelcase */
var data = { var data = {

Просмотреть файл

@ -0,0 +1,165 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
/**
* IMPORTANT: This file is a special version of thanks.js that supports making a Firefox
* attribution flow request immediately prior to triggering a download of the Firefox
* installer. This is required in order to support Return to addons.mozilla.org (RTAMO),
* which is a user facing feature that enables easy installation of a Firefox extension
* as a post-install onboarding step. It is triggered via a special `?s=direct` query
* parameter added to the `/thanks/` page when linking from an AMO page.
*
* Because RTAMO is a user-facing feature, expressly requested by the user from the AMO
* page, we deem the RTAMO flow as essential/necessary. Extra measures are taken to remove
* non-essential attribution fields and include only those required for RTAMO to function.
*
* DNT is still respected as an opt-out signal.
*/
let timeout;
let requestComplete = false;
function beginFirefoxDownload() {
const directDownloadLink = document.getElementById('direct-download-link');
let downloadURL;
// Only auto-start the download if a supported platform is detected.
if (
Mozilla.DownloadThanks.shouldAutoDownload(
window.site.platform,
window.site.fxSupported
) &&
typeof Mozilla.Utils !== 'undefined'
) {
downloadURL = Mozilla.DownloadThanks.getDownloadURL(window.site);
if (downloadURL) {
// Pull download link from the download button and add to the 'Try downloading again' link.
// Make sure the 'Try downloading again' link is well formatted! (issue 9615)
if (directDownloadLink && directDownloadLink.href) {
directDownloadLink.href = downloadURL;
directDownloadLink.addEventListener(
'click',
(event) => {
try {
Mozilla.TrackProductDownload.handleLink(event);
} catch (error) {
return;
}
},
false
);
}
// Start the platform-detected download a second after DOM ready event.
Mozilla.Utils.onDocumentReady(() => {
setTimeout(() => {
try {
Mozilla.TrackProductDownload.sendEventFromURL(
downloadURL
);
} catch (error) {
return;
}
window.location.href = downloadURL;
}, 1000);
});
}
}
}
function onSuccess() {
// Make sure we only initiate the download once!
clearTimeout(timeout);
if (requestComplete) {
return;
}
requestComplete = true;
// Fire GA event to log attribution success
// UA
window.dataLayer.push({
event: 'non-interaction',
eAction: 'direct-attribution',
eLabel: 'success'
});
// GA4
window.dataLayer.push({
event: 'widget_action',
type: 'direct-attribution',
action: 'success',
non_interaction: true
});
beginFirefoxDownload();
}
function onTimeout() {
// Make sure we only initiate the download once!
clearTimeout(timeout);
if (requestComplete) {
return;
}
requestComplete = true;
// Fire GA event to log attribution timeout
// UA
window.dataLayer.push({
event: 'non-interaction',
eAction: 'direct-attribution',
eLabel: 'timeout'
});
// GA4
window.dataLayer.push({
event: 'widget_action',
type: 'direct-attribution',
action: 'timeout',
non_interaction: true
});
beginFirefoxDownload();
}
function initAttribution() {
// We pass omitNonEssentialFields=true here to only include the attribution fields
// required for RTAMO to function as a user facing feature.
const data = Mozilla.StubAttribution.getAttributionData(null, true);
// Make sure we check referrer for AMO (issue 11467)
if (
data &&
Mozilla.StubAttribution.withinAttributionRate() &&
Mozilla.StubAttribution.hasValidData(data)
) {
Mozilla.StubAttribution.successCallback = onSuccess;
Mozilla.StubAttribution.timeoutCallback = onTimeout;
// We don't want to delay the download indefinitely for a stub attribution call,
// so we only wait up to an additional 2 seconds (on top of GA) before downloading.
timeout = setTimeout(onTimeout, 2000);
Mozilla.StubAttribution.requestAuthentication(data);
} else {
beginFirefoxDownload();
}
}
/**
* If visitor already has a cookie, or does not meet the typical requirements fo
* stub attribution, then we can start the download as normal. If requirements *are*
* met and the visitor does *not* have a cookie, then attempt to make the attribution
* call before starting the download.
*/
if (
typeof Mozilla.StubAttribution !== 'undefined' &&
Mozilla.StubAttribution.meetsRequirements() &&
!Mozilla.StubAttribution.hasCookie()
) {
initAttribution();
} else {
beginFirefoxDownload();
}
// Bug 1354334 - add a hint for test automation that page has loaded.
document.getElementsByTagName('html')[0].classList.add('download-ready');

Просмотреть файл

@ -1,153 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
(function () {
'use strict';
var timeout;
var requestComplete = false;
function beginFirefoxDownload() {
var directDownloadLink = document.getElementById(
'direct-download-link'
);
var downloadURL;
// Only auto-start the download if a supported platform is detected.
if (
Mozilla.DownloadThanks.shouldAutoDownload(
window.site.platform,
window.site.fxSupported
) &&
typeof Mozilla.Utils !== 'undefined'
) {
downloadURL = Mozilla.DownloadThanks.getDownloadURL(window.site);
if (downloadURL) {
// Pull download link from the download button and add to the 'Try downloading again' link.
// Make sure the 'Try downloading again' link is well formatted! (issue 9615)
if (directDownloadLink && directDownloadLink.href) {
directDownloadLink.href = downloadURL;
directDownloadLink.addEventListener(
'click',
function (event) {
try {
Mozilla.TrackProductDownload.handleLink(event);
} catch (error) {
return;
}
},
false
);
}
// Start the platform-detected download a second after DOM ready event.
Mozilla.Utils.onDocumentReady(function () {
setTimeout(function () {
try {
Mozilla.TrackProductDownload.sendEventFromURL(
downloadURL
);
} catch (error) {
return;
}
window.location.href = downloadURL;
}, 1000);
});
}
}
}
function onSuccess() {
// Make sure we only initiate the download once!
clearTimeout(timeout);
if (requestComplete) {
return;
}
requestComplete = true;
// Fire GA event to log attribution success
// UA
window.dataLayer.push({
event: 'non-interaction',
eAction: 'direct-attribution',
eLabel: 'success'
});
// GA4
window.dataLayer.push({
event: 'widget_action',
type: 'direct-attribution',
action: 'success',
non_interaction: true
});
beginFirefoxDownload();
}
function onTimeout() {
// Make sure we only initiate the download once!
clearTimeout(timeout);
if (requestComplete) {
return;
}
requestComplete = true;
// Fire GA event to log attribution timeout
// UA
window.dataLayer.push({
event: 'non-interaction',
eAction: 'direct-attribution',
eLabel: 'timeout'
});
// GA4
window.dataLayer.push({
event: 'widget_action',
type: 'direct-attribution',
action: 'timeout',
non_interaction: true
});
beginFirefoxDownload();
}
/**
* If visitor already has a cookie, or does not meet the typical requirements fo
* stub attribution, then we can start the download as normal. If requirements *are*
* met and the visitor does *not* have a cookie, then attempt to make the attribution
* call before starting the download.
*/
if (
typeof Mozilla.StubAttribution !== 'undefined' &&
Mozilla.StubAttribution.meetsRequirements() &&
!Mozilla.StubAttribution.hasCookie()
) {
// Wait for GA to load so that we can pass along visit ID.
Mozilla.StubAttribution.waitForGoogleAnalyticsThen(function () {
var data = Mozilla.StubAttribution.getAttributionData();
// make sure we check referrer for AMO (issue 11467)
if (
data &&
Mozilla.StubAttribution.withinAttributionRate() &&
Mozilla.StubAttribution.hasValidData(data)
) {
Mozilla.StubAttribution.successCallback = onSuccess;
Mozilla.StubAttribution.timeoutCallback = onTimeout;
// We don't want to delay the download indefinitely for a stub attribution call,
// so we only wait up to an additional 2 seconds (on top of GA) before downloading.
timeout = setTimeout(onTimeout, 2000);
Mozilla.StubAttribution.requestAuthentication(data);
} else {
beginFirefoxDownload();
}
});
} else {
beginFirefoxDownload();
}
// Bug 1354334 - add a hint for test automation that page has loaded.
document.getElementsByTagName('html')[0].classList.add('download-ready');
})();

Просмотреть файл

@ -1326,7 +1326,7 @@
{ {
"files": [ "files": [
"js/firefox/new/common/thanks.js", "js/firefox/new/common/thanks.js",
"js/firefox/new/common/thanks-direct.js" "js/firefox/new/common/thanks-direct.es6.js"
], ],
"name": "firefox_new_thanks_direct" "name": "firefox_new_thanks_direct"
}, },

Просмотреть файл

@ -775,6 +775,48 @@ describe('stub-attribution.js', function () {
const result = Mozilla.StubAttribution.getAttributionData(referrer); const result = Mozilla.StubAttribution.getAttributionData(referrer);
expect(result).toEqual(data); expect(result).toEqual(data);
}); });
it('should omit non-essential attribution data when `omitNonEssentialFields=true` is passed', function () {
const referrer = 'https://addons.mozilla.org/';
/* eslint-disable camelcase */
const utms = {
utm_source: 'addons.mozilla.org',
utm_medium: 'referral',
utm_campaign: 'non-fx-button',
utm_content: 'rta%3Acm9uaW4td2FsbGV0QGF4aWVpbmZpbml0eS5jb20'
};
/* eslint-enable camelcase */
/* eslint-disable camelcase */
const data = {
utm_source: 'addons.mozilla.org',
utm_medium: 'referral',
utm_campaign: 'non-fx-button',
utm_content: 'rta%3Acm9uaW4td2FsbGV0QGF4aWVpbmZpbml0eS5jb20',
referrer: 'https://addons.mozilla.org/',
ua: 'other',
dlsource: DLSOURCE
};
/* eslint-enable camelcase */
spyOn(window._SearchParams.prototype, 'utmParams').and.returnValue(
utms
);
spyOn(window._SearchParams.prototype, 'get').and.callFake(
function (key) {
return key === 'experiment' ? 'firefox-new' : 1;
}
);
spyOn(Mozilla.StubAttribution, 'getUserAgent').and.returnValue(
'chrome'
);
const result = Mozilla.StubAttribution.getAttributionData(
referrer,
true
);
expect(result).toEqual(data);
});
}); });
describe('requestAuthentication', function () { describe('requestAuthentication', function () {