Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 3 additions & 11 deletions docs/platform-guides/desktop/feature-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -67,27 +67,17 @@ The Nimbus Feature API will return the correct configuration for a feature given

## Registering a new feature

To register a new feature, you will need to choose an identifier and add it to the manifest in [FeatureManifest.yaml](https://searchfox.org/mozilla-central/source/toolkit/components/nimbus/FeatureManifest.yaml):
After adding the feature a build step is required to update the appropriate header file.
To register a new feature, choose an identifier and add it to [FeatureManifest.yaml](https://searchfox.org/mozilla-central/source/toolkit/components/nimbus/FeatureManifest.yaml). After adding the feature, a build step is required to update the generated header file.

```yaml
# In FeatureManifest.yaml
# Our feature name
aboutwelcome:
description: The about:welcome page
owner: user@mozilla.com
hasExposure: true
exposureDescription: >
Recorded when the about:welcome page is first shown to the user.
# Include this if you need synchronous access / very early access at startup
# or if you are registering this to use for platform experiments.
isEarlyStartup: true
# Set to true to allow a client to be enrolled in multiple experiments/rollouts
# for this feature simultaneously. See "Co-enrolling Features" docs.
# allowCoenrollment: false
variables:
# Additional (optional) values that we can control
# The name of these variables is up to you
enabled:
type: boolean
fallbackPref: browser.aboutwelcome.enabled
Expand All @@ -100,6 +90,8 @@ aboutwelcome:
pref("browser.aboutwelcome.enabled", true);
```

See the [Desktop Feature Manifest Reference](/platform-guides/desktop/feature-manifest) for the complete schema, including all feature and variable properties, `setPref` vs `fallbackPref`, enum constraints, and validation.

## Importing the Feature API

Import the `NimbusFeatures` module:
Expand Down
226 changes: 226 additions & 0 deletions docs/platform-guides/desktop/feature-manifest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
---
id: desktop-feature-manifest
title: Feature Manifest Reference
slug: /platform-guides/desktop/feature-manifest
---

# Desktop Feature Manifest Reference

The desktop Nimbus Feature Manifest ([`FeatureManifest.yaml`](https://searchfox.org/mozilla-central/source/toolkit/components/nimbus/FeatureManifest.yaml)) defines every feature that can be configured by experiments and rollouts in Firefox Desktop. Each feature entry declares what variables it exposes, how those variables connect to Firefox preferences, and what telemetry it records.

After adding or modifying a feature in the manifest, a build step is required to update the generated header file.

:::tip
This reference covers the **Desktop** manifest format (`FeatureManifest.yaml`). For mobile apps, see the [Feature Manifest Language (FML) specification](/technical-reference/fml/fml-spec).
:::

## Feature properties

Each top-level key in `FeatureManifest.yaml` is a feature ID. The feature definition supports these properties:

| Property | Required | Type | Default | Description |
| :--- | :---: | :--- | :--- | :--- |
| `description` | Yes | string | — | Human-readable description of the feature |
| `owner` | Yes | string | — | Email of the team or person responsible |
| `hasExposure` | Yes | boolean | — | Whether this feature records [exposure events](/data-analysis/jetstream/overview#enrollment-vs-exposure) |
| `exposureDescription` | If `hasExposure: true` | string | — | Describes when/how the exposure event fires |
| `variables` | Yes | object | — | Variable definitions (can be `{}` if the feature has no variables) |
| `isEarlyStartup` | No | boolean | `false` | Cache values in Firefox prefs for synchronous access during early startup |
| `allowCoenrollment` | No | boolean | `false` | Allow multiple simultaneous experiment/rollout enrollments for this feature |
| `applications` | No | string[] | `["firefox-desktop"]` | Which Firefox processes can enroll (see [Applications](#applications)) |
| `schema` | No | object | — | JSON Schema for validation (see [Schema validation](#schema-validation)) |

### Applications

The `applications` array specifies which Firefox processes can use this feature:

- `"firefox-desktop"` — the main browser process (default)
- `"firefox-desktop-background-task"` — the background task runner

```yaml
applications:
- firefox-desktop
- firefox-desktop-background-task
```

If omitted, defaults to `["firefox-desktop"]`.

### Schema validation

The optional `schema` property points to a JSON Schema file that validates the combined feature configuration. It has two fields:

- `uri` — a `resource://` URI that Firefox loads at runtime for client-side validation
- `path` — a filesystem path (relative to the repo root) where Experimenter can find the schema

```yaml
schema:
uri: resource://nimbus/schemas/PrefFlipsFeature.schema.json
path: toolkit/components/nimbus/schemas/PrefFlipsFeature.schema.json
```

## Variable properties

Each key under `variables` defines a configurable variable. Variables support these properties:

| Property | Required | Type | Description |
| :--- | :---: | :--- | :--- |
| `description` | Yes | string | Human-readable description of the variable |
| `type` | Yes | string | One of `boolean`, `string`, `int`, `json` |
| `fallbackPref` | No | string | Pref to read the default value from (mutually exclusive with `setPref`) |
| `setPref` | No | string or object | Pref that Nimbus actively sets on enrollment (mutually exclusive with `fallbackPref`) |
| `enum` | No | array | Constrains allowed values (`string` and `int` types only) |

### Variable types

| Type | Values | Supports `enum` | Notes |
| :--- | :--- | :---: | :--- |
| `boolean` | `true` / `false` | No | |
| `string` | Text values | Yes | |
| `int` | Whole numbers | Yes | |
| `json` | Arbitrary JSON objects/arrays | No | Stored as JSON strings in prefs |

### `fallbackPref` vs `setPref`

These are **mutually exclusive** — a variable can use one or the other, not both.

| | `fallbackPref` | `setPref` |
| :--- | :--- | :--- |
| **What it does** | Reads the current pref value as the default when no experiment is active | Nimbus actively **sets** the pref when the user enrolls |
| **On enrollment** | No change to the pref | Pref is set to the experiment branch value |
| **On unenrollment** | No change to the pref | Original pref value is restored |
| **If user changes pref** | No effect on enrollment | Causes automatic unenrollment |
| **Use case** | Feature gates and defaults that already exist as browser prefs | Controlling prefs that other code reads directly |

**`fallbackPref` example:**
```yaml
enabled:
type: boolean
fallbackPref: browser.aboutwelcome.enabled
description: Whether the about:welcome page is enabled
```

**`setPref` example:**
```yaml
enabled:
type: boolean
setPref:
branch: default # or "user"
pref: browser.search.visualSearch.featureGate
description: Feature gate for visual search
```

The `setPref` object format has two fields:
- `branch` — which pref branch to set: `"default"` (resets each startup) or `"user"` (persists to disk)
- `pref` — the pref name

:::note
For a deep dive into pref experiment behavior including unenrollment scenarios, pref branch trade-offs, and conflict handling, see [Pref Experiments](/platform-guides/desktop/pref-experiments).
:::

### `enum` constraints

The `enum` property restricts a `string` or `int` variable to a fixed set of values:

```yaml
rankingMode:
type: string
enum:
- default
- interest
- random
description: The ranking algorithm to use
```

`enum` is not supported for `boolean` or `json` types.

## Examples

### Simple feature with a feature gate

```yaml
search:
description: Search service related features
owner: search-and-suggest-program@mozilla.com
hasExposure: true
exposureDescription: >
Recorded when the visual search context menu item is shown.
variables:
visualSearchEnabled:
type: boolean
setPref:
branch: default
pref: browser.search.visualSearch.featureGate
description: Feature gate for visual search
```

### Feature with multiple variable types

```yaml
urlbar:
description: The Address Bar
owner: search-and-suggest-program@mozilla.com
hasExposure: true
exposureDescription: >
Recorded once per session on first urlbar interaction.
variables:
onboardingTimesToShow:
type: int
fallbackPref: browser.urlbar.quickactions.timesToShowOnboardingLabel
description: Number of times to show the onboarding label
quickSuggestRankingMode:
type: string
fallbackPref: browser.urlbar.quicksuggest.rankingMode
enum:
- default
- interest
- random
description: The ranking mode for QuickSuggest
scoreMap:
type: json
description: JSON object mapping result types to scores
```

### Early startup feature

```yaml
aboutwelcome:
description: The about:welcome page
owner: omc-core@mozilla.com
hasExposure: true
exposureDescription: >
Recorded once per session when about:welcome is shown.
isEarlyStartup: true
variables:
enabled:
type: boolean
fallbackPref: browser.aboutwelcome.enabled
description: Whether the about:welcome page is enabled
screens:
type: json
fallbackPref: browser.aboutwelcome.screens
description: Content to show in the onboarding flow
```

### Co-enrolling feature

```yaml
prefFlips:
description: Flip arbitrary prefs for incident response
owner: beth@mozilla.com
hasExposure: false
allowCoenrollment: true
variables:
prefs:
type: json
description: The prefs to set
schema:
uri: resource://nimbus/schemas/PrefFlipsFeature.schema.json
path: toolkit/components/nimbus/schemas/PrefFlipsFeature.schema.json
```

## Further reading

- [Feature API Reference](/platform-guides/desktop/feature-api) — how to access feature values in code
- [Pref Experiments](/platform-guides/desktop/pref-experiments) — deep dive into `setPref` and `fallbackPref` behavior
- [Co-enrolling Features](/technical-reference/fml/coenrolling-features) — how `allowCoenrollment` works
- [FeatureManifest.yaml on Searchfox](https://searchfox.org/mozilla-central/source/toolkit/components/nimbus/FeatureManifest.yaml) — the live manifest
49 changes: 25 additions & 24 deletions docs/technical-reference/feature-definition.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,35 @@ slug: /technical-reference/feature-definition
sidebar_position: 2
---

In the experimentation ecosystem, experiment surfaces are described as features. A feature is an area of code instrumented with telemetry and accessible for remote configuration. It can be as small as a single function or as complex as a whole page. Some examples:
In the Nimbus ecosystem, a **feature** is an area of code instrumented for experiments and remote configuration. It can be as small as a single function or as complex as a whole page. Some examples:

aboutwelcome: The about:welcome page in Desktop
homescreen: The homescreen page in Fenix
tabTrayFeature: The tab tray in Firefox iOS
- `aboutwelcome` — the about:welcome page in Desktop
- `homescreen` — the homescreen page in Fenix
- `tabTrayFeature` — the tab tray in Firefox iOS

Features are defined in a manifest file specific to your platform. The manifest declares what variables the feature exposes, how they connect to preferences, and what telemetry the feature records.

Features are defined in a Feature Manifest file for the application, and the client code uses the Nimbus SDK to access variables associated with those features.
## Define your feature

After landing a new feature in `mozilla-central` and before doing an Experiment or Rollout using it, it is recommended to go through QA to provide an extra layer of stability and possibly be informed of certain limitations that could exist with the feature. See **To test your feature** for information on how to involve QA.
Choose the guide for your platform:

## To define your feature in the feature manifest file
First, look at what is already defined in the manifest file:
* [Desktop](https://searchfox.org/mozilla-central/source/toolkit/components/nimbus/FeatureManifest.yaml)
* Mobile
* [Fenix (Firefox Android)](https://github.com/mozilla-mobile/firefox-android/blob/main/fenix/app/nimbus.fml.yaml)
* [Focus Android](https://github.com/mozilla-mobile/firefox-android/blob/main/focus-android/app/nimbus.fml.yaml)
* [Firefox iOS](https://github.com/mozilla-mobile/firefox-ios/blob/main/nimbus.fml.yaml)
* [Focus iOS](https://github.com/mozilla-mobile/focus-ios/blob/main/nimbus.fml.yaml)
- **Desktop** — add your feature to [`FeatureManifest.yaml`](https://searchfox.org/mozilla-central/source/toolkit/components/nimbus/FeatureManifest.yaml). See the [Desktop Feature Manifest Reference](/platform-guides/desktop/feature-manifest) for the complete schema.
- **Mobile (Android / iOS)** — add your feature to your app's `.fml.yaml` file. See the [Feature Manifest Language (FML) specification](/technical-reference/fml/fml-spec) for the complete schema.
- [Fenix (Firefox Android)](https://github.com/mozilla-mobile/firefox-android/blob/main/fenix/app/nimbus.fml.yaml)
- [Focus Android](https://github.com/mozilla-mobile/firefox-android/blob/main/focus-android/app/nimbus.fml.yaml)
- [Firefox iOS](https://github.com/mozilla-mobile/firefox-ios/blob/main/nimbus.fml.yaml)
- [Focus iOS](https://github.com/mozilla-mobile/focus-ios/blob/main/nimbus.fml.yaml)
- **Web (Cirrus)** — see the [Cirrus integration guide](/platform-guides/web/integration).

## To test your feature
Starting with 2023, the Ecosystem QA team has begun to test all the available Desktop Nimbus Features and their configurations. This is done in an attempt to ease testing on future experiments using a feature config (old or new) and to provide a baseline health report for it.
## QA testing your feature

For engineers looking to test a new config:
* See [this document](https://docs.google.com/document/d/1oz1YyaaBI-oHUDsktWA-dLtX7WzhYqs7C121yOPKo2w/edit) for steps on how to file a QA request. When logging the ticket, please use the `Feature-Configuration` label in JIRA to mark it as such. [Example](https://mozilla-hub.atlassian.net/browse/QA-1785)
* If you have documentation regarding the feature’s configuration capabilities, please link it to the QA ticket as this helps with Test Plan and Test Case creation.
* The most commonly QA asked questions for feature configs are:
* What specific functionality is enabled in the browser and how exactly could we see it in action?
* Are there any exposed user preferences in about:preferences when using the feature?
* If the feature has an `exposure` event, when does it trigger?
* Does the feature have specific telemetry events and which telemetry data pipeline are we using? Legacy or Glean?
After landing a new feature, it is recommended to go through QA before running experiments or rollouts. This provides an extra layer of stability and can surface limitations early.

- See [this document](https://docs.google.com/document/d/1oz1YyaaBI-oHUDsktWA-dLtX7WzhYqs7C121yOPKo2w/edit) for steps on how to file a QA request. Use the `Feature-Configuration` label in Jira. ([Example](https://mozilla-hub.atlassian.net/browse/QA-1785))
- If you have documentation about the feature's configuration, link it to the QA ticket — this helps with test plan and test case creation.

Common questions QA will ask:
- What specific functionality is enabled and how can we see it in action?
- Are there any exposed user preferences in about:preferences?
- If the feature has an exposure event, when does it trigger?
- Does the feature have specific telemetry events and which pipeline (Legacy or Glean)?
1 change: 1 addition & 0 deletions sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ module.exports = {
type: "category",
label: "Desktop",
items: [
"platform-guides/desktop/desktop-feature-manifest",
"platform-guides/desktop/desktop-feature-api",
"platform-guides/desktop/desktop-pref-experiments",
"platform-guides/desktop/onboarding-feature-desktop",
Expand Down