I. Notification Permission Telemetry
My first Firefox patch: adding Glean telemetry to track how users interact with notification permission prompts.
Bug 1998053 | D274203 | Reviewer: timhuang
The Problem
Firefox had limited visibility into how users interact with notification permission requests. We knew when permissions were granted or denied, but not:
- How often the permission icon appears vs. the full prompt
- Whether users click the icon or get the prompt automatically
- What percentage of requests are auto-blocked due to lack of user gesture
- How behavior differs across site categories (social media vs. productivity apps)
The Architecture
Firefoxโs notification permission system has several layers:
1. DOM Layer (dom/notification/)
- Handles
Notification.requestPermission()API calls - Validates security context (HTTPS required)
- Checks for user gesture activation
2. Permission UI Layer (browser/modules/PermissionUI.sys.mjs)
DesktopNotificationPermissionPromptclass- Manages the permission dialog lifecycle
- Handles the โpost-promptโ (shaking icon) flow
- This is where I added the new telemetry
3. Popup Notification System (browser/modules/PopupNotifications.jsm)
- Generic notification panel infrastructure
- Provides callbacks:
onShown,onAfterShow, event callbacks
What I Built
Five Glean Event Metrics
web_notification_permission:
icon_shown:
description: Permission icon appears and animates in URL bar
icon_clicked:
description: User clicks the permission icon
prompt_shown:
description: Permission dialog displayed (script vs icon_click)
prompt_blocked:
description: Permission request auto-denied (no user gesture)
prompt_interaction:
description: User allows/blocks permission (with persistence)Site Categorization System
Added a hardcoded map of 86 high-traffic domains across 8 categories:
const SITE_CATEGORIES = new Map([
["facebook.com", "social"],
["slack.com", "chat_communication"],
["mail.google.com", "email"],
["youtube.com", "media_streaming"],
// ... 86 total domains
]);
function getSiteCategory(principal) {
let host = principal.URI.host;
if (SITE_CATEGORIES.has(host)) {
return SITE_CATEGORIES.get(host);
}
// Check subdomain match
for (let [domain, category] of SITE_CATEGORIES) {
if (host.endsWith("." + domain)) {
return category;
}
}
return "other";
}The Tricky Parts
Detecting Icon Click vs. Automatic Prompt
The challenge was distinguishing:
- Automatic: User clicked a button โ site calls
requestPermission()โ prompt appears immediately - Icon click: Site calls
requestPermission()without gesture โ icon appears โ user clicks icon โ prompt appears
Solution: check both the preference and the requestโs hasValidTransientUserGestureActivation:
let trigger = "automatic";
if (
this.requiresUserInput &&
!this.request.hasValidTransientUserGestureActivation
) {
trigger = "icon_click";
}Finding the Right Callback Point
The telemetry had to go in the base PermissionPrompt classโs prompt() method, which wraps all actionsโnot in DesktopNotificationPermissionPrompt directly.
What I Learned
- Firefoxโs Permission System is Layered โ DOM validates, UI presents, permission manager stores
- Glean Telemetry is Code, Not Configuration โ Metrics are defined in YAML but recorded in code
- User Gestures Matter โ
hasValidTransientUserGestureActivationdetermines immediate vs. deferred prompts - The Permission Prompt is a State Machine โ Not just โshown โ allow/blockโ but a full lifecycle