Technical README: The <permission> Element (PEPC)

This document provides a detailed technical overview of the <permission> element feature, also known as PEPC (Permission Element Policy Control). It is intended for developers who want to understand the implementation of this feature in Chromium.

1. Overview

The <permission> element is an HTML element that allows websites to embed a permission request UI directly into their content. The goal is to make permission requests more contextual, user-initiated, and trustworthy, leading to a better user experience and higher permission grant rates.

The core principle of the feature is a two-step permission request process:

  1. The user clicks the <permission> element on the page.
  2. The browser displays a secondary, browser-controlled UI (a bubble prompt on desktop, a dialog on Android) to confirm the permission request.

This two-step process is crucial for security, as it prevents websites from tricking users into granting permissions with a single click.

2. Architectural Overview

The following diagram illustrates the high-level architecture of the <permission> element feature:

+-------------------------------------------------------------------------------------------------+
| Renderer Process (Blink)                                                                        |
|                                                                                                 |
|  +-------------------------+                                                                    |
|  | HTMLPermissionElement   |                                                                    |
|  +-------------------------+                                                                    |
|              |                                                                                  |
|              | 1. RegisterPageEmbeddedPermissionControl                                         |
|              | 3. RequestPageEmbeddedPermission                                                 |
|              v                                                                                  |
|  +-------------------------+                                                                    |
|  | PermissionService       |                                                                    |
|  +-------------------------+                                                                    |
|                                                                                                 |
+-------------------------------------------------------------------------------------------------+
               |                                                                                  |
               | Mojo IPC                                                                         |
               v                                                                                  |
+-------------------------------------------------------------------------------------------------+
| Browser Process                                                                                 |
|                                                                                                 |
|  +-----------------------+      +--------------------------+      +-------------------------+   |
|  | PermissionServiceImpl |----->| PermissionControllerImpl |----->| PermissionPromptFactory |   |
|  +-----------------------+      +--------------------------+      +-------------------------+   |
|              |                                                            |                     |
|              | 2. OnEmbeddedPermissionControlRegistered                   | 4. Create           |
|              v                                                            v                     |
|  +---------------------------------+                             +--------------------------+   |
|  | EmbeddedPermissionControlClient |                             | EmbeddedPermissionPrompt |   |
|  +---------------------------------+                             +--------------------------+   |
|                                                                                 |               |
|                                                                5. Create & Show |               |
|                                                                                 v               |
|                                                            +----------------------------------+ |
|                                                            | EmbeddedPermissionPromptBaseView | |
|                                                            +----------------------------------+ |
|                                                                                                 |
+-------------------------------------------------------------------------------------------------+

3. Component Deep Dive

The implementation of the <permission> element spans across the renderer (Blink), the browser process, and the UI.

3.1. HTMLPermissionElement: The Renderer Component

The renderer-side implementation is responsible for parsing the <permission> element, handling its attributes, and managing its state.

third_party/blink/renderer/core/html/html_permission_element.h / .cc

  • HTMLPermissionElement class: This is the C++ implementation of the <permission> element. It inherits from HTMLElement and handles all renderer-side logic for the element.
  • Attributes: It handles the type attribute, which specifies the permission to be requested (e.g., “camera”, “geolocation”).
  • Communication: It communicates with the browser process via the PermissionService Mojo interface.

The HTMLPermissionElement has several complex areas in its implementation, primarily due to the need for robust security and state management.

3.1.1. Clickjacking Mitigation

The most complex part of the HTMLPermissionElement is its defense against clickjacking. This is achieved through a combination of an IntersectionObserver and geometry checks.

  • IntersectionObserver: The element uses an IntersectionObserver to monitor its visibility and occlusion, which is initialized in HTMLPermissionElement::AttachLayoutTree. The observer is configured to track whether the element is at least 90% visible and has been for at least 100ms. The callback for the observer is HTMLPermissionElement::OnIntersectionChanged.
  • Geometry Checks: The element also tracks its own geometry (size and position). The HTMLPermissionElement::DidRecalcStyle and HTMLPermissionElement::DidFinishLifecycleUpdate methods check if the element's intersection with the viewport has changed. If it has, a timer is started by calling DisableClickingTemporarily, and clicks are ignored until the timer has finished.
  • Occlusion Detection: The IntersectionObserver is configured with expose_occluder_id = true in its parameters. This allows the element to know which element is covering it via the IntersectionObserverEntry in the OnIntersectionChanged callback.

