summaryrefslogtreecommitdiffstats
path: root/browser/components/asrouter/docs
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/asrouter/docs')
-rw-r--r--browser/components/asrouter/docs/about-welcome.md105
-rw-r--r--browser/components/asrouter/docs/aboutwelcome-1.pngbin0 -> 91928 bytes
-rw-r--r--browser/components/asrouter/docs/aboutwelcome-2.pngbin0 -> 103305 bytes
-rw-r--r--browser/components/asrouter/docs/aboutwelcome-res-1.pngbin0 -> 86697 bytes
-rw-r--r--browser/components/asrouter/docs/aboutwelcome-res-2.pngbin0 -> 104842 bytes
-rw-r--r--browser/components/asrouter/docs/cfr-doorhanger.pngbin0 -> 70244 bytes
-rw-r--r--browser/components/asrouter/docs/cfr_doorhanger_screenshot.pngbin0 -> 257709 bytes
-rw-r--r--browser/components/asrouter/docs/contextual-feature-recommendation.md83
-rw-r--r--browser/components/asrouter/docs/debugging-docs.md32
-rw-r--r--browser/components/asrouter/docs/debugging-guide.pngbin0 -> 247644 bytes
-rw-r--r--browser/components/asrouter/docs/feature-callout.md614
-rw-r--r--browser/components/asrouter/docs/feature-callout.pngbin0 -> 188755 bytes
-rw-r--r--browser/components/asrouter/docs/first-run.md68
-rw-r--r--browser/components/asrouter/docs/index.rst108
-rw-r--r--browser/components/asrouter/docs/infobar.pngbin0 -> 106424 bytes
-rw-r--r--browser/components/asrouter/docs/infobars.md60
-rw-r--r--browser/components/asrouter/docs/message-routing-overview.pngbin0 -> 50250 bytes
-rw-r--r--browser/components/asrouter/docs/moments-page.md64
-rw-r--r--browser/components/asrouter/docs/moments.png0
-rw-r--r--browser/components/asrouter/docs/private-browsing.md59
-rw-r--r--browser/components/asrouter/docs/private-browsing.pngbin0 -> 139858 bytes
-rw-r--r--browser/components/asrouter/docs/remote_cfr.md82
-rw-r--r--browser/components/asrouter/docs/selected-PB.pngbin0 -> 24388 bytes
-rw-r--r--browser/components/asrouter/docs/simple-cfr-template.rst37
-rw-r--r--browser/components/asrouter/docs/spotlight.md90
-rw-r--r--browser/components/asrouter/docs/spotlight.pngbin0 -> 52974 bytes
-rw-r--r--browser/components/asrouter/docs/targeting-attributes.md1033
-rw-r--r--browser/components/asrouter/docs/targeting-guide.md37
-rw-r--r--browser/components/asrouter/docs/telemetry.md90
29 files changed, 2562 insertions, 0 deletions
diff --git a/browser/components/asrouter/docs/about-welcome.md b/browser/components/asrouter/docs/about-welcome.md
new file mode 100644
index 0000000000..b8f549370d
--- /dev/null
+++ b/browser/components/asrouter/docs/about-welcome.md
@@ -0,0 +1,105 @@
+# About Welcome
+
+## What is about:welcome
+A full-page multistep onboarding experience on `about:welcome` that appears to all new Firefox users after Firefox has successfully been installed.
+
+Onboarding experience on `about:welcome` shows screens following below precedence order:
+- Has AMO attribution
+ - Return to AMO custom onboarding screens
+- Experiments
+- Return `MR_ABOUT_WELCOME_DEFAULT` [screens](https://searchfox.org/mozilla-central/rev/3b707c8fd7e978eebf24279ee51ccf07895cfbcb/browser/components/newtab/aboutwelcome/lib/AboutWelcomeDefaults.jsm#523) after applying dynamic rules inside [prepareContentForReact](https://searchfox.org/mozilla-central/rev/3b707c8fd7e978eebf24279ee51ccf07895cfbcb/browser/components/newtab/aboutwelcome/lib/AboutWelcomeDefaults.jsm#577) method. Each screen can additionally be dynamically configured to show/hide via [screen level targeting](https://searchfox.org/mozilla-central/rev/3b707c8fd7e978eebf24279ee51ccf07895cfbcb/browser/components/newtab/aboutwelcome/lib/AboutWelcomeDefaults.jsm#90).
+
+Spotlight messaging surface shows `about:welcome` screens content with the appearance of a spotlight modal by using exposed window.AW* interfaces. This [Unified Onboarding](https://docs.google.com/document/d/1o8W-gEkgw2GC7KFSfQRkKfWzNJg1-6fpkVPrYmmot4Y/edit) approach enables reusing `about:welcome` as rendering engine for multiple messaging surfaces such as Spotlight and Feature Callout.
+
+## Testing about:welcome screens
+
+### Via Screens Pref:
+1. Go to `about:config`, search for `browser.aboutwelcome.screens` and set it to the array of screens value to be used in JSON recipe
+2. Go to about:welcome and you should see the about:welcome screen(s)
+**Note:** If you are enrolled in a nimbus experiment, about.welcome.screens will not show up
+
+### Via Experiments
+You can test custom `about:welcome` UI by creating an experiment. [Messaging Journey](https://experimenter.info/messaging/desktop-messaging-journey) captures creating and testing experiments via Nimbus.
+
+### Example JSON screens property
+```
+[
+ {
+ "id": "TEST_SCREEN_1",
+ "content": {
+ "position": "split",
+ "split_narrow_bkg_position": "-155px",
+ "progress_bar": "true",
+ "background": "url('chrome://activity-stream/content/data/content/assets/mr-pintaskbar.svg') var(--mr-secondary-position) no-repeat #F8F6F4",
+ "logo": {},
+ "title": "Welcome to Firefox",
+ "subtitle": "Launch a healthier internet from anywhere with a single click.",
+ "primary_button": {
+ "label": {
+ "string_id": "mr2022-onboarding-pin-primary-button-label"
+ },
+ "action": {
+ "navigate": true,
+ "type": "PIN_FIREFOX_TO_TASKBAR"
+ }
+ },
+ "checkbox": {
+ "label": "Also add private browsing",
+ "defaultValue": true,
+ "action": {
+ "type": "MULTI_ACTION",
+ "navigate": true,
+ "data": {
+ "actions": [
+ {
+ "type": "PIN_FIREFOX_TO_TASKBAR",
+ "data": {
+ "privatePin": true
+ }
+ },
+ {
+ "type": "PIN_FIREFOX_TO_TASKBAR"
+ }
+ ]
+ }
+ }
+ },
+ "secondary_button": {
+ "label": "Next Screen",
+ "action": {
+ "navigate": true
+ },
+ "has_arrow_icon": true
+ }
+ }
+ },
+ {
+ "id": "TEST_SCREEN_2",
+ "content": {
+ "position": "split",
+ "progress_bar": "true",
+ "split_narrow_bkg_position": "-228px",
+ "background": "url('chrome://activity-stream/content/data/content/assets/mr-gratitude.svg') var(--mr-secondary-position) no-repeat #F8F6F4",
+ "logo": {},
+ "title": "You’re helping us build a better web",
+ "subtitle": "With your support, we’re working to make the internet more open, accessible, and better for everyone.",
+ "primary_button": {
+ "label": "Start browsing",
+ "action": {
+ "navigate": true
+ }
+ }
+ }
+ }
+]
+```
+
+### Example about:welcome screens
+
+### Browser View
+![About Welcome 1](./aboutwelcome-1.png)
+![About Welcome 2](./aboutwelcome-2.png)
+
+### Responsive View
+![About Welcome Responsive 1](./aboutwelcome-res-1.png)
+![About Welcome Responsive 2](./aboutwelcome-res-2.png)
diff --git a/browser/components/asrouter/docs/aboutwelcome-1.png b/browser/components/asrouter/docs/aboutwelcome-1.png
new file mode 100644
index 0000000000..92b5d4a878
--- /dev/null
+++ b/browser/components/asrouter/docs/aboutwelcome-1.png
Binary files differ
diff --git a/browser/components/asrouter/docs/aboutwelcome-2.png b/browser/components/asrouter/docs/aboutwelcome-2.png
new file mode 100644
index 0000000000..b2f22abc38
--- /dev/null
+++ b/browser/components/asrouter/docs/aboutwelcome-2.png
Binary files differ
diff --git a/browser/components/asrouter/docs/aboutwelcome-res-1.png b/browser/components/asrouter/docs/aboutwelcome-res-1.png
new file mode 100644
index 0000000000..443a5f2f2c
--- /dev/null
+++ b/browser/components/asrouter/docs/aboutwelcome-res-1.png
Binary files differ
diff --git a/browser/components/asrouter/docs/aboutwelcome-res-2.png b/browser/components/asrouter/docs/aboutwelcome-res-2.png
new file mode 100644
index 0000000000..1b3510db98
--- /dev/null
+++ b/browser/components/asrouter/docs/aboutwelcome-res-2.png
Binary files differ
diff --git a/browser/components/asrouter/docs/cfr-doorhanger.png b/browser/components/asrouter/docs/cfr-doorhanger.png
new file mode 100644
index 0000000000..04ea001ccf
--- /dev/null
+++ b/browser/components/asrouter/docs/cfr-doorhanger.png
Binary files differ
diff --git a/browser/components/asrouter/docs/cfr_doorhanger_screenshot.png b/browser/components/asrouter/docs/cfr_doorhanger_screenshot.png
new file mode 100644
index 0000000000..aee3bcf3bd
--- /dev/null
+++ b/browser/components/asrouter/docs/cfr_doorhanger_screenshot.png
Binary files differ
diff --git a/browser/components/asrouter/docs/contextual-feature-recommendation.md b/browser/components/asrouter/docs/contextual-feature-recommendation.md
new file mode 100644
index 0000000000..2492d68814
--- /dev/null
+++ b/browser/components/asrouter/docs/contextual-feature-recommendation.md
@@ -0,0 +1,83 @@
+# Contextual Feature Recommendation
+
+## What are CFRs?
+The most commonly used CFR as a Messaging Surface is the doorhanger, which anchors to one of the UI elements such as the application menu, the identity panel and so on.
+CFRs like any other messaging screen has specific triggers. You can learn more about triggers [here](https://firefox-source-docs.mozilla.org/toolkit/components/messaging-system/docs/TriggerActionSchemas/index.html).
+
+[More examples of templates supported with CFR](https://experimenter.info/messaging/desktop-messaging-surfaces/#doorhanger)
+
+### Note:
+For new messages, [Feature Callout](./feature-callout.md) is recommended instead of CFR.
+
+### Example of Doorhanger
+![Doorhanger](./cfr-doorhanger.png)
+
+## Testing CFRs
+
+### Via the dev tools:
+1. Go to `about:config`, set pref `browser.newtabpage.activity-stream.asrouter.devtoolsEnabled` to `true`
+2. Open a new tab and go to `about:asrouter` in the url bar
+3. In devtools Messages section, select and show messages from `cfr` as provider
+4. You should see example JSON messages with `"template": "cfr_doorhanger"` or `"template": "milestone_message"`. Clicking `Show` next to CFR message should show respective message UI
+5. You can directly modify the message in the text area with your changes or by pasting your custom message JSON. Clicking `Modify` shows your new updated CFR message.
+6. Ensure that all required properties are covered according to the [Doorhanger Schema](https://searchfox.org/mozilla-central/source/browser/components/asrouter/content-src/templates/CFR/templates/ExtensionDoorhanger.schema.json)
+7. Clicking `Share`, copies link to clipboard that can be pasted in the url bar to preview doorhanger UI in browser and can be shared to get feedback from your team.
+- **Note:** Some messages will not be shown when testing multiple CFRs due to overlap, ensure you close the previous message before testing another
+
+- **Note:** The `"anchor_id"` prop is the ID of the element the CFR will attach to (example below: `tracking-protection-icon-box`). Setting prop skip_address_bar_notifier to true will show the doorhanger straight away skipping url bar notifier (See [Bug 1831198](https://bugzilla.mozilla.org/show_bug.cgi?id=1831198)).
+
+### Via Experiments:
+You can test CFR messaging surface by creating an experiment or landing message in tree. [Messaging Journey](https://experimenter.info/messaging/desktop-messaging-journey) captures creating and testing experiments via Nimbus.
+
+### Example JSON for CFR
+```
+{
+ "id": "Test_CFR",
+ "groups": [
+ "cfr"
+ ],
+ "template": "cfr_doorhanger",
+ "content": {
+ "persistent_doorhanger": true,
+ "anchor_id": "tracking-protection-icon-container",
+ "layout": "icon_and_message",
+ "icon": "chrome://activity-stream/content/data/content/assets/glyph-webextension-16.svg",
+ "icon_dark_theme": "chrome://activity-stream/content/data/content/assets/glyph-webextension-16.svg",
+ "icon_class": "cfr-doorhanger-small-icon",
+ "heading_text": "Update Nightly to play Video",
+ "text": "Videos on this site may not play correctly on this version of Nightly. For full video support, update Nightly now.",
+ "buttons": {
+ "primary": {
+ "label": {
+ "string_id": "cfr-doorhanger-extension-ok-button"
+ },
+ "action": {
+ "type": "OPEN_PREFERENCES_PAGE",
+ "data": {
+ "category": "sync",
+ "entrypoint": "cfr-test"
+ }
+ }
+ },
+ "secondary": [
+ {
+ "label": {
+ "string_id": "cfr-doorhanger-extension-cancel-button"
+ },
+ "action": {
+ "type": "CANCEL"
+ }
+ }
+ ]
+ },
+ "skip_address_bar_notifier": true
+ },
+ "frequency": {
+ "lifetime": 1
+ },
+ "trigger": {
+ "id": "nthTabClosed"
+ },
+ "targeting": "firefoxVersion >= 115"
+}
+```
diff --git a/browser/components/asrouter/docs/debugging-docs.md b/browser/components/asrouter/docs/debugging-docs.md
new file mode 100644
index 0000000000..dab1c0895d
--- /dev/null
+++ b/browser/components/asrouter/docs/debugging-docs.md
@@ -0,0 +1,32 @@
+# Using ASRouter Devtools
+
+## How to enable ASRouter devtools
+- In `about:config`, set `browser.newtabpage.activity-stream.asrouter.devtoolsEnabled` to `true`
+- Visit `about:asrouter` to see the devtools.
+
+## Overview of ASRouter devtools
+
+![Devtools image](./debugging-guide.png)
+
+## How to enable/disable a provider
+
+To enable a provider such as `cfr`, Look at the list of "Message Providers" at the top of the page. Make sure the checkbox is checked next to the provider you want to enable.
+
+To disable it, uncheck the checkbox. You should see a red label indicating the provider is now disabled.
+
+## How to see all messages from a provider
+
+In order to see all active messages for a current provider such as `cfr`, use the drop down selector under the "Messages" section. Select the name of the provider you are interested in.
+
+The messages on the page should now be filtered to include only the provider you selected.
+
+## How to test data collection
+
+All of Messaging System, including ASRouter, is instrumented in Glean.
+To test this instrumentation, please consult [this guide](/toolkit/components/glean/user/instrumentation_tests.md), and:
+
+- In about:config, set:
+ - `browser.newtabpage.activity-stream.telemetry` to `true`
+- To view additional debug logs for messaging system or about:welcome, set:
+ - `messaging-system.log` to `debug`
+ - `browser.aboutwelcome.log` to `debug`
diff --git a/browser/components/asrouter/docs/debugging-guide.png b/browser/components/asrouter/docs/debugging-guide.png
new file mode 100644
index 0000000000..8616a29ab3
--- /dev/null
+++ b/browser/components/asrouter/docs/debugging-guide.png
Binary files differ
diff --git a/browser/components/asrouter/docs/feature-callout.md b/browser/components/asrouter/docs/feature-callout.md
new file mode 100644
index 0000000000..9cd083e5f2
--- /dev/null
+++ b/browser/components/asrouter/docs/feature-callout.md
@@ -0,0 +1,614 @@
+# Feature Callout
+
+Feature Callouts point to and describe features in content pages or the browser chrome. They can consist of a single message or of a sequence of messages. Callouts are different from Spotlights or other dialogs in that they do not block other interactions with the browser. Feature callouts are currently only available for experimentation in the browser chrome. For example, callouts can easily be configured to point to toolbar buttons in the browser chrome.
+
+Callouts may be configured with the following content elements (each of which is optional):
+
+- title
+- subtitle
+- inline title icon
+- a large illustration above the title
+- primary action button
+- secondary action button
+- additional action button
+- dismiss button
+- checkboxes and/or radio buttons
+
+The callout's arrow (the triangle-shaped caret pointing to the anchor) can be positioned in the middle or in the corners of any of the callout's edges, and it can be anchored to the same positions on its anchor element. The arrow position and anchor position each support all 8 cardinal and ordinal directions. The arrow can also be hidden entirely. There is also an optional effect to highlight the button the callout is anchored to. This highlight only works if the anchor element is a button.
+
+## Examples
+
+![Feature Callout](./feature-callout.png)
+
+## Testing Feature Callouts
+
+### Via the devtools:
+
+1. Go to `about:config`, set pref `browser.newtabpage.activity-stream.asrouter.devtoolsEnabled` to `true`
+2. Open a new tab and go to `about:asrouter` in the urlbar
+3. In the devtools Messages section, search for `feature_callout` using the findbar
+4. You should see an example JSON message labeled `TEST_FEATURE_TOUR`. Clicking `Show` next to it should show the callout
+5. You can directly modify the message in the text area with your changes or by pasting your custom message JSON. Clicking `Modify` shows your updated message. Make sure it's valid JSON and be careful not to add unnecessary commas after the final member in an array or the final property of an object, as they will invalidate the message.
+6. For these testing purposes, targeting and trigger are ignored, as the message will be triggered by pressing the "Modify" button. So you won't be able to test triggers and targeting by this method.
+6. Ensure that all required properties are covered according to the schema below
+7. Clicking `Share` copies a link to your clipboard that can be pasted in the urlbar to preview the message and can be shared to get feedback from your team
+
+- **Note:** Only one Feature Callout can be shown at a time. You must dismiss existing callouts before new ones can be shown.
+
+### Via local provider:
+
+You can also test Feature Callouts by adding them to the [local provider](https://searchfox.org/mozilla-central/source/browser/components/asrouter/modules/FeatureCalloutMessages.sys.mjs). While slower than using the devtools, this is useful when you want to test the trigger or targeting, or when your callout's anchor is an element that is not visible while on `about:asrouter` (such as a urlbar button).
+
+### Via Experiments:
+
+You can test Feature Callouts by creating an experiment or landing message in tree. [Messaging Journey](https://experimenter.info/messaging/desktop-messaging-journey) captures creating and testing experiments via Nimbus. This is the most time-consuming method, but if your callout will be launched as an experiment, then it also provides the most accurate preview.
+
+### Schema
+
+```ts
+interface FeatureCallout {
+ // Unique id for the message. Used to store impressions, recorded in telemetry
+ id: string;
+ template: "feature_callout";
+ // Targeting expression string. JEXL is used for evaluation. See the Targeting
+ // section below for details.
+ targeting: string;
+ // Trigger object. See the Triggers section below for details.
+ trigger: {
+ // The trigger's unique identifier, e.g. "nthTabClosed".
+ id: string;
+ // A set of parameters for the triggers. Usage depends on the trigger id.
+ params?: any;
+ // A set of URL match patterns (like globs) used by some triggers.
+ // See https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns
+ patterns?: string[];
+ };
+ // An optional object specifying frequency caps for the message.
+ frequency?: {
+ // A basic limit on the number of times the message can be shown to a user
+ // across the entire lifetime of the user profile.
+ lifetime?: number;
+ // An array specifying any number of limits on the number of times the
+ // message can be shown to a user within a specific time period. This can be
+ // specified in addition to or instead of a lifetime limit.
+ custom?: Array<{
+ // The number of times the message can be shown within the period.
+ cap: number;
+ // The period of time in milliseconds. For example, 24 hours is 86400000.
+ period: number;
+ }>;
+ };
+ // An array of message groups, which are used for frequency capping. Typically
+ // this should be ["cfr"], unless you have a specific reason to do otherwise.
+ groups?: string[];
+ // Messages can optionally have a priority or weight, influencing the order in
+ // which they're shown. Higher priority messages are shown first. Messages can
+ // also be selected randomly based on their weight. However, weight is rarely
+ // used. We recommend using neither weight nor priority, unless you are adding
+ // multiple messages with the same trigger and similar targeting.
+ weight?: number; // e.g. weight: 200 is more likely than weight: 100
+ priority?: number; // e.g. priority: 2 beats priority: 1
+ // Whether the message should be skipped in automated tests. If omitted, the
+ // message can be shown in tests. A truthy value will skip the message in
+ // tests. The value should be a string explaining why the message needs to be
+ // skipped. You can still test messages with this property in automation by
+ // stubbing `ASRouter.messagesEnabledInAutomation` (adding the message id to
+ // the array). This way, you can avoid showing the message in all tests except
+ // the specific test where you want to test it. This has no effect for
+ // messages in Nimbus experiments. It's for local messages only.
+ skip_in_tests?: string;
+ content: {
+ // The same as the id above
+ id: string;
+ template: "multistage";
+ backdrop: "transparent";
+ transitions: false;
+ disableHistoryUpdates: true;
+ // The name of a preference that will be used to store screen progress. Only
+ // relevant if your callout has multiple screens and serves as a tour. This
+ // allows tour progress to persist across sessions and even devices, if the
+ // pref is synced via FxA. In most cases, this will not be needed.
+ tour_pref_name?: string;
+ // A default value for the pref. Can be used if the pref is not set in
+ // Firefox's default prefs. This is the default value that will be used
+ // until the pref is set by the user interacting with the callout. It will
+ // be used to determine the starting screen. Values are JSON objects like
+ // this: { "screen": "SCREEN_1", "complete": false }
+ // The "screen" property is the id of the screen to start on, and the
+ // "complete" property is a boolean indicating whether the tour has been
+ // completed (it should always be false here). As with tour_pref_name, this
+ // should usually be omitted.
+ tour_pref_default_value?: string;
+ // Set to "block" to block all telemetry. Recommended to omit this.
+ metrics?: string;
+ // An array of screens that should be shown in sequence. The first screen
+ // will be shown immediately. If the screen includes actions (such as
+ // `primary_button.action`) with `navigate: true`, the user can advance to
+ // the next screen, causing the first screen to fade out and the next screen
+ // to fade in.
+ screens: [
+ {
+ id: string;
+ // Feature callouts with multiple screens show a series of dots at the
+ // bottom, indicating which screen the user is on. This property allows
+ // you to hide those dots. The steps indicator is already hidden if
+ // there's only one screen, since it's unnecessary. Defaults to false.
+ force_hide_steps_indicator?: boolean;
+ // An array of anchor objects. Each anchor object represents a single
+ // element on the page that the callout should be anchored to. The
+ // callout will be anchored to the first visible element in the array.
+ anchors: [
+ {
+ // A CSS selector for the element to anchor to. The callout will be
+ // anchored to the first visible element that matches this selector.
+ selector: string;
+ // An object representing how the callout should be positioned
+ // relative to the anchor element.
+ panel_position: {
+ // The point on the anchor that the callout should be tied to. See
+ // PopupAttachmentPoint below for the possible values. These are
+ // the same values used by XULPopupElements.
+ anchor_attachment: PopupAttachmentPoint;
+ // The point on the callout that should be tied to the anchor.
+ callout_attachment: PopupAttachmentPoint;
+ // Offsets in pixels to apply to the callout position in the
+ // horizontal and vertical directions. Generally not needed.
+ offset_x?: number;
+ offset_y?: number;
+ };
+ // Hide the arrow that points from the callout to the anchor?
+ hide_arrow?: boolean;
+ // Whether to set the [open] style on the anchor element while the
+ // callout is showing. False to set it, true to not set it. Not all
+ // elements have an [open] style. Buttons do, for example. It's
+ // usually similar to :active.
+ no_open_on_anchor?: boolean;
+ // The desired width of the arrow in a number of pixels. 33.94113 by
+ // default (this corresponds to a triangle with 24px edges). This
+ // also affects the height of the arrow.
+ arrow_width?: number;
+ }
+ ];
+ content: {
+ position: "callout";
+ // By default, callouts don't hide if the user clicks outside of them.
+ // Set this to true to make the callout hide on outside clicks.
+ autohide?: boolean;
+ // Callout card width as a CSS value, e.g. "400px" or "min-content".
+ // Defaults to "400px".
+ width?: string;
+ // Callout card padding in pixels. Defaults to 24.
+ padding?: number;
+ // Callouts normally have a vertical layout, with rows of content. If
+ // you want a single row with a more inline layout, you can use this
+ // property, which works well in tandem with title_logo.
+ layout?: "inline";
+ // An optional object representing a large illustration to show above
+ // other content. See Logo below for the possible properties.
+ logo?: Logo;
+ // The callout's headline. This is optional but commonly used. Can be
+ // a raw string or a LocalizableThing (see interface below).
+ title?: Label;
+ // An optional object representing an icon to show next to the title.
+ // See TitleLogo below for the possible properties.
+ title_logo?: TitleLogo;
+ // A subtitle to show below the title. Typically a longer paragraph.
+ subtitle?: Label;
+ primary_button?: {
+ // Text to show inside the button.
+ label: Label;
+ // Buttons can optionally show an arrow icon, indicating that
+ // clicking the button will advance to the next screen.
+ has_arrow_icon?: boolean;
+ // Buttons can be disabled. The boolean option isn't really useful,
+ // since there's no logic to enable the button. However, if your
+ // screen uses the "multiselect" tile (see tiles), you can use
+ // "hasActiveMultiSelect" to disable the button until the user
+ // selects something.
+ disabled?: boolean | "hasActiveMultiSelect";
+ // Primary buttons can have a "primary" or "secondary" style. This
+ // is useful because you can't change the order of the buttons, but
+ // you can swap the primary and secondary buttons' styles.
+ style?: "primary" | "secondary";
+ // The action to take when the button is clicked. See Action below.
+ action: Action;
+ };
+ secondary_button?: {
+ label: Label;
+ // Extra text to show before the button.
+ text: Label;
+ has_arrow_icon?: boolean;
+ disabled?: boolean | "hasActiveMultiSelect";
+ style?: "primary" | "secondary";
+ action: Action;
+ };
+ additional_button?: {
+ label: Label;
+ // If you have several buttons, you can use this property to control
+ // the orientation of the buttons. By default, buttons are laid out
+ // in a complex way. Use row or column to override this.
+ flow?: "row" | "column";
+ disabled?: boolean;
+ // The additional button can also be styled as a link.
+ style?: "primary" | "secondary" | "link";
+ action: Action;
+ // Justification/alignment of the buttons row/column. Defaults to
+ // "end" (right-justified buttons). You can use space-between if,
+ // for example, you have 2 buttons and you want one on the left and
+ // one on the right.
+ alignment?: "start" | "end" | "space-between";
+ };
+ dismiss_button?: {
+ // This can be used to control the ARIA attributes and tooltip.
+ // Usually it's omitted, since it has a correct default value.
+ label?: Label;
+ // The button can be 32px or 24px. Defaults to 32px.
+ size?: "small" | "large";
+ action: Action;
+ // CSS overrides.
+ marginBlock?: string;
+ marginInline?: string;
+ };
+ // A split button is an additional_button or secondary_button split
+ // into 2 buttons: one that performs the main action, and one with an
+ // arrow that opens a dropdown submenu (which this property controls).
+ submenu_button?: {
+ // This defines the dropdown menu that appears when the user clicks
+ // the split button.
+ submenu: SubmenuItem[];
+ // The submenu button can only be a split button, so a secondary or
+ // additional button needs to exist for it to attach to.
+ attached_to: "secondary_button" | "additional_button";
+ // Used mainly to control the ARIA label and tooltip (tooltips are
+ // currently broken), but can also be used to override CSS styles.
+ label?: Label;
+ // Whether the split button should follow the primary or secondary
+ // button style. Set this to the same style you specified for the
+ // button it's attached to. Defaults to "secondary".
+ style?: "primary" | "secondary";
+ };
+ // Predefined content modules. The only one currently supported in
+ // feature callout is "multiselect", which allows you to show a series
+ // of checkboxes and/or radio buttons.
+ tiles?: {
+ type: "multiselect";
+ // Depends on the type, but we only support "multiselect" currently.
+ data: MultiSelectItem[];
+ // By default, multiselect items appear in the order they're listed
+ // in the data array. Set this to true to randomize the order. This
+ // is most commonly used to randomize the order of answer choices
+ // for a survey question, to avoid the first-choice bias.
+ randomize?: boolean;
+ // Allows CSS overrides of the multiselect container.
+ style?: {
+ color?: string;
+ fontSize?: string;
+ fontWeight?: string;
+ letterSpacing?: string;
+ lineHeight?: string;
+ marginBlock?: string;
+ marginInline?: string;
+ paddingBlock?: string;
+ paddingInline?: string;
+ whiteSpace?: string;
+ flexDirection?: string;
+ flexWrap?: string;
+ flexFlow?: string;
+ flexGrow?: string;
+ flexShrink?: string;
+ justifyContent?: string;
+ alignItems?: string;
+ gap?: string;
+ // Any CSS properties starting with "--" are also allowed, to
+ // override CSS variables used in _feature-callout.scss.
+ "--some-variable"?: string;
+ };
+ };
+ // The dots in the corner that show what screen you're on and how many
+ // screens there are in total. This property is only used to override
+ // the ARIA attributes or tooltip. Not recommended.
+ steps_indicator?: {
+ string_id: string;
+ };
+ // An extra block of configurable content below the title/subtitle but
+ // above the optional `tiles` section and the main buttons. Styles not
+ // yet implemented; not recommended.
+ above_button_content?: LinkParagraphOrImage[];
+ // An optional array of event listeners to add to the page where the
+ // feature callout is shown. This can be used to perform actions in
+ // response to interactions and other events outside of the feature
+ // callout itself. The prototypical use case is dismissing the feature
+ // callout when the user clicks the button the callout is anchored to.
+ // It also supports performing actions on a timeout/interval.
+ page_event_listeners?: Array<{
+ params: {
+ // Event type string, e.g. "click". This supports:
+ // 1. Any DOM event type
+ // 2. "timeout" and "interval" for timers
+ // 3. Internal feature callout events: "touradvance" and
+ // "tourend". This can be used to perform actions when the user
+ // advances to the next screen or finishes the callout tour.
+ type: string;
+ // Target selector, e.g. `tag.class, #id[attr]` - Not needed for
+ // all types.
+ selectors?: string;
+ // addEventListener options
+ options: {
+ // Handle events in capturing phase?
+ capture?: boolean;
+ // Remove listener after first event?
+ once?: boolean;
+ // Prevent default action in event handler?
+ preventDefault?: boolean;
+ // Used only for `timeout` and `interval` event types. These
+ // don't set up real event listeners, but instead invoke the
+ // action on a timer.
+ interval?: number;
+ };
+ };
+ action: {
+ // One of the special message action ids.
+ type?: "string";
+ // Data to pass to the action. Depends on the action.
+ data?: any;
+ // Dismiss screen after performing action? If there's no type, the
+ // action will *only_ dismiss the callout.
+ dismiss?: boolean;
+ };
+ }>;
+ };
+ }
+ ];
+ // Specify the index of the screen to start on. Generally unused.
+ startScreen?: number;
+ };
+}
+
+type PopupAttachmentPoint =
+ | "topleft"
+ | "topright"
+ | "bottomleft"
+ | "bottomright"
+ | "leftcenter"
+ | "rightcenter"
+ | "topcenter"
+ | "bottomcenter";
+
+type Label = string | LocalizableThing;
+
+interface LocalizableThing {
+ // A raw, untranslated string, typically used for EN-only experiments.
+ raw?: string;
+ // A Fluent string id from a .ftl file.
+ string_id?: string;
+ // Arguments to pass to Fluent. Used for Fluent strings that have variables.
+ args?: {
+ [key: string]: string;
+ };
+ // A string to use as the element's aria-label attribute value.
+ aria_label?: string;
+ // CSS overrides.
+ color?: string;
+ fontSize?: string;
+ fontWeight?: string;
+ letterSpacing?: string;
+ lineHeight?: string;
+ marginBlock?: string;
+ marginInline?: string;
+ paddingBlock?: string;
+ paddingInline?: string;
+ whiteSpace?: string;
+}
+
+interface Logo {
+ imageURL: "chrome://branding/content/about-logo.svg";
+ darkModeImageURL: string;
+ reducedMotionImageURL: string;
+ darkModeReducedMotionImageURL: string;
+ // <img> alt text. Defaults to ""
+ alt: string;
+ // CSS style overrides for the icon.
+ width: string;
+ height: string;
+ marginBlock: string;
+ marginInline: string;
+}
+
+interface TitleLogo extends Logo {
+ // Logo alignment relative to the title. Use "top" if you have multiple rows
+ // of text and you want the logo aligned to the top row. Defaults to "center".
+ alignment: "top" | "bottom" | "center";
+}
+
+// Click the Special Message Actions link at the bottom of the page.
+interface Action {
+ // One of the special message action ids.
+ type?: "string";
+ // Data to pass to the action. Depends on the action.
+ data?: any;
+ // Set to true if you want the action to advance to the next screen or hide
+ // the callout if it's the last screen. Can be used in lieu of "type" and
+ // "data" to create a button that just advances the screen.
+ navigate?: boolean;
+ // Same as "navigate" but dismisses the callout instead of advancing to the
+ // next screen.
+ dismiss?: boolean;
+ // Set to true if this action is for the primary button and you're using the
+ // "multiselect" tile. This is what allows the primary button to perform the
+ // actions specified by the user's checkbox/radio selections. It will combine
+ // all the actions for all the selected checkboxes/radios into this action's
+ // data.actions array, and perform them in series.
+ collectSelect?: boolean;
+}
+
+// Either an image or a paragraph that supports inline links. Currently requires
+// Fluent strings. Raw strings are not supported.
+interface LinkParagraphOrImage extends Logo {
+ // Which type of content this is.
+ type: "image" | "text";
+
+ // Each of these is only used if `type` is "text".
+ // The `text` object contains the Fluent string id. Doesn't support raw text.
+ text: LocalizableThing;
+ // An array of key names. Each link key must exist in screen.content. For
+ // example, if link_keys is ["learn_more"], then there must be a key named
+ // "learn_more" in screen.content. The value of that key must be an object
+ // with an `action` property (which is an Action). Moreover, the string_id in
+ // the `text` object (see the property above) must refer to a Fluent string
+ // that contains an anchor element with `data-l10n-name="learn_more"`, e.g.:
+ // my-string = Do the thing! <a data-l10n-name="learn_more">Learn more</a>
+ link_keys: string[];
+}
+
+interface MultiSelectItem {
+ // A unique id for this item, distinguishing it from other items.
+ id: string;
+ type: "checkbox" | "radio";
+ // Radios need to be members of radio groups to work properly. Set the same
+ // group for your radios to make sure only one can be selected at a time.
+ group?: string;
+ // Set to true to make it selected/checked by default.
+ defaultValue: false;
+ label?: Label;
+ // CSS overrides for the div box containing the item and its optional label.
+ style?: {
+ color?: string;
+ fontSize?: string;
+ fontWeight?: string;
+ letterSpacing?: string;
+ lineHeight?: string;
+ marginBlock?: string;
+ marginInline?: string;
+ paddingBlock?: string;
+ paddingInline?: string;
+ whiteSpace?: string;
+ flexDirection?: string;
+ flexWrap?: string;
+ flexFlow?: string;
+ flexGrow?: string;
+ flexShrink?: string;
+ justifyContent?: string;
+ alignItems?: string;
+ gap?: string;
+ };
+ // You can replace the checkbox check/radio circle with an icon by using a
+ // bunch of CSS overrides.
+ icon?: {
+ style: {
+ color?: string;
+ fontSize?: string;
+ fontWeight?: string;
+ letterSpacing?: string;
+ lineHeight?: string;
+ marginBlock?: string;
+ marginInline?: string;
+ paddingBlock?: string;
+ paddingInline?: string;
+ whiteSpace?: string;
+ width?: string;
+ height?: string;
+ background?: string;
+ backgroundColor?: string;
+ backgroundImage?: string;
+ backgroundSize?: string;
+ backgroundPosition?: string;
+ backgroundRepeat?: string;
+ backgroundOrigin?: string;
+ backgroundClip?: string;
+ border?: string;
+ borderRadius?: string;
+ appearance?: string;
+ fill?: string;
+ stroke?: string;
+ outline?: string;
+ outlineOffset?: string;
+ boxShadow?: string;
+ };
+ };
+ // The action is not performed until the user clicks the primary button.
+ action: Action;
+}
+
+interface SubmenuItem {
+ // Submenus can have 3 types of items, just like normal menupopups
+ // in Firefox.
+ type: "action" | "menu" | "separator";
+ // The id is used to identify the submenu item in telemetry.
+ id?: string;
+ label: Label;
+ // Used only for type "action". The action to perform when the
+ // submenu item is clicked.
+ action?: Action;
+ // Used only for type "menu". The submenu items to show when the
+ // user hovers over this item. This is a recursive structure.
+ submenu: SubmenuItem[];
+ // An optional URL specifying an icon to show next to the label.
+ icon?: string;
+}
+```
+
+### Example JSON
+
+```json
+{
+ "id": "TEST_FEATURE_TOUR",
+ "template": "feature_callout",
+ "groups": [],
+ "targeting": "true",
+ "content": {
+ "id": "TEST_FEATURE_TOUR",
+ "template": "multistage",
+ "backdrop": "transparent",
+ "transitions": false,
+ "disableHistoryUpdates": true,
+ "screens": [
+ {
+ "id": "FEATURE_CALLOUT_1",
+ "anchors": [
+ {
+ "selector": "#PanelUI-menu-button",
+ "panel_position": {
+ "anchor_attachment": "bottomcenter",
+ "callout_attachment": "topright"
+ }
+ }
+ ],
+ "content": {
+ "position": "callout",
+ "title": {
+ "raw": "Panel Feature Callout"
+ },
+ "subtitle": {
+ "raw": "Hello!"
+ },
+ "primary_button": {
+ "label": {
+ "raw": "Advance"
+ },
+ "action": {
+ "navigate": true
+ }
+ },
+ "dismiss_button": {
+ "action": {
+ "dismiss": true
+ }
+ }
+ }
+ }
+ ]
+ },
+}
+```
+
+### Targeting
+
+Messages use JEXL targeting expressions to determine whether the user is eligible to see the message. See [Guide to targeting with JEXL](./targeting-guide.md) and [Targeting attributes](./targeting-attributes.md) for details.
+
+### Triggers
+
+Triggers are used to determine when a message should be shown. See [Trigger Listeners](/toolkit/components/messaging-system/docs/TriggerActionSchemas/index.md) for details.
+
+### Special Message Actions
+
+Buttons, links, and other calls to action can use one or more of a set of predefined actions. [Click here](/toolkit/components/messaging-system/docs/SpecialMessageActionSchemas/index.md) for a full list of valid actions.
diff --git a/browser/components/asrouter/docs/feature-callout.png b/browser/components/asrouter/docs/feature-callout.png
new file mode 100644
index 0000000000..8c710145b9
--- /dev/null
+++ b/browser/components/asrouter/docs/feature-callout.png
Binary files differ
diff --git a/browser/components/asrouter/docs/first-run.md b/browser/components/asrouter/docs/first-run.md
new file mode 100644
index 0000000000..59cb1d298a
--- /dev/null
+++ b/browser/components/asrouter/docs/first-run.md
@@ -0,0 +1,68 @@
+# Onboarding flow
+
+Onboarding flow comprises of entire flow users have after Firefox has successfully been installed or upgraded.
+
+For new users, the first instance of new tab shows relevant messaging on about:welcome. For existing users, an upgrade dialog with release highlights is shown on major release upgrades.
+
+
+## New User Onboarding
+
+A full-page multistep experience that shows up on first run since Fx80 with `browser.aboutwelcome.enabled` pref as `true`. Setting `browser.aboutwelcome.enabled` to `false` takes user to about:newtab and hides about:welcome.
+
+### Default values
+
+Multistage proton onboarding experience is live since Fx89 and its major variations are:
+
+#### Zero onboarding
+
+No about:welcome experience is shown (users see about:newtab during first run).
+
+Testing instructions: Set `browser.aboutwelcome.enabled` to `false` in about:config
+
+#### Proton
+
+A full-page multistep experience that shows a large splash screen and several subsequent screens. See [Default experience variations](#default-experience-variations) for more information.
+
+#### Return to AMO (RTAMO)
+
+Special custom onboarding experience shown to users when they try to download an addon from addons.mozilla.org but don’t have Firefox installed. This experience allows them to install the addon they were trying to install directly from a button on [RTAMO](https://docs.google.com/document/d/1QOJ8P0xQbdynAmEzOIx8I5qARwA-VqmOMpHzK9h9msg/edit?usp=sharing).
+
+Note that this uses [attribution data](https://docs.google.com/document/d/1zB5zwiyNVOiTD4I3aZ-Wm8KFai9nnWuRHsPg-NW4tcc/edit#heading=h.szk066tfte4n) added to the browser during the download process, which is only currently implemented for Windows.
+
+Testing instructions:
+- Set pref browser.newtabpage.activity-stream.asrouter.devtoolsEnabled as true
+- Open about:asrouter
+- Click Targeting -> Attribution -> Force Attribution
+- Open about:welcome, should display RTAMO page
+
+### General capabilities
+- Run experiments and roll-outs through Nimbus (see [FeatureManifests](https://searchfox.org/mozilla-central/rev/5e955a47c4af398e2a859b34056017764e7a2252/toolkit/components/nimbus/FeatureManifest.js#56)), only windows is supported. FeatureConfig (from prefs or experiments) has higher precedence to defaults. See [Default experience variations](#default-experience-variations)
+- AboutWelcomeDefaults methods [getDefaults](https://searchfox.org/mozilla-central/rev/81c32a2ea5605c5cb22bd02d28c362c140b5cfb4/browser/components/newtab/aboutwelcome/lib/AboutWelcomeDefaults.jsm#539) and [prepareContentForReact](https://searchfox.org/mozilla-central/rev/81c32a2ea5605c5cb22bd02d28c362c140b5cfb4/browser/components/newtab/aboutwelcome/lib/AboutWelcomeDefaults.jsm#566) have dynamic rules which are applied to both experiments and default UI before content is shown to user.
+- about:welcome only shows up for users who download Firefox Beta or release (currently not enabled on Nightly)
+- [Enterprise builds](https://searchfox.org/mozilla-central/rev/5e955a47c4af398e2a859b34056017764e7a2252/browser/components/enterprisepolicies/Policies.jsm#1385) can turn off about:welcome by setting the browser.aboutwelcome.enabled preference to false.
+
+### Default experience variations
+In order of precedence:
+- Has AMO attribution
+ - Return to AMO
+- Experiments
+- Defaults
+ - Proton default content with below screens
+ - Welcome Screen with option to 'Pin Firefox', 'Set default' or 'Get Started'
+ - Import screen allows user to import password, bookmarks and browsing history from previous browser.
+ - Set a theme lets users personalize Firefox with a theme.
+
+## Upgrade Dialog
+Upgrade Dialog was first introduced in Fx89 with MR1 release. It replaces whatsnew tab with an upgrade modal explaining proton changes, setting Firefox as default and/or pinning, and allowing theme change.
+
+### Feature Details:
+- Hides whatsnew tab on release channel when Upgrade Modal is shown
+- Modal dialog appears on major version upgrade to 89 for MR1
+ - It’s a window modal preventing access to tabs and other toolbar UI
+- Support desired content and actions on each screen. For MR1 initial screen explains proton changes, highlight option to set Firefox as default and pin. Subsequent screen allows theme changes.
+
+### Testing Instructions:
+- In about:config, set:
+ - `browser.startup.homepage_override.mstone` to `88.0` . The dialog only shows after it detects a major upgrade and need to set to 88 to trigger MR1 upgrade dialog.
+ - Ensure pref `browser.startup.upgradeDialog.version` is empty. After the dialog shows, `browser.startup.upgradeDialog.version` remembers what version of the dialog to avoid reshowing.
+- Restart Firefox
diff --git a/browser/components/asrouter/docs/index.rst b/browser/components/asrouter/docs/index.rst
new file mode 100644
index 0000000000..dc2d8e4ebf
--- /dev/null
+++ b/browser/components/asrouter/docs/index.rst
@@ -0,0 +1,108 @@
+================
+Messaging System
+================
+
+Vision
+------
+Firefox must be an opinionated user agent that keeps folks safe, informed and
+effective while browsing the Web. In order to have an opinion, Firefox must
+have a voice.
+
+That voice will **respect the user’s attention** while surfacing contextually
+relevant and timely information tailored to their individual needs and choices.
+
+What does Messaging System support?
+-----------------------------------
+There are several key windows of opportunity, such as the first-run activation
+phase or coordinated feature releases, where Firefox engages with users.
+
+The Firefox Messaging System supports this engagement by targeting messages
+exactly to the users who need to see them and enables the development of new
+user messages that can be easily tested and deployed. It offers standard
+mechanisms to measure user engagement and to perform user messaging experiments
+with reduced effort across engineering teams and a faster delivery cycle from
+ideation to analysis of results.
+
+This translates to **users seeing fewer and more relevant in-product
+messages**, while supporting fast delivery, experimentation, and protection of
+our users time and attention.
+
+Messaging System Overview
+-------------------------
+At the core of the Firefox Messaging System is the Messaging System Router
+(called ASRouter for historical reasons). The router is a generalized Firefox
+component and set of conventions that provides:
+
+* Flexible and configurable routing of local or remote Messages to UI
+ Templates. This allows new message campaigns to be started and controlled
+ on or off-trains
+* Traffic Cop message sequencing and intermediation to prevent multiple
+ messages being concurrently shown
+* Programmable message targeting language to show the right message to the
+ right user at the right time
+* A template library of reusable Message and Notification UIs
+* Full compatibility with Normandy pref-flip experiments
+* Generalized and privacy conscious event telemetry
+* Flexible Frequency Capping to mitigate user message fatigue
+* Localized off train Messages
+* Powerful development/debugging/QA tools on about:asrouter
+
+Message Routing
+---------------
+.. image:: ./message-routing-overview.png
+ :align: center
+ :alt: Message Routing Overview
+
+The Firefox Messaging System implements a separation-of-concerns pattern for
+Messages, UI Templates, and Timing/Targeting mechanisms. This allows us to
+maintain a high standard of security and quality while still allowing for
+maximum flexibility around content creation.
+
+
+UI Templates
+------------
+We have built a library of reusable Notification and Message interfaces which
+land in the Firefox codebase and ride the trains. These templates have a
+defined schema according to the available design components (e.g. titles, text,
+icons) and access to a set of enhanced user actions such as triggering URLs,
+launching menus, or installing addons, which can be attached to interactive
+elements (such as buttons).
+
+Current templates include\:
+
+.. In theory, we ought to be able to use the :glob: directive here to
+.. automatically generate the list below. For unknown reasons, however,
+.. `mach doc` _sometimes_ gets confused and refuses to find patterns like
+.. `*.md`.
+.. toctree::
+ :maxdepth: 1
+
+ moments-page
+ feature-callout
+ contextual-feature-recommendation
+ about-welcome
+ infobars
+ spotlight
+ private-browsing
+
+Detailed Docs
+-------------
+
+* Read more about `trigger listeners and user action schemas`__.
+
+.. __: /toolkit/components/messaging-system/docs
+
+.. In theory, we ought to be able to use the :glob: directive here to
+.. automatically generate the list below. For unknown reasons, however,
+.. `mach doc` _sometimes_ gets confused and refuses to find patterns like
+.. `*.md`.
+.. toctree::
+ :maxdepth: 2
+
+ simple-cfr-template
+ debugging-docs
+ first-run
+ remote_cfr
+ targeting-attributes
+ targeting-guide
+ telemetry
diff --git a/browser/components/asrouter/docs/infobar.png b/browser/components/asrouter/docs/infobar.png
new file mode 100644
index 0000000000..a0bf137689
--- /dev/null
+++ b/browser/components/asrouter/docs/infobar.png
Binary files differ
diff --git a/browser/components/asrouter/docs/infobars.md b/browser/components/asrouter/docs/infobars.md
new file mode 100644
index 0000000000..29472a9f73
--- /dev/null
+++ b/browser/components/asrouter/docs/infobars.md
@@ -0,0 +1,60 @@
+# Infobars
+Infobars are shown at the top of the browser content area, these can be per tab (switching tabs hides it) or global (persistent across tabs).
+
+## Example of a Infobar
+![Infobars](./infobar.png)
+
+## Testing Infobars
+
+### Via the dev tools:
+1. Go to `about:config`, set pref `browser.newtabpage.activity-stream.asrouter.devtoolsEnabled` to `true`
+2. Open a new tab and go to `about:asrouter` in the url bar
+3. In devtools Messages section, select and show messages from `cfr` as provider
+4. You should see example JSON messages with `"template": "infobar"`. Clicking `Show` next to infobar message should show respective message UI
+5. You can directly modify the message in the text area with your changes or by pasting your custom message JSON. Clicking `Modify` shows your updated message.
+6. Ensure that all required properties are covered according to the [Infobar Schema](https://searchfox.org/mozilla-central/source/browser/components/asrouter/content-src/templates/CFR/templates/InfoBar.schema.json)
+7. Clicking `Share`, copies link to clipboard that can be pasted in the url bar to preview infobar message UI in browser and can be shared to get feedback from your team.
+- **Note:** Overlapping infobars will not be shown when testing multiple infobar messages
+- **Note:** Modifying the `label` property will change the text within the buttons, eg: `"label": "Disable"`
+
+### Via Experiments:
+You can test Infobar messaging surface by creating an experiment or landing message in tree. [Messaging Journey](https://experimenter.info/messaging/desktop-messaging-journey) captures creating and testing experiments via Nimbus.
+
+### Example JSON for Infobar
+```
+{
+ "content": {
+ "text": "Your privacy matters. Nightly now securely routes your DNS requests whenever possible to a partner service to protect you while you browse.",
+
+ "buttons": [
+ {
+ "label": "Okay",
+ "action": {
+ "type": "ACCEPT_DOH"
+ },
+ "primary": true
+ },
+ {
+ "label": "Disable",
+ "action": {
+ "type": "DISABLE_DOH"
+ }
+ }
+ ],
+ "priority": 1,
+ "bucket_id": "TEST_DOH_BUCKET"
+ },
+ "trigger": {
+ "id": "openURL",
+ "patterns": [
+ "*://*/*"
+ ]
+ },
+ "template": "infobar",
+ "frequency": {
+ "lifetime": 3
+ },
+ "targeting": "firefoxVersion >= 89",
+ "id": "Test_Infobar"
+}
+```
diff --git a/browser/components/asrouter/docs/message-routing-overview.png b/browser/components/asrouter/docs/message-routing-overview.png
new file mode 100644
index 0000000000..0ec2ec3c14
--- /dev/null
+++ b/browser/components/asrouter/docs/message-routing-overview.png
Binary files differ
diff --git a/browser/components/asrouter/docs/moments-page.md b/browser/components/asrouter/docs/moments-page.md
new file mode 100644
index 0000000000..97442baf29
--- /dev/null
+++ b/browser/components/asrouter/docs/moments-page.md
@@ -0,0 +1,64 @@
+# Moments Page
+
+## What are Moments pages?
+Moments Page is a web page URL that’s loaded for existing Firefox Desktop users on subsequent startup for user profiles meeting the targeting specified in moments message config.
+
+Moments Pages are different from WNP (What’s New Page) that shows up when users update to a new major version based on configurations built into the executable for that channel/build. Moments are shown outside of an upgrade on regular restarts and are remotely configurable via Messaging System.
+
+The constraint of synchronous start-up behavior prevents waiting for Remote Settings to make a targeting decision resulting in “Moments” shown on subsequent start-ups.
+
+### Startup pref lifecycle
+The process of selecting/blocking/showing is as follows:
+1. At the start of any `“update”` cycle (i.e. on a regular interval, and preferably when remote settings updates):
+2. Check the override pref `browser.startup.homepage_override.once`; if a message ID is set, unblock that message since it has not yet been shown. Clear the override pref.
+3. Run messages through targeting and select a message.
+4. [Set the message with expiration data](https://searchfox.org/mozilla-central/rev/3b707c8fd7e978eebf24279ee51ccf07895cfbcb/browser/components/newtab/lib/MomentsPageHub.jsm#87) in the pref.
+5. Block the message that was chosen immediately.
+
+
+When the message is shown at startup:
+1. Clear the override pref.
+
+
+
+
+### Example of a Moments page
+![Moments](./moments.png)
+
+## Testing Moments Page
+
+### Via the dev tools:
+1. In the search tab go to `about:config`, set `browser.newtabpage.activity-stream.asrouter.devtoolsEnabled` to `true`
+2. Open a new tab, in the search tab go to `about:asrouter`
+3. In devtools, select and show messages from `panel_local_testing` as provider
+4. You should see example JSON messages with `"template": "update_action"`. You can directly modify the message in the text area with your changes or by pasting your custom message JSON. For testing, please keep `id` property in config same as respective message modified.
+5. Clicking `Modify` updates the override pref `browser.startup.homepage_override.once` and configures the Messaging System to open moments url in message config on next browser restart.
+6. Ensure that all required properties are covered according to the [Moments Schema](https://searchfox.org/mozilla-central/source/browser/components/asrouter/content-src/templates/OnboardingMessage/UpdateAction.schema.json)
+7. Restart firefox and your moments page should pop up on re-run
+
+### Via Experiments:
+You can test the moments page by creating an experiment. [Messaging Journey](https://experimenter.info/messaging/desktop-messaging-journey) captures creating experiments via Nimbus.
+
+### Example JSON for Moments page
+```
+{
+ "groups": [
+ "moments-pages"
+ ],
+ "content": {
+ "action": {
+ "id": "moments-wnp",
+ "data": {
+ "url": "https://www.mozilla.org/firefox/welcome/12",
+ "expireDelta": 172800000
+ }
+ }
+ },
+ "trigger": {
+ "id": "momentsUpdate"
+ },
+ "template": "update_action",
+ "targeting": "true",
+ "id": "WNP_THANK_YOU"
+}
+```
diff --git a/browser/components/asrouter/docs/moments.png b/browser/components/asrouter/docs/moments.png
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/browser/components/asrouter/docs/moments.png
diff --git a/browser/components/asrouter/docs/private-browsing.md b/browser/components/asrouter/docs/private-browsing.md
new file mode 100644
index 0000000000..405a5a1019
--- /dev/null
+++ b/browser/components/asrouter/docs/private-browsing.md
@@ -0,0 +1,59 @@
+# PrivateBrowsing
+
+## What is PrivateBrowsing?
+Messages shown inside `about:privatebrowsing` (incognito) content page. This messaging surface allows experimentation on content shown (promotion and info section) when new private window or tab is opened.
+
+### Example of a PrivateBrowsing window
+![Private Browsing](./private-browsing.png)
+
+## Testing PrivateBrowsing
+
+### Via the dev tools:
+1. In the search tab go to `about:config`, set `browser.newtabpage.activity-stream.asrouter.devtoolsEnabled` to `true`
+2. Open a new tab, in the search tab go to `about:asrouter`
+3. On the left navigation, click on `Private Browsing`
+4. This shows all example messages developed for `about:privatebrowsing` messaging surface
+5. You can directly modify the message in the text area with your changes or by pasting your custom message JSON. Ensure that all required properties are covered according to the [Private Browsing Schema](https://searchfox.org/mozilla-central/source/browser/components/asrouter/content-src/templates/PBNewtab/NewtabPromoMessage.schema.json)
+6. To view message in private browsing window, click the circle to select respective message. Then hit the blue `Open a Private Browsing Window` at the top of the screen. This opens new private window with promotion and info section updated with custom message.
+
+![Circle](./selected-PB.png)
+
+7. To reset the chosen PrivateBrowsing window and choose another, click `Reset Message State` at the top of the screen
+
+### Via Experiments:
+You can test any `privatebrowsing` custom message UI by creating an experiment. [Messaging Journey](https://experimenter.info/messaging/desktop-messaging-journey) captures creating experiments via Nimbus.
+
+### Example of messaging in privatebrowsing window
+```
+{
+ "id": "TEST_PBM_PROMO",
+ "template": "pb_newtab",
+ "content": {
+ "promoEnabled": true,
+ "promoType": "VPN",
+ "infoEnabled": true,
+ "infoBody": "Nightly clears your search and browsing history",
+ "infoLinkText": "Click Here to Learn More",
+ "infoTitleEnabled": false,
+ "promoLinkType": "button",
+ "promoLinkText": "fluent:about-private-browsing-prominent-cta",
+ "promoSectionStyle": "below-search",
+ "promoHeader": "Get privacy protections",
+ "promoTitle": "Hide browsing activity and location with Mozilla VPN. One click creates a secure connection",
+ "promoTitleEnabled": true,
+ "promoImageLarge": "chrome://browser/content/assets/moz-vpn.svg",
+ "promoButton": {
+ "action": {
+ "type": "OPEN_URL",
+ "data": {
+ "args": "https://vpn.mozilla.org/"
+ }
+ }
+ }
+ },
+ "targeting": "firefoxVersion >= 89",
+ "frequency": {
+ "lifetime": 3
+ }
+}
+```
diff --git a/browser/components/asrouter/docs/private-browsing.png b/browser/components/asrouter/docs/private-browsing.png
new file mode 100644
index 0000000000..0ed1f56c4e
--- /dev/null
+++ b/browser/components/asrouter/docs/private-browsing.png
Binary files differ
diff --git a/browser/components/asrouter/docs/remote_cfr.md b/browser/components/asrouter/docs/remote_cfr.md
new file mode 100644
index 0000000000..47daade633
--- /dev/null
+++ b/browser/components/asrouter/docs/remote_cfr.md
@@ -0,0 +1,82 @@
+# Remote CFR Messages
+Starting in Firefox 68, CFR messages will be defined using [Remote Settings](https://remote-settings.readthedocs.io/en/latest/index.html). In this document, we'll cover how to set up a dev environment.
+
+## Using a dev server for Remote CFR
+
+> Note: Since Novembre 2021, Remote Settings has a proper DEV instance, which is
+> reachable without VPN, but has the same config (openid, multi-signoff, ...)
+> and collections as STAGE/PROD.
+
+**1. Obtain your Bearer Token**
+
+Until [Bug 1630651](https://bugzilla.mozilla.org/show_bug.cgi?id=1630651) happens, the easiest way to obtain your OpenID credentials is to use the admin interface.
+
+1. [Login on the Admin UI](https://remote-settings-dev.allizom.org/v1/admin/) using your LDAP identity
+2. Copy the authentication header (📋 icon in the top bar)
+3. Test your credentials with ``curl``. When reaching out the server root URL with this bearer token you should see a ``user`` entry whose ``id`` field is ``ldap:<you>@mozilla.com``.
+
+```bash
+SERVER=https://settings.dev.mozaws.net/v1
+BEARER_TOKEN="Bearer uLdb-Yafefe....2Hyl5_w"
+
+curl -s ${SERVER}/ -H "Authorization:${BEARER_TOKEN}" | jq .user
+```
+
+**2. Create/Update/Delete CFR entries**
+
+> The messages can also be created manually using the [admin interface](https://settings.dev.mozaws.net/v1/admin/).
+
+In following example, we will create a new entry using the REST API (reusing `SERVER` and `BEARER_TOKEN` from previous step).
+
+```bash
+CID=cfr
+
+# post a message
+curl -X POST ${SERVER}/buckets/main-workspace/collections/${CID}/records \
+ -d '{"data":{"id":"PIN_TAB","template":"cfr_doorhanger","content":{"category":"cfrFeatures","bucket_id":"CFR_PIN_TAB","notification_text":{"string_id":"cfr-doorhanger-extension-notification"},"heading_text":{"string_id":"cfr-doorhanger-pintab-heading"},"info_icon":{"label":{"string_id":"cfr-doorhanger-extension-sumo-link"},"sumo_path":"extensionrecommendations"},"text":{"string_id":"cfr-doorhanger-pintab-description"},"descriptionDetails":{"steps":[{"string_id":"cfr-doorhanger-pintab-step1"},{"string_id":"cfr-doorhanger-pintab-step2"},{"string_id":"cfr-doorhanger-pintab-step3"}]},"buttons":{"primary":{"label":{"string_id":"cfr-doorhanger-pintab-ok-button"},"action":{"type":"PIN_CURRENT_TAB"}},"secondary":[{"label":{"string_id":"cfr-doorhanger-extension-cancel-button"},"action":{"type":"CANCEL"}},{"label":{"string_id":"cfr-doorhanger-extension-never-show-recommendation"}},{"label":{"string_id":"cfr-doorhanger-extension-manage-settings-button"},"action":{"type":"OPEN_PREFERENCES_PAGE","data":{"category":"general-cfrfeatures"}}}]}},"targeting":"locale == \"en-US\" && !hasPinnedTabs && recentVisits[.timestamp > (currentDate|date - 3600 * 1000 * 1)]|length >= 3","frequency":{"lifetime":3},"trigger":{"id":"frequentVisits","params":["docs.google.com","www.docs.google.com","calendar.google.com","messenger.com","www.messenger.com","web.whatsapp.com","mail.google.com","outlook.live.com","facebook.com","www.facebook.com","twitter.com","www.twitter.com","reddit.com","www.reddit.com","github.com","www.github.com","youtube.com","www.youtube.com","feedly.com","www.feedly.com","drive.google.com","amazon.com","www.amazon.com","messages.android.com"]}}}' \
+ -H 'Content-Type:application/json' \
+ -H "Authorization:${BEARER_TOKEN}"
+```
+
+The collection was modified and now with pending changes in the workspace. We will now request a review, so that the changes become visible in the **preview** bucket.
+
+```bash
+# request review
+curl -X PATCH ${SERVER}/buckets/main-workspace/collections/${CID} \
+ -H 'Content-Type:application/json' \
+ -d '{"data": {"status": "to-review"}}' \
+ -H "Authorization:${BEARER_TOKEN}"
+```
+
+Now this new record should be listed here: https://settings.dev.mozaws.net/v1/buckets/main-preview/collections/cfr/records
+
+**3. Set Remote Settings prefs to use the dev server.**
+
+Until [support for the DEV environment](https://github.com/mozilla-extensions/remote-settings-devtools/issues/66) is added to the [Remote Settings dev tools](https://github.com/mozilla-extensions/remote-settings-devtools/), we'll change the preferences manually.
+
+> These are critical preferences, you should use a dedicated Firefox profile for development.
+
+```javascript
+ Services.prefs.setCharPref("services.settings.loglevel", "debug");
+ Services.prefs.setCharPref("services.settings.server", "https://settings.dev.mozaws.net/v1");
+ // Pull data from the preview bucket.
+ RemoteSettings.enablePreviewMode(true);
+```
+
+**3. Set ASRouter CFR pref to use Remote Settings provider and enable asrouter devtools.**
+
+```javascript
+Services.prefs.setStringPref("browser.newtabpage.activity-stream.asrouter.providers.cfr", JSON.stringify({"id":"cfr-remote","enabled":true,"type":"remote-settings","collection":"cfr"}));
+Services.prefs.setBoolPref("browser.newtabpage.activity-stream.asrouter.devtoolsEnabled", true);
+```
+
+**4. Go to `about:asrouter`**
+There should be a "cfr-remote" provider listed.
+
+## Using the staging server for Remote CFR
+
+If your message is published in the staging environment the easiest way to test is using the [Remote Settings Devtools](https://github.com/mozilla/remote-settings-devtools/releases) addon. You can install this by going to `about:debugging` and using the `Load Temporary Addon` feature.
+The devtools allow you to switch your profile between production and staging and takes care of correctly flipping all the required preferences.
+
+## Remote l10n
+By default, all CFR messages are localized with the remote Fluent files hosted in `ms-language-packs` on Remote Settings. For local test and development, you can force ASRouter to use the local Fluent files by flipping the pref `browser.newtabpage.activity-stream.asrouter.useRemoteL10n`.
diff --git a/browser/components/asrouter/docs/selected-PB.png b/browser/components/asrouter/docs/selected-PB.png
new file mode 100644
index 0000000000..ee6fdcc26e
--- /dev/null
+++ b/browser/components/asrouter/docs/selected-PB.png
Binary files differ
diff --git a/browser/components/asrouter/docs/simple-cfr-template.rst b/browser/components/asrouter/docs/simple-cfr-template.rst
new file mode 100644
index 0000000000..a1edf4cc8a
--- /dev/null
+++ b/browser/components/asrouter/docs/simple-cfr-template.rst
@@ -0,0 +1,37 @@
+Simple CFR Template
+--------------------
+
+The “Simple CFR Template” is a two-stage UI (a chiclet notification and a door-hanger)
+that shows up on a configurable `trigger condition`__, such as when the user visits a
+particular web page.
+
+.. __: /toolkit/components/messaging-system/docs/TriggerActionSchemas
+
+Warning! Before reading, you should consider whether a `Messaging Experiment is relevant for your needs`__.
+
+.. __: https://docs.google.com/document/d/1S45a_nFn8QRM8gvsxCM6HHROrIQlQQl6fUlJ2j63PGI/edit
+
+.. image:: ./cfr_doorhanger_screenshot.png
+ :align: center
+ :alt: Simple CFR Template 2 stage
+
+Doorhanger Configuration
+=========================
+
+Stage 1 – Chiclet
+++++++++++++++++++
+
+* **chiclet_label**: The text that shows up in the chiclet. 20 characters max.
+* **chiclet_color**: The background color of the chiclet as a HEX code.
+
+
+Stage 2 – Door-hanger
+++++++++++++++++++++++
+
+* **title**: Title text at the top of the door hanger.
+* **body**: A longer paragraph of text.
+* **icon**: An image (please provide a URL or the image file up to 96x96px).
+* **primary_button_label**: The label of the button.
+* **primary_button_action**: The special action triggered by clicking on the button. Choose any of the available `button actions`__. Common examples include opening a section of about:preferences, or opening a URL.
+
+.. __: /toolkit/components/messaging-system/docs/SpecialMessageActionSchemas
diff --git a/browser/components/asrouter/docs/spotlight.md b/browser/components/asrouter/docs/spotlight.md
new file mode 100644
index 0000000000..99d3efe59f
--- /dev/null
+++ b/browser/components/asrouter/docs/spotlight.md
@@ -0,0 +1,90 @@
+# Spotlight
+This is a window or tab level modal, the user is given a primary and a secondary button to interact with the modal.
+Spotlights by default are `“window modal”` preventing access to the rest of the browser including opening and switching tabs. `“Tab modal”` grays out page content and allows interacting with tabs and the rest of the browser.
+
+[More examples of templates supported in Spotlight](https://experimenter.info/messaging/desktop-messaging-surfaces/#multistage-spotlight)
+
+## Example of Spotlight page
+
+![Spotlight](./spotlight.png)
+
+## Testing Spotlight
+1. Go to `about:config`, set pref `browser.newtabpage.activity-stream.asrouter.devtoolsEnabled` to `true`
+2. Open a new tab and go to `about:asrouter` in the url bar
+3. In devtools `Messages` section, select and show messages from `onboarding` as provider
+4. You should see example JSON messages with `"template": "spotlight"`. Clicking `Show` next to spotlight template message should show respective message UI
+5. For quick testing, you can directly modify the message in the text area with your changes or by pasting your custom screen message JSON. Clicking `Modify` shows your new updated spotlight message.
+6. Ensure that all required properties are covered according to the [Spotlight Schema](https://searchfox.org/mozilla-central/source/browser/components/asrouter/content-src/templates/OnboardingMessage/Spotlight.schema.json)
+7. Clicking `Share`, copies link to clipboard that can be pasted in the url bar to preview spotlight custom screen(s) in browser and can be shared to get feedback from your team.
+- **Note:** Spotlight can be either window or tab level, with the `"modal": "tab"` or `"modal": "window"` property in the recipe
+
+### Via the Experiments:
+You can test the spotlight by creating an experiment or landing a message in tree. [Messaging Journey](https://experimenter.info/messaging/desktop-messaging-journey) captures creating and testing experiments via Nimbus and landing messages in Firefox.
+
+### Example JSON recipe for Spotlight
+
+```
+{
+ "template": "spotlight",
+ "targeting": "firefoxVersion >= 114",
+ "frequency": {
+ "lifetime": 1
+ },
+ "trigger": {
+ "id": "defaultBrowserCheck"
+ },
+ "content": {
+ "template": "multistage",
+ "id": "Spotlight_MESSAGE_ID",
+ "transitions": true,
+ "modal": "tab",
+ "screens": [
+ {
+ "id": "Screen_ID",
+ "content": {
+ "logo": {
+ "imageURL": "chrome://activity-stream/content/data/content/assets/heart.webp",
+ "height": "73px"
+ },
+ "title": {
+ "fontSize": "36px",
+ "raw": "Say hello to Firefox"
+ },
+ "title_style": "fancy shine",
+ "subtitle": {
+ "lineHeight": "1.4",
+ "marginBlock": "8px 16px",
+ "raw": "Here’s a quick reminder that you can keep your favorite browser just one click away."
+ },
+ "primary_button": {
+ "label": {
+ "string_id": "onboarding-start-browsing-button-label"
+ },
+ "action": {
+ "type": "OPEN_URL",
+ "data": {
+ "args": "https://www.mozilla.org",
+ "where": "tab"
+ }
+ }
+ },
+ "secondary_button": {
+ "action": {
+ "navigate": true
+ },
+ "label": {
+ "marginBlock": "0 -20px",
+ "raw": "Not now"
+ }
+ },
+ "dismiss_button": {
+ "action": {
+ "navigate": true
+ }
+ }
+ }
+ }
+ ]
+ }
+}
+```
diff --git a/browser/components/asrouter/docs/spotlight.png b/browser/components/asrouter/docs/spotlight.png
new file mode 100644
index 0000000000..fd417a1897
--- /dev/null
+++ b/browser/components/asrouter/docs/spotlight.png
Binary files differ
diff --git a/browser/components/asrouter/docs/targeting-attributes.md b/browser/components/asrouter/docs/targeting-attributes.md
new file mode 100644
index 0000000000..89c5a6b6c6
--- /dev/null
+++ b/browser/components/asrouter/docs/targeting-attributes.md
@@ -0,0 +1,1033 @@
+# Targeting attributes
+
+When you create ASRouter messages such as contextual feature recommendations or onboarding cards, you may choose to include **targeting information** with those messages.
+
+Targeting information must be captured in [an expression](./targeting-guide.md) that has access to the following attributes. You may combine and compare any of these attributes as needed.
+
+Please note that some targeting attributes require stricter controls on the telemetry than can be collected, so when in doubt, ask for review.
+
+## Available attributes
+
+* [activeNotifications](#activenotifications)
+* [addonsInfo](#addonsinfo)
+* [addressesSaved](#addressessaved)
+* [archBits](#archbits)
+* [attachedFxAOAuthClients](#attachedfxaoauthclients)
+* [attributionData](#attributiondata)
+* [backgroundTaskName](#backgroundtaskname)
+* [blockedCountByType](#blockedcountbytype)
+* [browserSettings](#browsersettings)
+* [creditCardsSaved](#creditcardssaved)
+* [currentDate](#currentdate)
+* [defaultPDFHandler](#defaultpdfhandler)
+* [devToolsOpenedCount](#devtoolsopenedcount)
+* [distributionId](#distributionId)
+* [doesAppNeedPin](#doesappneedpin)
+* [doesAppNeedPrivatePin](#doesappneedprivatepin)
+* [firefoxVersion](#firefoxversion)
+* [fxViewButtonAreaType](#fxviewbuttonareatype)
+* [hasAccessedFxAPanel](#hasaccessedfxapanel)
+* [hasActiveEnterprisePolicies](#hasactiveenterprisepolicies)
+* [hasMigratedBookmarks](#hasmigratedbookmarks)
+* [hasMigratedCSVPasswords](#hasmigratedcsvpasswords)
+* [hasMigratedHistory](#hasmigratedhistory)
+* [hasMigratedPasswords](#hasmigratedpasswords)
+* [hasPinnedTabs](#haspinnedtabs)
+* [homePageSettings](#homepagesettings)
+* [inMr2022Holdback](#inmr2022holdback)
+* [isBackgroundTaskMode](#isbackgroundtaskmode)
+* [isChinaRepack](#ischinarepack)
+* [isDefaultBrowser](#isdefaultbrowser)
+* [isDefaultHandler](#isdefaulthandler)
+* [isDeviceMigration](#isdevicemigration)
+* [isFxAEnabled](#isfxaenabled)
+* [isFxASignedIn](#isFxASignedIn)
+* [isMajorUpgrade](#ismajorupgrade)
+* [isRTAMO](#isrtamo)
+* [isWhatsNewPanelEnabled](#iswhatsnewpanelenabled)
+* [launchOnLoginEnabled](#launchonloginenabled)
+* [locale](#locale)
+* [localeLanguageCode](#localelanguagecode)
+* [memoryMB](#memorymb)
+* [messageImpressions](#messageimpressions)
+* [needsUpdate](#needsupdate)
+* [newtabSettings](#newtabsettings)
+* [pinnedSites](#pinnedsites)
+* [platformName](#platformname)
+* [previousSessionEnd](#previoussessionend)
+* [primaryResolution](#primaryresolution)
+* [profileAgeCreated](#profileagecreated)
+* [profileAgeReset](#profileagereset)
+* [profileRestartCount](#profilerestartcount)
+* [providerCohorts](#providercohorts)
+* [recentBookmarks](#recentbookmarks)
+* [region](#region)
+* [screenImpressions](#screenImpressions)
+* [searchEngines](#searchengines)
+* [sync](#sync)
+* [topFrecentSites](#topfrecentsites)
+* [totalBlockedCount](#totalblockedcount)
+* [totalBookmarksCount](#totalbookmarkscount)
+* [userId](#userid)
+* [userMonthlyActivity](#usermonthlyactivity)
+* [userPrefersReducedMotion](#userprefersreducedmotion)
+* [useEmbeddedMigrationWizard](#useembeddedmigrationwizard)
+* [userPrefs](#userprefs)
+* [usesFirefoxSync](#usesfirefoxsync)
+* [xpinstallEnabled](#xpinstallEnabled)
+
+## Detailed usage
+
+### `addonsInfo`
+Provides information about the add-ons the user has installed.
+
+Note that the `name`, `userDisabled`, and `installDate` is only available if `isFullData` is `true` (this is usually not the case right at start-up).
+
+**Due to an existing bug, `userDisabled` is not currently available**
+
+#### Examples
+* Has the user installed the unicorn addon?
+```java
+addonsInfo.addons["unicornaddon@mozilla.org"]
+```
+
+* Has the user installed and disabled the unicorn addon?
+```java
+addonsInfo.isFullData && addonsInfo.addons["unicornaddon@mozilla.org"].userDisabled
+```
+
+#### Definition
+```ts
+declare const addonsInfo: Promise<AddonsInfoResponse>;
+interface AddonsInfoResponse {
+ // Does this include extra information requiring I/O?
+ isFullData: boolean;
+ // addonId should be something like activity-stream@mozilla.org
+ [addonId: string]: {
+ // Version of the add-on
+ version: string;
+ // (string) e.g. "extension"
+ type: AddonType;
+ // Version of the add-on
+ isSystem: boolean;
+ // Is the add-on a webextension?
+ isWebExtension: boolean;
+ // The name of the add-on
+ name: string;
+ // Is the add-on disabled?
+ // CURRENTLY UNAVAILABLE due to an outstanding bug
+ userDisabled: boolean;
+ // When was it installed? e.g. "2018-03-10T03:41:06.000Z"
+ installDate: string;
+ };
+}
+```
+### `attributionData`
+
+An object containing information on exactly how Firefox was downloaded
+
+#### Examples
+* Was the browser installed via the `"back_to_school"` campaign?
+```java
+attributionData && attributionData.campaign == "back_to_school"
+```
+
+#### Definition
+```ts
+declare const attributionData: AttributionCode;
+interface AttributionCode {
+ // Descriptor for where the download started from
+ campaign: string,
+ // A source, like addons.mozilla.org, or google.com
+ source: string,
+ // The medium for the download, like if this was referral
+ medium: string,
+ // Additional content, like an addonID for instance
+ content: string
+}
+```
+
+### `browserSettings`
+
+* `update`, which has information about Firefox update channel
+
+#### Examples
+
+* Is updating enabled?
+```java
+browserSettings.update.enabled
+```
+
+* Is beta channel?
+```js
+browserSettings.update.channel == 'beta'
+```
+
+#### Definition
+
+```ts
+declare const browserSettings: {
+ attribution: undefined | {
+ // Referring partner domain, when install happens via a known partner
+ // e.g. google.com
+ source: string;
+ // category of the source, such as "organic" for a search engine
+ // e.g. organic
+ medium: string;
+ // identifier of the particular campaign that led to the download of the product
+ // e.g. back_to_school
+ campaign: string;
+ // identifier to indicate the particular link within a campaign
+ // e.g. https://mozilla.org/some-page
+ content: string;
+ },
+ update: {
+ // Is auto-downloading enabled?
+ autoDownload: boolean;
+ // What release channel, e.g. "nightly"
+ channel: string;
+ // Is updating enabled?
+ enabled: boolean;
+ }
+}
+```
+
+### `currentDate`
+
+The current date at the moment message targeting is checked.
+
+#### Examples
+* Is the current date after Oct 3, 2018?
+```java
+currentDate > "Wed Oct 03 2018 00:00:00"|date
+```
+
+#### Definition
+
+```ts
+declare const currentDate; ECMA262DateString;
+// ECMA262DateString = Date.toString()
+type ECMA262DateString = string;
+```
+
+### `devToolsOpenedCount`
+Number of usages of the web console.
+
+#### Examples
+* Has the user opened the web console more than 10 times?
+```java
+devToolsOpenedCount > 10
+```
+
+#### Definition
+```ts
+declare const devToolsOpenedCount: number;
+```
+
+### `isDefaultBrowser`
+
+Is Firefox the user's default browser?
+
+#### Definition
+
+```ts
+declare const isDefaultBrowser: boolean;
+```
+
+### `isDefaultHandler`
+
+Is Firefox the user's default handler for various file extensions?
+
+Windows-only.
+
+#### Definition
+
+```ts
+declare const isDefaultHandler: {
+ pdf: boolean;
+ html: boolean;
+};
+```
+
+#### Examples
+* Is Firefox the default PDF handler?
+```ts
+isDefaultHandler.pdf
+```
+
+### `defaultPDFHandler`
+
+Information about the user's default PDF handler
+
+Windows-only.
+
+#### Definition
+
+```ts
+declare const defaultPDFHandler: {
+ // Does the user have a default PDF handler registered?
+ registered: boolean;
+
+ // Is the default PDF handler a known browser?
+ knownBrowser: boolean;
+};
+```
+
+### `firefoxVersion`
+
+The major Firefox version of the browser
+
+#### Examples
+* Is the version of the browser greater than 63?
+```java
+firefoxVersion > 63
+```
+
+#### Definition
+
+```ts
+declare const firefoxVersion: number;
+```
+
+### `launchOnLoginEnabled`
+
+Is the launch on login option enabled?
+
+```ts
+declare const launchOnLoginEnabled: boolean;
+```
+
+### `locale`
+The current locale of the browser including country code, e.g. `en-US`.
+
+#### Examples
+* Is the locale of the browser either English (US) or German (Germany)?
+```java
+locale in ["en-US", "de-DE"]
+```
+
+#### Definition
+```ts
+declare const locale: string;
+```
+
+### `localeLanguageCode`
+The current locale of the browser NOT including country code, e.g. `en`.
+This is useful for matching all countries of a particular language.
+
+#### Examples
+* Is the locale of the browser any English locale?
+```java
+localeLanguageCode == "en"
+```
+
+#### Definition
+```ts
+declare const localeLanguageCode: string;
+```
+
+### `needsUpdate`
+
+Does the client have the latest available version installed
+
+```ts
+declare const needsUpdate: boolean;
+```
+
+### `pinnedSites`
+The sites (including search shortcuts) that are pinned on a user's new tab page.
+
+#### Examples
+* Has the user pinned any site on `foo.com`?
+```java
+"foo.com" in pinnedSites|mapToProperty("host")
+```
+
+* Does the user have a pinned `duckduckgo.com` search shortcut?
+```java
+"duckduckgo.com" in pinnedSites[.searchTopSite == true]|mapToProperty("host")
+```
+
+#### Definition
+```ts
+interface PinnedSite {
+ // e.g. https://foo.mozilla.com/foo/bar
+ url: string;
+ // e.g. foo.mozilla.com
+ host: string;
+ // is the pin a search shortcut?
+ searchTopSite: boolean;
+}
+declare const pinnedSites: Array<PinnedSite>
+```
+
+### `previousSessionEnd`
+
+Timestamp of the previously closed session.
+
+#### Definition
+```ts
+declare const previousSessionEnd: UnixEpochNumber;
+// UnixEpochNumber is UNIX Epoch timestamp, e.g. 1522843725924
+type UnixEpochNumber = number;
+```
+
+### `primaryResolution`
+
+An object containing the available width and available height of the primary monitor in pixel values. The values take into account the existence of docks and task bars.
+
+#### Definition
+
+```ts
+interface primaryResolution {
+ width: number;
+ height: number;
+}
+```
+
+### `profileAgeCreated`
+
+The date the profile was created as a UNIX Epoch timestamp.
+
+#### Definition
+
+```ts
+declare const profileAgeCreated: UnixEpochNumber;
+// UnixEpochNumber is UNIX Epoch timestamp, e.g. 1522843725924
+type UnixEpochNumber = number;
+```
+
+### `profileAgeReset`
+
+The date the profile was reset as a UNIX Epoch timestamp (if it was reset).
+
+#### Examples
+* Was the profile never reset?
+```java
+!profileAgeReset
+```
+
+#### Definition
+```ts
+// profileAgeReset can be undefined if the profile was never reset
+// UnixEpochNumber is number, e.g. 1522843725924
+declare const profileAgeReset: undefined | UnixEpochNumber;
+// UnixEpochNumber is UNIX Epoch timestamp, e.g. 1522843725924
+type UnixEpochNumber = number;
+```
+
+### `providerCohorts`
+
+Information about cohort settings (from prefs, including shield studies) for each provider.
+
+#### Examples
+* Is the user in the "foo_test" cohort for cfr?
+```java
+providerCohorts.cfr == "foo_test"
+```
+
+#### Definition
+
+```ts
+declare const providerCohorts: {
+ [providerId: string]: string;
+}
+```
+
+### `region`
+
+Country code retrieved from `location.services.mozilla.com`. Can be `""` if request did not finish or encountered an error.
+
+#### Examples
+* Is the user in Canada?
+```java
+region == "CA"
+```
+
+#### Definition
+
+```ts
+declare const region: string;
+```
+
+### `searchEngines`
+
+Information about the current and available search engines.
+
+#### Examples
+* Is the current default search engine set to google?
+```java
+searchEngines.current == "google"
+```
+
+#### Definition
+
+```ts
+declare const searchEngines: Promise<SearchEnginesResponse>;
+interface SearchEnginesResponse: {
+ current: SearchEngineId;
+ installed: Array<SearchEngineId>;
+}
+// This is an identifier for a search engine such as "google" or "amazondotcom"
+type SearchEngineId = string;
+```
+
+### `sync`
+
+Information about synced devices.
+
+#### Examples
+* Is at least 1 mobile device synced to this profile?
+```java
+sync.mobileDevices > 0
+```
+
+#### Definition
+
+```ts
+declare const sync: {
+ desktopDevices: number;
+ mobileDevices: number;
+ totalDevices: number;
+}
+```
+
+### `topFrecentSites`
+
+Information about the browser's top 25 frecent sites.
+
+**Please note this is a restricted targeting property that influences what telemetry is allowed to be collected may not be used without review**
+
+
+#### Examples
+* Is mozilla.com in the user's top frecent sites with a frececy greater than 400?
+```java
+"mozilla.com" in topFrecentSites[.frecency >= 400]|mapToProperty("host")
+```
+
+#### Definition
+```ts
+declare const topFrecentSites: Promise<Array<TopSite>>
+interface TopSite {
+ // e.g. https://foo.mozilla.com/foo/bar
+ url: string;
+ // e.g. foo.mozilla.com
+ host: string;
+ frecency: number;
+ lastVisitDate: UnixEpochNumber;
+}
+// UnixEpochNumber is UNIX Epoch timestamp, e.g. 1522843725924
+type UnixEpochNumber = number;
+```
+
+### `totalBookmarksCount`
+
+Total number of bookmarks.
+
+#### Definition
+
+```ts
+declare const totalBookmarksCount: number;
+```
+
+### `usesFirefoxSync`
+
+Does the user use Firefox sync?
+
+#### Definition
+
+```ts
+declare const usesFirefoxSync: boolean;
+```
+
+### `isFxAEnabled`
+
+Does the user have Firefox sync enabled? The service could potentially be turned off [for enterprise builds](https://searchfox.org/mozilla-central/rev/b59a99943de4dd314bae4e44ab43ce7687ccbbec/browser/components/enterprisepolicies/Policies.jsm#327).
+
+#### Definition
+
+```ts
+declare const isFxAEnabled: boolean;
+```
+
+### `isFxASignedIn`
+
+Is the user signed in to a Firefox Account?
+
+#### Definition
+
+```ts
+declare const isFxASignedIn: Promise<boolean>
+```
+
+### `creditCardsSaved`
+
+The number of credit cards the user has saved for Forms and Autofill.
+
+#### Examples
+```java
+creditCardsSaved > 1
+```
+
+#### Definition
+
+```ts
+declare const creditCardsSaved: Promise<number>
+```
+
+### `addressesSaved`
+
+The number of addresses the user has saved for Forms and Autofill.
+
+#### Examples
+```java
+addressesSaved > 1
+```
+
+#### Definition
+
+```ts
+declare const addressesSaved: Promise<number>
+```
+
+### `archBits`
+
+The number of bits used to represent a pointer in this build.
+
+#### Definition
+
+```ts
+declare const archBits: number;
+```
+
+### `xpinstallEnabled`
+
+Pref used by system administrators to disallow add-ons from installed altogether.
+
+#### Definition
+
+```ts
+declare const xpinstallEnabled: boolean;
+```
+
+### `hasPinnedTabs`
+
+Does the user have any pinned tabs in any windows.
+
+#### Definition
+
+```ts
+declare const hasPinnedTabs: boolean;
+```
+
+### `hasAccessedFxAPanel`
+
+Boolean pref that gets set the first time the user opens the FxA toolbar panel
+
+#### Definition
+
+```ts
+declare const hasAccessedFxAPanel: boolean;
+```
+
+### `isWhatsNewPanelEnabled`
+
+Boolean pref that controls if the What's New panel feature is enabled
+
+#### Definition
+
+```ts
+declare const isWhatsNewPanelEnabled: boolean;
+```
+
+### `totalBlockedCount`
+
+Total number of events from the content blocking database
+
+#### Definition
+
+```ts
+declare const totalBlockedCount: number;
+```
+
+### `recentBookmarks`
+
+An array of GUIDs of recent bookmarks as provided by [`NewTabUtils.getRecentBookmarks`](https://searchfox.org/mozilla-central/rev/c5c002f81f08a73e04868e0c2bf0eb113f200b03/toolkit/modules/NewTabUtils.sys.mjs#1059)
+
+#### Definition
+
+```ts
+interface Bookmark {
+ bookmarkGuid: string;
+ url: string;
+ title: string;
+ ...
+}
+declare const recentBookmarks: Array<Bookmark>
+```
+
+### `userPrefs`
+
+Information about user facing prefs configurable from `about:preferences`.
+
+#### Examples
+```java
+userPrefs.cfrFeatures == false
+```
+
+#### Definition
+
+```ts
+declare const userPrefs: {
+ cfrFeatures: boolean;
+ cfrAddons: boolean;
+}
+```
+
+### `attachedFxAOAuthClients`
+
+Information about connected services associated with the FxA Account.
+Return an empty array if no account is found or an error occurs.
+
+#### Definition
+
+```
+interface OAuthClient {
+ // OAuth client_id of the service
+ // https://docs.telemetry.mozilla.org/datasets/fxa_metrics/attribution.html#service-attribution
+ id: string;
+ lastAccessedDaysAgo: number;
+}
+
+declare const attachedFxAOAuthClients: Promise<OAuthClient[]>
+```
+
+#### Examples
+```javascript
+{
+ id: "7377719276ad44ee",
+ name: "Pocket",
+ lastAccessTime: 1513599164000
+}
+```
+
+### `platformName`
+
+[Platform information](https://searchfox.org/mozilla-central/rev/c5c002f81f08a73e04868e0c2bf0eb113f200b03/toolkit/modules/AppConstants.sys.mjs#153).
+
+#### Definition
+
+```
+declare const platformName = "linux" | "win" | "macosx" | "android" | "other";
+```
+
+### `memoryMB`
+
+The amount of RAM available to Firefox, in megabytes.
+
+#### Definition
+
+```ts
+declare const memoryMB = number;
+```
+
+### `messageImpressions`
+
+Dictionary that maps message ids to impression timestamps. Timestamps are stored in
+consecutive order. Can be used to detect first impression of a message, number of
+impressions. Can be used in targeting to show a message if another message has been
+seen.
+Impressions are used for frequency capping so we only store them if the message has
+`frequency` configured.
+Impressions for badges might not work as expected: we add a badge for every opened
+window so the number of impressions stored might be higher than expected. Additionally
+not all badges have `frequency` cap so `messageImpressions` might not be defined.
+Badge impressions should not be used for targeting.
+
+#### Definition
+
+```
+declare const messageImpressions: { [key: string]: Array<UnixEpochNumber> };
+```
+
+### `blockedCountByType`
+
+Returns a breakdown by category of all blocked resources in the past 42 days.
+
+#### Definition
+
+```
+declare const messageImpressions: { [key: string]: number };
+```
+
+#### Examples
+
+```javascript
+Object {
+ trackerCount: 0,
+ cookieCount: 34,
+ cryptominerCount: 0,
+ fingerprinterCount: 3,
+ socialCount: 2
+}
+```
+
+### `isChinaRepack`
+
+Does the user use [the partner repack distributed by Mozilla Online](https://github.com/mozilla-partners/mozillaonline),
+a wholly owned subsidiary of the Mozilla Corporation that operates in China.
+
+#### Definition
+
+```ts
+declare const isChinaRepack: boolean;
+```
+
+### `userId`
+
+A unique user id generated by Normandy (note that this is not clientId).
+
+#### Definition
+
+```ts
+declare const userId: string;
+```
+
+### `profileRestartCount`
+
+A session counter that shows how many times the browser was started.
+More info about the details in [the telemetry docs](https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/concepts/sessions.html).
+
+#### Definition
+
+```ts
+declare const profileRestartCount: number;
+```
+
+### `homePageSettings`
+
+An object reflecting the current settings of the browser home page (about:home)
+
+#### Definition
+
+```ts
+declare const homePageSettings: {
+ isDefault: boolean;
+ isLocked: boolean;
+ isWebExt: boolean;
+ isCustomUrl: boolean;
+ urls: Array<URL>;
+}
+
+interface URL {
+ url: string;
+ host: string;
+}
+```
+
+#### Examples
+
+* Default about:home
+```javascript
+Object {
+ isDefault: true,
+ isLocked: false,
+ isCustomUrl: false,
+ isWebExt: false,
+ urls: [
+ { url: "about:home", host: "" }
+ ],
+}
+```
+
+* Default about:home with locked preference
+```javascript
+Object {
+ isDefault: true,
+ isLocked: true,
+ isCustomUrl: false,
+ isWebExt: false,
+ urls: [
+ { url: "about:home", host: "" }
+ ],
+}
+```
+
+* Custom URL
+```javascript
+Object {
+ isDefault: false,
+ isLocked: false,
+ isCustomUrl: true,
+ isWebExt: false,
+ urls: [
+ { url: "https://www.google.com", host: "google.com" }
+ ],
+}
+```
+
+* Custom URLs
+```javascript
+Object {
+ isDefault: false,
+ isLocked: false,
+ isCustomUrl: true,
+ isWebExt: false,
+ urls: [
+ { url: "https://www.google.com", host: "google.com" },
+ { url: "https://www.youtube.com", host: "youtube.com" }
+ ],
+}
+```
+
+* Web extension
+```javascript
+Object {
+ isDefault: false,
+ isLocked: false,
+ isCustomUrl: false,
+ isWebExt: true,
+ urls: [
+ { url: "moz-extension://123dsa43213acklncd/home.html", host: "" }
+ ],
+}
+```
+
+### `newtabSettings`
+
+An object reflecting the current settings of the browser newtab page (about:newtab)
+
+#### Definition
+
+```ts
+declare const newtabSettings: {
+ isDefault: boolean;
+ isWebExt: boolean;
+ isCustomUrl: boolean;
+ url: string;
+ host: string;
+}
+```
+
+#### Examples
+
+* Default about:newtab
+```javascript
+Object {
+ isDefault: true,
+ isCustomUrl: false,
+ isWebExt: false,
+ url: "about:newtab",
+ host: "",
+}
+```
+
+* Custom URL
+```javascript
+Object {
+ isDefault: false,
+ isCustomUrl: true,
+ isWebExt: false,
+ url: "https://www.google.com",
+ host: "google.com",
+}
+```
+
+* Web extension
+```javascript
+Object {
+ isDefault: false,
+ isCustomUrl: false,
+ isWebExt: true,
+ url: "moz-extension://123dsa43213acklncd/home.html",
+ host: "",
+}
+```
+
+### `activeNotifications`
+
+True when an infobar style message is displayed or when the awesomebar is
+expanded to show a message (for example onboarding tips).
+
+### `isMajorUpgrade`
+
+A boolean. `true` if the browser just updated to a new major version.
+
+### `hasActiveEnterprisePolicies`
+
+A boolean. `true` if any Enterprise Policies are active.
+
+### `userMonthlyActivity`
+
+Returns an array of entries in the form `[int, unixTimestamp]` for each day of
+user activity where the first entry is the total urls visited for that day.
+
+### `doesAppNeedPin`
+
+Checks if Firefox app can be and isn't pinned to OS taskbar/dock.
+
+### `doesAppNeedPrivatePin`
+
+Checks if Firefox Private Browsing Mode can be and isn't pinned to OS taskbar/dock. Currently this only works on certain Windows versions.
+
+### `isBackgroundTaskMode`
+
+Checks if this invocation is running in background task mode.
+
+### `backgroundTaskName`
+
+A non-empty string task name if this invocation is running in background task
+mode, or `null` if this invocation is not running in background task mode.
+
+### `userPrefersReducedMotion`
+
+Checks if user prefers reduced motion as indicated by the value of a media query for `prefers-reduced-motion`.
+
+### `inMr2022Holdback`
+
+A boolean. `true` when the user is in the Major Release 2022 holdback study.
+
+### `distributionId`
+
+A string containing the id of the distribution, or the empty string if there
+is no distribution associated with the build.
+
+### `fxViewButtonAreaType`
+
+A string of the name of the container where the Firefox View button is shown, null if the button has been removed.
+
+### `hasMigratedBookmarks`
+
+A boolean. `true` if the user ever used the Migration Wizard to migrate bookmarks since Firefox 113 released. Available in Firefox 113+; will not be true if the user had only ever migrated bookmarks prior to Firefox 113 being released.
+
+### `hasMigratedCSVPasswords`
+
+A boolean. `true` if CSV passwords have been imported via the migration wizard since Firefox 116 released. Available in Firefox 116+; ; will not be true if the user had only ever migrated CSV passwords prior to Firefox 116 being released.
+
+### `hasMigratedHistory`
+
+A boolean. `true` if the user ever used the Migration Wizard to migrate history since Firefox 113 released. Available in Firefox 113+; will not be true if the user had only ever migrated history prior to Firefox 113 being released.
+
+### `hasMigratedPasswords`
+
+A boolean. `true` if the user ever used the Migration Wizard to migrate passwords since Firefox 113 released. Available in Firefox 113+; will not be true if the user had only ever migrated passwords prior to Firefox 113 being released.
+
+### `useEmbeddedMigrationWizard`
+
+A boolean. `true` if the user is configured to use the embedded Migration Wizard in about:welcome.
+
+### `isRTAMO`
+
+A boolean. `true` when [RTAMO](first-run.md#return-to-amo-rtamo) has been used to download Firefox, `false` otherwise.
+
+### `isDeviceMigration`
+
+A boolean. `true` when [support.mozilla.org](https://support.mozilla.org) has been used to download the browser as part of a "migration" campaign, for device migration guidance, `false` otherwise.
+### `screenImpressions`
+
+An array that maps about:welcome screen IDs to their most recent impression timestamp. Should only be used for unique screen IDs to avoid unintentionally targeting messages with identical screen IDs.
+#### Definition
+
+```
+declare const screenImpressions: { [key: string]: Array<UnixEpochNumber> };
+```
diff --git a/browser/components/asrouter/docs/targeting-guide.md b/browser/components/asrouter/docs/targeting-guide.md
new file mode 100644
index 0000000000..3172cece81
--- /dev/null
+++ b/browser/components/asrouter/docs/targeting-guide.md
@@ -0,0 +1,37 @@
+# Guide to targeting with JEXL
+
+For a more in-depth explanation of JEXL syntax you can read the [Normady project docs](https://mozilla.github.io/normandy/user/filters.html?highlight=jexl).
+
+## How to write JEXL targeting expressions
+A message needs to contain the `targeting` property (JEXL string) which is evaluated against the provided attributes.
+Examples:
+
+```javascript
+{
+ "id": "7864",
+ "content": {...},
+ // simple equality check
+ "targeting": "usesFirefoxSync == true"
+}
+
+{
+ "id": "7865",
+ "content": {...},
+ // using JEXL transforms and combining two attributes
+ "targeting": "usesFirefoxSync == true && profileAgeCreated > '2018-01-07'|date"
+}
+
+{
+ "id": "7866",
+ "content": {...},
+ // targeting addon information
+ "targeting": "addonsInfo.addons['activity-stream@mozilla.org'].name == 'Activity Stream'"
+}
+
+{
+ "id": "7866",
+ "content": {...},
+ // targeting based on time
+ "targeting": "currentDate > '2018-08-08'|date"
+}
+```
diff --git a/browser/components/asrouter/docs/telemetry.md b/browser/components/asrouter/docs/telemetry.md
new file mode 100644
index 0000000000..4484a3eaf4
--- /dev/null
+++ b/browser/components/asrouter/docs/telemetry.md
@@ -0,0 +1,90 @@
+# Messaging System & Onboarding Telemetry
+
+This document (combined with the [messaging system ping section of the Glean Dictionary](https://dictionary.telemetry.mozilla.org/apps/firefox_desktop/pings/messaging-system)), is now the place to look first for Messaging System and Onboarding telemetry information. For historical reasons, there is still some related documentation mixed in with the Activity Stream documentation. If you can't find what you need here, check [old metrics we collect](/browser/components/newtab/docs/v2-system-addon/data_events.md) and the
+[old data dictionary](/browser/components/newtab/docs/v2-system-addon/data_dictionary.md).
+
+## Collection with Glean
+
+Code all over the messaging system passes JSON ping objects up to a few
+central spots. It may be [annotated with
+attribution](https://searchfox.org/mozilla-central/search?q=symbol:AboutWelcomeTelemetry%23_maybeAttachAttribution&redirect=false)
+along the way, and/or adjusted by some [policy
+routines](https://searchfox.org/mozilla-central/search?q=symbol:TelemetryFeed%23createASRouterEvent&redirect=false)
+before it's sent. The JSON will be transformed slightly further before being [sent to
+Glean][submit-glean-for-glean].
+
+## Design of Messaging System Data Collections
+
+Data is sent in the
+[Messaging System Ping](https://dictionary.telemetry.mozilla.org/apps/firefox_desktop/pings/messaging-system).
+Which Messaging System Ping you get is recorded with
+[Ping Type](https://dictionary.telemetry.mozilla.org/apps/firefox_desktop/metrics/messaging_system_ping_type).
+If you wish to expand the collection of data,
+consider whether data belongs on the `messaging-system` ping
+(usually when data is timely to the ping itself)
+or if it's a more general collection,
+in which case the data can go on the default `send_in_pings` entry,
+which is the `metrics` ping.
+In either case, you can add a metric definition in the
+[metrics.yaml][metrics-yaml]
+file.
+
+## Adding or changing telemetry
+
+A general process overview can be found in the
+[Activity Stream telemetry document](/browser/components/newtab/docs/v2-system-addon/telemetry.md).
+
+Note that when you need to add new metrics (i.e. JSON keys),
+they MUST to be
+[added](https://mozilla.github.io/glean/book/user/metrics/adding-new-metrics.html) to
+[browser/components/newtab/metrics.yaml][metrics-yaml]
+in order to show up correctly in the Glean data.
+
+Avoid adding any new nested objects, because Glean can't handle these. In the best case, any such additions will end up being flattened or stringified before being sent.
+
+## Monitoring FxMS Telemetry Health
+
+The OMC team owns an [OpMon](https://github.com/mozilla/opmon) dashboard for the FxMS Desktop Glean telemetry with
+alerts. Note that it can only show one channel at any given time, here's a link
+to [Windows
+Release](https://mozilla.cloud.looker.com/dashboards/operational_monitoring::firefox_messaging_system?Percentile=50&Normalized+Channel=release&Normalized+Os=Windows).
+The dashboard is specified in
+[firefox-messaging-system.toml](https://github.com/mozilla/metric-hub/blob/main/opmon/firefox-messaging-system.toml),
+and reading the source can help clarify exactly what it means. We are the owner
+of this file, and are encouraged to adjust it to our needs, though it's probably
+a good idea to get review from someone in Data Science.
+
+The current plan is to review the OpMon dashboard as a group in our weekly
+triage meeting, note anything that seems unusual to our [Google docs
+log](https://docs.google.com/document/d/1d16GCuul9sENMOMDAcD1kKNBtnJLouDxZtIgz2u-70U/edit),
+and, if we want to investigate further, file [a bug that blocks
+`fxms-glean`](https://bugzilla.mozilla.org/showdependencytree.cgi?id=1843409&hide_resolved=1).
+
+The dashboard is configured to alert in various cases, and those alerts can be
+seen at the bottom of the dashboard. As of this writing, the alerts have some
+noise [to be cleaned up](https://bugzilla.mozilla.org/show_bug.cgi?id=1843406)
+before we can automatically act on them.
+
+## Appendix: A Short Glean Primer, as it applies to this project (courtesy of Chris H-C)
+
+* [Glean](https://mozilla.github.io/glean/book/) is a data collection library by
+ Mozilla for Mozilla. You define metrics like counts and timings and things,
+ and package those into pings which are the payloads sent to our servers.
+* You can see current [FxMS Glean metrics and pings](https://dictionary.telemetry.mozilla.org/apps/firefox_desktop/pings/messaging-system)
+ in the desktop section of the Glean Dictionary. The layer embedding Glean into
+ Firefox Desktop is called [Firefox on Glean (FOG)](https://firefox-source-docs.mozilla.org/toolkit/components/glean/index.html).
+* Documentation will be automatically generated and hosted on the Glean
+ Dictionary, so write long rich-text Descriptions and augment them off-train
+ with Glean Annotations.
+* Schemas for ingestion are automatically generated. You can go from landing a
+ new ping to querying the data being sent [within two
+ days](https://blog.mozilla.org/data/2021/12/14/this-week-in-glean-how-long-must-i-wait-before-i-can-see-my-data/).
+* Make a mistake? No worries. Changes are quick and easy and are reflected in
+ the received data within a day.
+* Local debugging involves using Glean's ergonomic test APIs and/or the Glean
+ Debug Ping Viewer which you can learn more about on `about:glean`.
+* If you have any questions, the Glean Team is available across a lot of
+ timezones on the [`#glean:mozilla.org` channel](https://chat.mozilla.org/#/room/#glean:mozilla.org) on Matrix and Slack `#data-help`.
+
+ [submit-glean-for-glean]: https://searchfox.org/mozilla-central/search?q=.submitGleanPingForPing&path=*.jsm&case=false&regexp=false
+ [metrics-yaml]: https://searchfox.org/mozilla-central/source/browser/components/newtab/metrics.yaml