100%

ETP Infrastructure: A Build-Time Pipeline for Firefox Privacy Configuration: Index

From Firefox Privacy Engineering at Mozilla
ETP Infrastructure: A Build-Time Pipeline for Firefox Privacy Configuration
Page metadata
First created May 26, 2026
Last edited May 26, 2026

Firefox’s Enhanced Tracking Protection has two modes — Standard (default) and Strict (opt-in) — and behaves differently across normal and private browsing contexts. The features turned on in each mode are encoded across three source files: firefox.js holds a comma-separated string of feature codes (tp,tpPrivate,cookieBehavior5,btp,fpp,lna, and so on), StaticPrefList.yaml defines the Standard-mode defaults, and all.js holds additional values. To answer the question “is Bounce Tracking Protection enabled in Strict mode, normal browsing?” — for roughly fifteen features across two contexts — you had to trace through all three files yourself, decode the feature-code conventions, and resolve the overrides by hand.

Before this work, that document did not exist. The privacy team needed it for internal alignment and external-facing documentation, but maintaining it by hand was impractical: prefs change every release cycle, and a stale matrix is worse than no matrix at all.

I built a build-time pipeline that solves this problem from two directions. The desktop side is a Sphinx extension that parses the pref files statically and resolves the capability matrix at documentation build time. The Android side is a runtime extraction pipeline that reads resolved prefs out of running Fenix nightly builds, because Android’s category-based configuration cannot be parsed from source alone. The two outputs combine into a single cross-platform document published to Firefox Source Docs.

The desktop pipeline

Main article: Sphinx ETP Extension.

Bug 2011450. 982 lines of Python that parses firefox.js, StaticPrefList.yaml, and all.js, resolves the Standard and Strict mode pref values for each ETP feature, handles the encoding conventions for boolean and integer prefs (cookieBehavior5 means “set network.cookie.cookieBehavior to 5”; btp is a boolean), and outputs the capability matrix as a markdown table rendered into Firefox Source Docs at build time. The extension hooks into the existing Sphinx pipeline for firefox-source-docs.mozilla.org, so the matrix updates automatically on every documentation build, and the team never has to edit the matrix by hand again.

The extension landed in February 2026 with reviewer manuel. The deployment value is high relative to the line count: it converts an unmaintainable manual document into a build artifact that stays accurate by construction.

The Android extension

Main article: Android ETP Pipeline.

Fenix (Firefox on Android, built on GeckoView) takes a fundamentally different approach to privacy configuration. Instead of toggling individual Gecko prefs, it uses a category-based system defined in EngineSession.kt: coarse buckets like AD, ANALYTIC, SOCIAL, CRYPTOMINING, FINGERPRINTING, CONTENT, FULL. When the user selects Standard or Strict mode, GeckoView applies the relevant categories through ContentBlocking.Settings, which then maps down to underlying Gecko prefs in a way that is not visible from source. The category-to-pref mapping is not one-to-one and is not documented anywhere in the codebase.

The only reliable way to know what prefs Android sets is to run it and read the values back. Bug 2020402 is the runtime extraction system that does this: launch a Fenix nightly build under instrumentation, navigate through both modes and both browsing contexts, read out the resolved Gecko prefs, and emit them in the same schema the Sphinx extension uses for desktop. The two outputs are then combined into a single matrix that compares both platforms side by side. Reviewer: manuel.

Followups

Three smaller patches caught edge cases the original extension missed.

Pref Comment Cleanup

Main article: Pref Comment Cleanup.

Bug 2020396. The Sphinx extension parses firefox.js with regex. Some prefs had inline comments after their value (pref("network.cookie.cookieBehavior", 5 /* BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN */);) which were being captured as part of the value. Rather than complicating the regex, the simpler fix was to move the comments above the pref declaration. The interesting decision was choosing to fix the data rather than the parser. Reviewer: manuel.

Private Browsing Cells

Main article: Private Browsing Cells.

Bug 2020394. The generated matrix had blank cells for private-browsing values when the feature inherited from normal mode. Readers were interpreting empty as “disabled in private browsing,” which was the opposite of the truth. Fix: show the normal-mode value with an “Inherits from Normal” annotation. Small label change, real ambiguity removed. Reviewer: manuel.

Strict Mode Fix

Main article: Strict Mode Fix.

Bug 2020404. Bounce Tracking Protection breaks the integer-suffix convention used by most ETP feature codes — its code is just btp with no numeric suffix even though its pref is an integer. The generic resolver was falling through to default values. Fix: a named case in _resolve_strict_value for btp specifically.

What this pattern is good for

The pipeline is a small instance of a useful pattern: when documentation drift is inevitable and the source of truth is itself code, generate the documentation from the code at build time. The same approach would work for any system where configuration is scattered across files and modes — feature flags resolved across environments, permission matrices resolved across roles, capability tables resolved across product surfaces. The cost is a one-time engineering investment; the benefit is that the document cannot go stale without the build breaking.

Index