3.1.2. State Management

The HTMLPermissionElement has a complex state machine that tracks the permission status, the element‘s validity, and the user’s interaction with the element.

  • Permission Status: The element's appearance and behavior change based on the current permission status (granted, denied, or prompt). This status is cached in the renderer process (propagated from browser process early when the page completed navigation) and updated by the browser process via the OnPermissionStatusChange method, which is part of the CachedPermissionStatus::Client interface implemented by HTMLPermissionElement.
  • Element Validity: The element can be in an invalid state for several reasons. The isValid() method returns the element's validity, which is determined by the GetClickingEnabledState() method. This method checks for things like being in a secure context, having a valid type attribute, and having valid CSS.
  • User Interaction: The element tracks user interaction to prevent abuse. For example, in HTMLPermissionElement::DefaultEventHandler, it checks the pending_request_created_ timestamp to see if a request is already pending.

3.1.3. Shadow DOM and Internal Structure

The <permission> element is not a simple element. It's composed of a shadow DOM that contains an icon and a text span, which are created in the HTMLPermissionElement::DidAddUserAgentShadowRoot method.

  • Shadow DOM: The use of a shadow DOM encapsulates the element‘s internal structure and styling, preventing it from being manipulated by the website’s CSS.
  • Icon: The icon is implemented as a separate custom element, HTMLPermissionIconElement, which is added to the shadow DOM. This allows for the icon to have its own dedicated logic and styling.
  • Internal Styling: The element has its own internal stylesheet that defines the appearance of the icon and text. This stylesheet is carefully constructed to be resistant to tampering.

3.1.4. Mojo Communication and Lifecycle

The HTMLPermissionElement has a complex lifecycle that is tied to its communication with the browser process.

  • Registration: When the element is rendered on the page, HTMLPermissionElement::InsertedInto is called, which in turn calls MaybeRegisterPageEmbeddedPermissionControl. This method is responsible for making the RegisterPageEmbeddedPermissionControl Mojo call to the browser process.
  • Connection Errors: The permission_service_ mojo remote has a disconnect handler set in GetPermissionService() to call OnPermissionServiceConnectionFailed, which resets the service connection.
  • Garbage Collection: The element's lifecycle is managed by the Blink garbage collector. The HTMLPermissionElement::RemovedFrom method handles cleanup, including unregistering the element from the browser process by calling EnsureUnregisterPageEmbeddedPermissionControl.

3.1.5. CSS Validation

To prevent websites from styling the <permission> element in a deceptive way, the element validates its own CSS.

  • Restricted Properties: Only a limited set of CSS properties can be applied to the element. This is enforced by HTMLPermissionElement::GetCascadeFilter(), which filters out properties that are not marked as kValidForPermissionElement.
  • Validation Logic: The HTMLPermissionElement::DidRecalcStyle method calls IsStyleValid() to check the values of the allowed CSS properties. If an invalid value is detected, the element is disabled by calling DisableClickingIndefinitely(DisableReason::kInvalidStyle).

3.1.6. Fallback Mode

The HTMLPermissionElement includes a graceful degradation mechanism known as “fallback mode.”

  • Trigger: This mode is activated if the element's type attribute is invalid or requests a permission that is not supported. This is checked in HTMLPermissionElement::AttributeChanged, and if the type is invalid, EnableFallbackMode() is called.
  • Behavior: When in fallback mode, the element essentially reverts to behaving like a generic HTMLUnknownElement. The EnableFallbackMode() method achieves this by adding an <slot> element to the user agent shadow root, which allows the element's children to render, and removing the internal permission container.

3.2. Mojo (Communication Layer)

The Mojo interface defines the contract for communication between the renderer and the browser process.

third_party/blink/public/mojom/permissions/permission.mojom

  • PermissionService interface: Implemented in the browser process by PermissionServiceImpl, this interface provides methods for the renderer to interact with the permission system. The key methods for the <permission> element are:
    • RegisterPageEmbeddedPermissionControl: The renderer calls this to inform the browser about a new <permission> element.
    • RequestPageEmbeddedPermission: The renderer calls this when the user clicks the <permission> element.
  • EmbeddedPermissionControlClient interface: Implemented in the renderer process by HTMLPermissionElement, this interface allows the browser to send messages back to the permission element. The key method is:
    • OnEmbeddedPermissionControlRegistered: Called by the browser to inform the renderer of the result of the registration process.

3.3. Browser Process

The browser-side implementation is responsible for handling the permission logic, displaying the UI, and managing the user's decisions.

3.3.1. Instance-per-Page Logic

A key security and anti-abuse feature of PEPC is that it limits the number of <permission> elements that can be active on a single page at any given time. This logic is managed by the EmbeddedPermissionControlChecker class.

content/browser/permissions/embedded_permission_control_checker.h / .cc

  • EmbeddedPermissionControlChecker class: This class is attached to a Page object (making it “per page”). It's responsible for tracking and enforcing the instance limit for <permission> elements.
  • client_map_ Data Structure: The core of the checker is the client_map_, a std::map that associates a set of permission types with a queue of Client objects. Each Client object represents a single <permission> element on the page.
  • kMaxPEPCPerPage Limit: The checker enforces a hard limit of 3 active <permission> elements per permission type on a page. This is defined by the kMaxPEPCPerPage constant.
  • Queuing Behavior: When a new <permission> element is registered, CheckPageEmbeddedPermission is called. If the number of active elements for that permission type is less than the limit, the new element is approved. Otherwise, it's added to the queue but not approved. When an active element is removed (e.g., the user navigates away or the element is removed from the DOM), its corresponding Client is removed from the queue, and the next element in the queue is approved. This creates a queuing behavior that ensures that only a limited number of elements are active at any given time.

content/browser/permissions/permission_service_impl.h / .cc

  • PermissionServiceImpl class: This class is the browser-side implementation of the PermissionService Mojo interface.
  • Request Dispatching: It acts as a dispatcher, receiving RegisterPageEmbeddedPermissionControl and RequestPageEmbeddedPermission calls from the renderer and forwarding them to the PermissionControllerImpl.
  • Validation: In the RegisterPageEmbeddedPermissionControl method, it uses EmbeddedPermissionControlChecker to perform security checks on the element.
  • Context Management: It holds a PermissionServiceContext member, which provides information about the renderer frame and the browser context.

content/browser/permissions/permission_controller_impl.h / .cc

  • PermissionControllerImpl class: This is the central class for permission management in the browser process. It handles permission requests by creating PermissionRequest objects, queries permission statuses, and stores the user's decisions.

3.4. UI Components

The UI components are responsible for displaying the secondary permission prompt to the user. The logic for determining which UI screen to show is shared between platforms, while the view implementation is platform-specific.

3.4.1. EmbeddedPermissionPromptFlowModel: Shared UI Logic

The core logic for the embedded permission prompt's multi-screen flow is managed by the EmbeddedPermissionPromptFlowModel. This class is not a UI view itself, but a shared model used by both desktop and Android to decide which screen (or “variant”) of the prompt to display.

components/permissions/embedded_permission_prompt_flow_model.h / .cc

  • State Management: The model inspects the current state of the permission (e.g., ContentSetting, OS-level status, enterprise policies) to determine the appropriate UI.
  • Screen Variants: It defines an enum, Variant, which represents all possible screens the prompt can show. This includes states like kAsk (the main prompt), kPreviouslyDenied (a prompt variant for previously denied permissions), kOsPrompt (informing the user that an OS prompt is active), and kAdministratorDenied (informing the user that the permission is blocked by policy).
  • Platform Agnostic: Both the desktop and Android UI controllers create an instance of this model and use its DeterminePromptVariant method to decide which view to present to the user. This keeps the complex flow logic consistent across platforms.

3.4.2. Desktop (Views)

chrome/browser/ui/views/permissions/permission_prompt_factory.cc

  • CreatePermissionPrompt function: This factory function is responsible for creating the correct type of permission prompt.
  • Prompt Selection: It checks if the permission request was initiated by a <permission> element by calling permissions::PermissionUtil::ShouldCurrentRequestUsePermissionElementSecondaryUI. If it was, it creates an EmbeddedPermissionPrompt.

chrome/browser/ui/views/permissions/embedded_permission_prompt.h / .cc

  • EmbeddedPermissionPrompt class: This is the high-level controller for the embedded permission prompt. It's not a view itself, but it manages the lifecycle of the prompt view.
  • Flow Management: The EmbeddedPermissionPromptFlowModel is used to manage the different views that can be shown in the prompt. This includes the main prompt view, a view that informs the user that the permission is blocked, and a view that informs the user that the permission has been granted. This state management adds a layer of complexity to the prompt's implementation.
  • Delegate: It acts as a delegate for the prompt view, handling user actions like “Allow” and “Dismiss”, which in turn call Accept() and Dismiss() on the PermissionRequest delegate.

