зеркало из https://github.com/mozilla/bedrock.git
Omit non-essential fields from RTAMO flow (Fixes #14482)
This commit is contained in:
Родитель
df4d247018
Коммит
75cab111a3
|
@ -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 () {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче