100%

Building Firefox's New-Tab Privacy Surface: Index

From Firefox Privacy Engineering at Mozilla
Building Firefox's New-Tab Privacy Surface
Page metadata
First created May 26, 2026
Last edited May 26, 2026
Three widget variants on the Firefox new-tab page
Three widget variants tested on the new-tab page during the Nova redesign.

Firefox’s Enhanced Tracking Protection blocks thousands of tracker requests per user per week. Until this work, none of it was visible: ETP ran silently in the background, the about:protections page existed as a shell with no real backend, and the new-tab page showed nothing about privacy at all. This project built the user-facing privacy surface from the bottom of the stack to the top — a service layer that aggregates blocking events, a UI component that consumes them, a database schema extension to support per-origin breakdowns, a redesign integrating the widget into Firefox’s Nova design system, and a live-flush fix that closes the gap between in-memory blocking events and the database the widget reads from.

The widget is also the deployment target for the Tracker Performance Cost Model. It reports counts today; once the cost model lands, the same surface will report bandwidth and time saved.

The architecture, top to bottom

The widget runs on a four-layer stack. Each patch in this section addresses one layer.

Source events. Firefox’s nsIContentBlocker fires events when ETP intercepts a request. Events are buffered in an in-memory ContentBlockingLog per browsing session, then flushed to disk into protections.sqlite (the anti-tracking database) on a periodic schedule. The database stores per-day aggregate counts by blocking category — script trackers, fingerprinters, cryptominers, tracking cookies, social trackers.

Service layer. TrackingDBService reads the database and exposes per-day counts. I added PrivacyMetricsService on top of it, which aggregates the last seven days, formats it for the front end, and handles edge cases (no data yet, single-day windows, ETP disabled). Documented in Privacy Metrics Service.

UI component. The <privacy-metrics> web component on about:protections and the new-tab page calls PrivacyMetricsService, renders a card-style breakdown by category, and handles the empty-state and error-state UX. Documented in Privacy Metrics Component.

Top-trackers extension. “147 trackers blocked” is a count. “googletagmanager.com — blocked 47 times” is per-origin attribution, which requires a schema change to record origin URLs at write time. Documented in Top Trackers Database.

What I shipped, patch by patch

Demo grid showing all widget variants on about:protections
Demo grid of all visual variants on about:protections, used for design review.

Privacy Metrics Service

Main article: Privacy Metrics Service.

Bug 2010368. The backend layer. Aggregates blocking events from TrackingDBService over a configurable lookback window, returns a structured payload keyed by category, exposes a JSON-RPC interface that the front-end component consumes. Handles the edge cases that production telemetry surfaces: zero-event days, partial first days when ETP is first enabled, time-zone normalization. Reviewer: emz.

Privacy Metrics Component

Main article: Privacy Metrics Component.

Bug 2010369. The front-end layer. Web component that fetches from PrivacyMetricsService, renders the category breakdown, and degrades gracefully when the service returns no data. Built with Fluent for localization, themed against the Firefox design tokens, accessible by keyboard and screen reader. Reviewers: emz, fluent-reviewers, desktop-theme-reviewers, flod, jules.

Top Trackers Database

Main article: Top Trackers Database.

Bug 2027450. The schema extension. The existing protections.sqlite stored aggregate counts per category per day, with the origin information discarded at write time. Adding “top trackers blocked this week” to the widget required recording origin URLs alongside counts, which meant a new table, a migration, and changes to the write path in nsIContentBlocker callbacks. Reviewer: timhuang.

Nova Redesign and New-Tab Integration

Main article: Nova Redesign and New-Tab Integration.

Integration of the widget into Firefox’s Nova design system. Three visual variants tested against the new-tab page (above), a demo grid on about:protections for design review (right), and the final variant landed across desktop and mobile.

Anti-Tracking Database Flush

Main article: Anti-Tracking Database Flush.

Bug 2030052. The fix that made the widget honest. The widget reads from protections.sqlite, but blocking events live in an in-memory ContentBlockingLog for some time before being flushed to disk. The first version of the widget showed yesterday’s data — the data the database knew about — instead of what just happened. This patch flushes the live logs before the top-K query runs, so when the user opens the new tab page, the widget reflects what ETP blocked in the current session. Reviewer: timhuang.

What it took beyond the code

The widget touches five different review groups: the privacy team (emz, timhuang for the service and database layers), the Fluent localization team, the desktop theme reviewers, the new-tab page owners, and the front-end performance reviewers. The five patches landed across four months because each one had to clear a different set of reviewers and meet conventions specific to its surface. The privacy_metrics_component patch alone had five reviewers across four teams.

The Mozilla code review culture rewards exactly this kind of cross-team patience. The widget exists because each layer landed cleanly with the team that owned it, rather than as a single mega-patch that would have stalled for months in cross-team disagreement.

What this leaves room for

The widget today reports counts. The infrastructure I built — particularly the PrivacyMetricsService aggregation layer and the per-origin schema in protections.sqlite — was designed to accept additional dimensions. The Tracker Performance Cost Model plugs into the same service layer to add bandwidth and time-saved estimates without any architectural change. The “top trackers” surface can extend to “trackers that wasted the most of your bandwidth this week” with the same backend.

Index