chrome/browser/ui/views/permissions/embedded_permission_prompt_base_view.h / .cc

  • EmbeddedPermissionPromptBaseView class: This is the abstract base class for the actual UI of the embedded permission prompt. It's a views::BubbleDialogDelegateView that provides the common structure for the prompt.
  • Dynamic UI: The EmbeddedPermissionPromptBaseView is a highly dynamic view. The text and buttons that are displayed can change based on the state of the permission request. This is handled by the GetRequestLinesConfiguration() and GetButtonsConfiguration() methods, which are implemented by subclasses.

3.4.2. Android

On Android, the permission prompt is implemented as a modal dialog. The differentiation between a regular prompt and a PEPC prompt is handled by a boolean flag that is passed from the C++ side to the Java side.

components/permissions/android/permission_prompt/permission_prompt_android.cc

  • PermissionPromptAndroid class: This is the C++ part of the Android permission prompt. It acts as a bridge to the Java UI.
  • PEPC Detection: In its constructor, it calls permissions::PermissionUtil::ShouldCurrentRequestUsePermissionElementSecondaryUI() to determine if the current permission request is for a PEPC prompt.
  • JNI Bridge: It passes the result of the PEPC check as a boolean (useRequestElement) to the Java PermissionDialogController when it's created via a JNI call.

components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogController.java

  • PermissionDialogController class: This is the main controller for the permission prompt on Android.
  • PEPC Flag: It receives the useRequestElement boolean in its constructor. This flag is then used to customize the dialog for a PEPC prompt (e.g., by changing the text or the layout).
  • Lifecycle Management: The PermissionDialogController has to carefully manage the lifecycle of the PermissionDialog. It needs to handle cases where the dialog is dismissed by the user, the system, or by a screen rotation.
  • JNI Bridge: The controller communicates with the C++ backend through a JNI bridge (mNativePermissionDialogController). This involves passing data between the Java and C++ worlds, which can be complex and error-prone.

components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogDelegate.java

  • PermissionDialogDelegate class: This class acts as a bridge between the PermissionRequest (from the C++ side) and the Java UI. It provides the PermissionDialogController with the necessary data to display the prompt (e.g., getMessageText(), getPrimaryButtonText()) and forwards user decisions back to the PermissionRequest (e.g., onAccept(), onDismiss()).

The view for the permission prompt is defined in the layout files permission_dialog_vertical_buttons_permission.xml and permission_dialog.xml, and is inflated by the PermissionDialogCoordinator.

4. Code-Level Flow

This section describes the step-by-step code flow for a typical permission request initiated by a <permission> element.

  1. Element Creation (Renderer):

    • When the HTML parser encounters a <permission> tag, it creates an HTMLPermissionElement instance.
    • When the element is rendered on the page, its MaybeRegisterPageEmbeddedPermissionControl method is called.
    • This method gets the PermissionService Mojo remote and calls RegisterPageEmbeddedPermissionControl, passing the requested permissions and a pending remote for its EmbeddedPermissionControlClient implementation.
  2. Registration (Browser):

    • The PermissionServiceImpl receives the RegisterPageEmbeddedPermissionControl call.
    • It uses EmbeddedPermissionControlChecker to verify that the element is allowed in the current context.
    • It then calls OnEmbeddedPermissionControlRegistered on the EmbeddedPermissionControlClient remote to send the result back to the renderer.
  3. User Interaction (Renderer):

    • The user clicks the <permission> element.
    • The HTMLPermissionElement's DefaultEventHandler calls RequestPageEmbeddedPermissions.
    • This method calls RequestPageEmbeddedPermission on the PermissionService Mojo remote, passing the permission descriptors and the element's position.
  4. Prompt Creation (Browser):

    • The PermissionServiceImpl receives the RequestPageEmbeddedPermission call.
    • It forwards the request to the PermissionControllerImpl.
    • The PermissionControllerImpl creates a PermissionRequest and shows it via the PermissionRequestManager.
    • The PermissionRequestManager creates a PermissionPromptAndroid instance.
    • Inside the PermissionPromptAndroid constructor, permissions::PermissionUtil::ShouldCurrentRequestUsePermissionElementSecondaryUI() is called.
    • The PermissionPromptAndroid then creates a PermissionDialogController on the Java side, passing the boolean result of the check.
  5. Prompt Display (Browser):

    • Desktop: The EmbeddedPermissionPrompt (the controller) creates a concrete subclass of EmbeddedPermissionPromptBaseView (the view). The view is shown as a bubble anchored to the position of the <permission> element.
    • Android: The PermissionDialogDelegate holds the information about whether this is a PEPC prompt. The PermissionDialogController passes this delegate to the PermissionDialogCoordinator, which then inflates and customizes the appropriate view, for example by using a different layout.
  6. User Decision (Browser):

    • The user clicks a button on the prompt (e.g., “Allow”).
    • Desktop: The EmbeddedPermissionPromptBaseView calls a method on its delegate, the EmbeddedPermissionPrompt. The EmbeddedPermissionPrompt calls the appropriate method on its delegate_ (the PermissionRequest), such as Accept() or Deny().
    • Android: User actions on the dialog view are handled by the PermissionDialogMediator, which notifies the PermissionDialogController. The controller then calls the appropriate method on the PermissionDialogDelegate.
  7. Decision Handling (Browser and Renderer):

    • The PermissionRequest notifies the PermissionControllerImpl of the user's decision.
    • The PermissionControllerImpl stores the decision.
    • The result of the RequestPageEmbeddedPermission Mojo call is sent back to the renderer, and the HTMLPermissionElement's OnEmbeddedPermissionsDecided method is called with the result.

