commit 7a847766931915acd1c68abd8caedd59ff4aab41
parent b805859cefc681170619ff0a0e12d9a14861aed3
Author: Nicholas Rishel <nrishel@mozilla.com>
Date: Fri, 21 Nov 2025 00:14:16 +0000
Bug 2000321 - Add install attribution special handling to support Microsoft Store Ads attribution. r=nalexander
Differential Revision: https://phabricator.services.mozilla.com/D272723
Diffstat:
4 files changed, 56 insertions(+), 9 deletions(-)
diff --git a/browser/components/attribution/AttributionCode.sys.mjs b/browser/components/attribution/AttributionCode.sys.mjs
@@ -44,6 +44,7 @@ const ATTR_CODE_MAX_LENGTH = 1010;
const ATTR_CODE_VALUE_REGEX = /[a-zA-Z0-9_%\\-\\.\\(\\)]*/;
const ATTR_CODE_FIELD_SEPARATOR = "%26"; // URL-encoded &
const ATTR_CODE_KEY_VALUE_SEPARATOR = "%3D"; // URL-encoded =
+const MSCLKID_KEY_PREFIX = "storeBingAd_";
const ATTR_CODE_KEYS = [
"source",
"medium",
@@ -54,6 +55,7 @@ const ATTR_CODE_KEYS = [
"ua",
"dltoken",
"msstoresignedin",
+ "msclkid",
"dlsource",
];
@@ -145,6 +147,10 @@ export var AttributionCode = {
parsed[key] = value;
}
}
+ } else if (param.startsWith(MSCLKID_KEY_PREFIX)) {
+ // Microsoft Store Ads uses `_` to separate the key and value, therefore
+ // requires special handling.
+ parsed.msclkid = param.substring(MSCLKID_KEY_PREFIX.length);
} else {
lazy.log.debug(
`parseAttributionCode: "${code}" => isValid = false: "${key}", "${value}"`
diff --git a/browser/components/attribution/docs/index.rst b/browser/components/attribution/docs/index.rst
@@ -19,6 +19,7 @@ The following information is supported by this system:
* *dltoken*
* *dlsource*
* *msstoresignedin*
+* *msclkid*
Descriptions of each of these can be found in :ref:`the Telemetry Environment documentation <environment>`.
@@ -130,6 +131,8 @@ Firefox installs done through the Microsoft Store support extracting campaign ID
`https://www.microsoft.com/store/apps/9NZVDKPMR9RD?cid=source%3Dgoogle.com%26medium%3Dorganic%26campaign%3D(not%20set)%26content%3D(not%20set) <https://www.microsoft.com/store/apps/9NZVDKPMR9RD?cid=source%3Dgoogle.com%26medium%3Dorganic%26campaign%3D(not%20set)%26content%3D(not%20set)>`_
+Microsoft Store Ads presents its Ads Campaign ID to installed applications as a uniquely formatted ``storeBingAd_[uuid]``, for example ``storeBingAd_45cbbf091fb541f0ae959d50ffb8c5b8``. Firefox records this as ``msclkid=[uuid]``, for example ``msclkid=45cbbf091fb541f0ae959d50ffb8c5b8`` in installation attribution.
+
For more on how custom campaign IDs work in general in the Microsoft Store environment, `see Microsoft's documentation <https://docs.microsoft.com/en-us/windows/uwp/publish/create-a-custom-app-promotion-campaign>`_.
diff --git a/browser/components/attribution/test/xpcshell/head.js b/browser/components/attribution/test/xpcshell/head.js
@@ -68,6 +68,39 @@ let validAttrCodes = [
dlsource: "some-dl-source",
},
},
+ // Microsoft Store Ads attribution is not URL encoded, and instead provides a
+ // Microsoft Click ID in the format `storeBingAd_uuid` when requesting the
+ // Campaign ID. When retrieving this we append an additional key
+ // `&msstoresignedin=bool` as we would for a URL encoded campaign.
+ //
+ // At present we have not found a documented schema for Campaign IDs
+ // associated to Microsoft Store Ads, therefore don't test additional
+ // key/value combinations as `%26` is not guaranteed to be the key seperator
+ // if additional keys were added.
+ {
+ code: "storeBingAd_45cbbf091fb541f0ae959d50ffb8c5b8%26msstoresignedin%3Dtrue",
+ parsed: {
+ msclkid: "45cbbf091fb541f0ae959d50ffb8c5b8",
+ msstoresignedin: true,
+ },
+ doesNotRoundtrip: true, // `storeBingAd_uuid` becomes `msclkid=uuid`.
+ },
+ {
+ code: "storeBingAd_45cbbf091fb541f0ae959d50ffb8c5b8%26msstoresignedin%3Dfalse",
+ parsed: {
+ msclkid: "45cbbf091fb541f0ae959d50ffb8c5b8",
+ msstoresignedin: false,
+ },
+ doesNotRoundtrip: true, // `storeBingAd_uuid` becomes `msclkid=uuid`.
+ },
+ {
+ code: "storeBingAd_%26msstoresignedin%3Dfalse",
+ parsed: {
+ msclkid: "",
+ msstoresignedin: false,
+ },
+ doesNotRoundtrip: true, // `storeBingAd_uuid` becomes `msclkid=uuid`.
+ },
];
let invalidAttrCodes = [
diff --git a/toolkit/system/windowsPackageManager/nsIWindowsPackageManager.idl b/toolkit/system/windowsPackageManager/nsIWindowsPackageManager.idl
@@ -23,15 +23,20 @@ interface nsIWindowsPackageManager : nsISupports
*/
unsigned long long getInstalledDate();
-/* Asynchronously retrieves the campaignId, if any, a user's Microsoft Store install is
- * associated with. These are present if the user clicked a "ms-window-store://"
- * or "https://" link that included a "cid" query argument the very first time
- * they installed the app. (This value appears to be cached forever, so
- * subsequent installs will not refresh it.) If a non-empty campaign ID is
- * found it will be assumed to be a properly formatted attribution code and
- * have an additional "msstoresignedin" key appended to it indicate whether or
- * not the user was signed in when they installed the application. This key
- * will either be set to "true" or "false".
+/* Asynchronously retrieves the campaignId, if any, a user's Microsoft Store
+ * install is associated with.
+ *
+ * These are present if the user clicked a "ms-window-store://" or "https://"
+ * link that included a "cid" query argument the very first time they installed
+ * the app. These are also present if the user installed through a Microsoft
+ * Store Ad, which results in non-URL encoded string `storeBingAd_[uuid]` (This
+ * value appears to be cached forever, so subsequent installs will not refresh
+ * it.)
+ *
+ * If a non-empty campaign ID is found it will be assumed to be a properly
+ * formatted attribution code and have an additional "msstoresignedin" key
+ * appended to it indicate whether or not the user was signed in when they
+ * installed the application. This key will either be set to "true" or "false".
*
* @throw NS_ERROR_NOT_IMPLEMENTED if called on Windows 8 or earlier, or from
* a non-packaged build.