5.2. Bypassing the Quiet UI

The most significant difference is that PEPC requests bypass the “quiet” permission UI. The quiet UI is a less intrusive prompt that is shown when the browser determines that a regular permission prompt would be too disruptive.

5. Behavioral Differences: PEPC vs. Regular Requests

PEPC permission requests are treated differently from regular permission requests in a few key ways, primarily because they are considered a stronger signal of user intent.

5.1. Bypassing Permission Status Check

A key difference is that PEPC prompts can be shown even if the permission has been previously denied by the user. Regular permission prompts are only shown if the permission status is “ask”.

  • Logic: Both regular and PEPC permission requests flow through the same initial path, eventually reaching PermissionContextBase::RequestPermission for the specific permission type. Inside this method, the following sequence occurs:

    1. GetPermissionStatus is called to retrieve the current status of the permission (e.g., GRANTED, DENIED, or ASK). This function also returns the source of the status (e.g., user decision, embargo, kill switch).
    2. The result is passed to PermissionUtil::CanPermissionRequestIgnoreStatus. This is the critical function for the bypass behavior.
    3. CanPermissionRequestIgnoreStatus checks if the request was initiated by a permission element (via the embedded_permission_element_initiated flag in PermissionRequestData).
    4. If it is a PEPC request, the function checks the source of the permission status. It returns true if the denial is from a “soft” source that a direct user gesture should be able to override (like a previous user dismissal or ignore). It returns false for “hard” denials (like a kill switch or enterprise policy).
    5. Back in PermissionContextBase::RequestPermission, there is a check: if (!status_ignorable && ...)
      • For a regular request, CanPermissionRequestIgnoreStatus returns false. If the permission is already denied, the condition is met, and the request is immediately rejected without showing a prompt.
      • For a PEPC request that was previously denied by the user, CanPermissionRequestIgnoreStatus returns true. This makes the !status_ignorable part of the condition false, so the entire block is skipped.
    6. Because the rejection block is skipped, the code proceeds to DecidePermission, which continues the process of showing a prompt to the user.
  • Rationale: This allows users to easily change their minds about a permission that they have previously denied, without having to go into site settings. The explicit user gesture on the <permission> element is considered a strong enough signal to warrant re-prompting, unless the permission is blocked by a system-level or administrative policy.

5.2. Bypassing the Quiet UI

The most significant difference is that PEPC requests bypass the “quiet” permission UI. The quiet UI is a less intrusive prompt that is shown when the browser determines that a regular permission prompt would be too disruptive.

  • Logic: The decision to bypass the quiet UI is made in PermissionManager::RequestPermissions. This method checks if the request is a PEPC request by calling permissions::PermissionUtil::ShouldCurrentRequestUsePermissionElementSecondaryUI. If it is, the quiet UI is skipped and the full permission prompt is shown.
  • Rationale: Because a PEPC request is initiated by a direct user interaction with the <permission> element, it's assumed that the user is expecting a prompt and is ready to make a decision. Therefore, the less intrusive quiet UI is not necessary.

5.3. UI Customization

As mentioned in the previous sections, the UI for a PEPC prompt is different from a regular permission prompt.

  • Desktop: On desktop, a PEPC prompt is an EmbeddedPermissionPrompt, which is a bubble that is anchored to the <permission> element. A regular permission prompt is a bubble that is anchored to the omnibox.
  • Android: On Android, the PermissionDialogController receives a useRequestElement boolean that tells it to customize the dialog for a PEPC request. This can include changing the text to be more contextual to the user's action, or using a different layout.

5.4. Request Preemption

PEPC requests have a higher priority than regular permission requests. If a regular permission prompt is already showing and a PEPC request is triggered, the regular prompt will be cancelled and the PEPC prompt will be shown immediately.

  • Logic: This logic is implemented in the PermissionRequestQueue::AddRequest. When a new request is added to the queue, it checks if the new request is a PEPC request and if the currently showing request is not a PEPC request. If both are true, the currently showing request is cancelled.
  • Rationale: This ensures that PEPC requests, which are the result of a direct and explicit user action, are not blocked by less urgent, programmatically triggered permission requests.

6. Metrics

The PEPC feature is instrumented with a number of metrics to monitor its usage and performance. These metrics are recorded in UMA and UKM.

6.1. Renderer Metrics

These metrics are recorded in the renderer process and are related to the <permission> element itself.

  • Blink.PermissionElement.UserInteractionAccepted: A boolean histogram that records whether a user interaction (click) on the <permission> element was accepted or not. A click might be rejected for security reasons, for example if the element is obscured or has a deceptive style.

  • Blink.PermissionElement.UserInteractionDeniedReason: An enumeration histogram that records the reason why a user interaction was denied. The possible values are:

    • kInvalidType: The type attribute of the element is invalid.
    • kFailedOrHasNotBeenRegistered: The element has not been successfully registered with the browser process.
    • kRecentlyAttachedToLayoutTree: The element was recently attached to the layout tree.
    • kIntersectionWithViewportChanged: The element's intersection with the viewport has recently changed.
    • kIntersectionVisibilityOutOfViewPortOrClipped: The element is outside the viewport or clipped.
    • kIntersectionVisibilityOccludedOrDistorted: The element is occluded by another element or has a distorted visual effect.
    • kInvalidStyle: The element has a deceptive style.
    • kUntrustedEvent: The click event was not triggered by a real user.
  • Blink.PermissionElement.InvalidStyleReason: An enumeration histogram that records the reason why the element's style was considered invalid.

6.2. Browser Metrics

These metrics are recorded in the browser process and are related to the PEPC prompt.

  • Permissions.EmbeddedPermissionPrompt.Flow.Variant: An enumeration histogram that records which variant of the PEPC prompt was shown to the user. The possible values are:

    • kUninitialized
    • kAdministratorGranted
    • kPreviouslyGranted
    • kOsSystemSettings
    • kOsPrompt
    • kAsk
    • kPreviouslyDenied
    • kAdministratorDenied
  • Permissions.Prompt.{PermissionType}.ElementAnchoredBubble.{OsScreen}.OsScreenAction: An enumeration histogram that records the user's action on the OS-related screens of the PEPC prompt.

    • {PermissionType} can be Camera, Microphone, or Geolocation.
    • {OsScreen} can be OsPrompt or OsSystemSettings.
    • OsScreenAction can be:
      • kSystemSettings
      • kDismissedXButton
      • kDismissedScrim
      • kOsPromptDenied
      • kOsPromptAllowed
  • Permissions.Prompt.{PermissionType}.ElementAnchoredBubble.{OsScreen}.{OsScreenAction}.TimeToAction: A time histogram that records the time between showing an OS-related screen and the user taking an action on it.

6.3. UKM

UKM data is recorded for the PEPC feature to allow for more detailed analysis of user behavior. The ElementAnchoredPermissionPrompt event is recorded with the following metrics:

  • Action: The user's action on the prompt. The possible values are defined in the ElementAnchoredBubbleAction enum.
  • Variant: The variant of the prompt that was shown. The possible values are defined in the ElementAnchoredBubbleVariant enum.
  • ScreenCounter: The number of screens that were shown to the user during the permission request flow.