13 KiB
Executable File
title, date, status, tags, updated
| title | date | status | tags | updated | |||
|---|---|---|---|---|---|---|---|
| CPM Web Extension failures — what the data shows | 2026-10-08 | historical-analysis |
|
2026-10-20 |
CPM Web Extension failures: what the data shows
Current context — checked 20 October 2026. This analysis retains its October 5 production cut and October 8 conclusions; newer 12–14 October cohorts and truncation evidence have separate denominators in cpm-status-2026-10-15. They are not joined user transitions or causal shares.
The original phase-1 schema below has been superseded by one terminal
web_extension_cpm_episode, daily+count, on #73765d1cb4abd2; that PR is closed without merge. Actual fields, removals and observation limits: cpm-pr0-episode-telemetry-summary-2026-10-16. P1/P2/P4, Network, stable-origin P3 and shared-pinned P5 implementations have separate PRs; their gates are in the main status. P5 #7473 merged on 20 October intorelease/macos/1.213.0(9bcce0264e), with a default-ON remote failsafe; rollout and production effect remain unverified. Implementation and validation: cpm-status-2026-10-15#P5 — merged 20 октября 2026.Ready background + no native answer does not prove a lost init message. Page
initRespmay arrive while dashboard delivery fails, even in a detector-stuck episode. Neither timing fields norbg_eventsprovide end-to-end delivery proof. WebKit issue states and OS shipping statements below are the historical source audit, not freshly verified release information.
Historical context — recorded 15 October 2026
Current status — 2026-10-15: cpm-status-2026-10-15 (§3–5, §10–12). The October 8 data and denominators below are retained; use the main status for the October 12–14 cohort snapshot and the October 14 P5/P6 selection. These are different cuts, not interchangeable totals.
New causal evidence is narrower than a whole production cohort: shared-window closure reproduces P5/tab=false through production listener + system WebKit; a main-flag cycle through the real handler reproduces P6, but actual production flag changes remain unproven. This does not retract the earlier observation that the normal remote flag was stable. P5/tab=true, natural listener metadata loss and real iOS lifecycle are still unexplained.
Controlled long documents and host main-actor stalls did not match P5. Lost dashboard delivery can produce detector stuck even when the page receives initResp. The 14 current methods are green across separate local runs; this is mechanism/control evidence, not an estimate of prevalence or shipped-fix impact. The main status preserves 494 vs 499 P5 denominator differences, 627 + 235 P6 patterns, attribution limits and all red/negative results.
Context
Cookie Pop-up Management (CPM) runs in the iOS and macOS browsers as a built-in web extension. It has two parts:
- a content script inside each web page;
- a background service worker, the extension's shared "brain". WebKit starts it on demand and unloads it after about 30 seconds of inactivity.
On every page load, the content script asks the background worker for its state. The worker then reports to the app.
The app watches this exchange with a health monitor:
- If no report arrives within 4 seconds after a page finishes loading, the app sends an "initialization failed" pixel.
- If a later page load in the same episode also fails, the app sends a "messaging stuck" pixel and reloads the extension to recover.
- When answers resume, the app sends a "recovered" pixel.
- Failure pixels carry a snapshot of the extension's state: whether it is loaded, whether its background is alive, recent background lifecycle events, and WebKit errors.
Important: a failure pixel means "no answer within 4 seconds". It does not mean the extension is broken. A late answer also counts as a failure.
Key findings
- Recent wake is common among healthy-looking failures. A worker start longer than four seconds reproduces a timeout with an otherwise healthy app-side snapshot. This establishes a possible mechanism, not the cause or recovery outcome of each production report.
- About a third of iOS "stuck" reports in this historical cut carry WebKit error 6, "background failed to load". Source analysis and controlled macOS suspension show that WebKit's roughly 30-second timer can cancel an unfinished background load. The natural cause of every iOS error-6 report was not established.
- Network-process replacement is present in a minority (20–45%) of healthy-looking reports under these selections. A crash can reproduce failures across existing and new tabs. Replacement since context load is a proxy, not proof that this mechanism caused each selected failure or that every tab failed in production.
- The new episode telemetry adds load evidence and native-response attribution. It can distinguish an observed late response from no response within the window, but cannot prove page delivery or identify every lost-message cause. The original phase-1 proposal below is historical; the current contract is linked above.
Data used
- One full day, October 5, 2026 (UTC), on iOS 7.240 and macOS 1.210.
- The first daily "initialization failed" pixel: 6,624 iOS installs and 1,377 macOS installs.
- The daily "messaging stuck" pixel: 1,440 iOS installs and 487 macOS installs.
- Daily pixels fire at most once per install per day, so these are install-days, not users or episodes.
Failure cohorts
"Stuck" reports split by the state the app recorded at the time of failure. This describes symptoms, not root causes.
- Looks healthy (no visible error): the largest cohort, about 55% of iOS stuck reports.
- In 17–21% of iOS and 30–45% of macOS reports, the networking process had been replaced since the extension loaded.
- The rest has no visible cause, which is 748 iOS and 228 macOS daily reports. This is the main open question, covered below.
- WebKit error 6, background failed to load: about a third of iOS stuck reports; almost none on macOS.
- No background at all: 158 iOS and 35 macOS reports.
- Tab not connected to the extension (the tab has the wrong extension controller or no content scripts): 81 iOS and 102 macOS reports. On macOS this appeared only with version 1.210.
- Background process died: 14 iOS reports, almost always together with a networking process restart. This looks like iOS killing both processes under memory pressure.
The largest unexplained cohort: healthy-looking failures
- About half come right after the background was woken up again after idle unload. The background had been created less than 30 seconds earlier: 373 of 748 on iOS, 120 of 228 on macOS.
- A quarter on iOS and 15% on macOS come right after the extension was loaded or reloaded.
- On macOS, 63% of these reports come shortly after an app update, against 52% across all stuck reports.
- Memory pressure and WebKit errors are almost never present.
- Both macOS 26.7 and 27.0 are affected. The iOS version split has not been checked yet.
Ratios of separately deduplicated daily event totals:
- Recovery-without-reload daily totals are about 23% of initial-failure totals on iOS and 25% on macOS. The iOS count/daily ratio is about two reports per reporting installation-day; it does not identify repeated activity by the same people.
- Recovery-after-reload daily totals are 64% of stuck daily totals on iOS and 74% on macOS. These independently deduplicated counts do not establish an episode recovery probability.
- The recovery pixels cannot yet tell a late answer from a later page that worked. Phase 1 telemetry adds this.
Single failures and stuck episodes have different patterns:
- Failures right after an extension load make up 32% of single failures but only 18% of stuck reports.
- Failures right after a wake-up make up 44% of single failures but 61% of stuck reports.
- Recent-load and recent-wake signatures have different shares in the two separately sampled event populations. This does not show which individual initial failures later became stuck or recovered.
Theories and their status
-
Networking process crash leaves the background worker dead. Reproduced in tests. Its replacement signature appears in 20–45% under these filters; the causal share is unknown. The current app fix is #7459, not merged.
-
The first message is lost when a new extension version loads. Reproduced in tests. At launch the app already waits for the extension, so this is covered. Installing or updating the extension mid-session was not covered; app fix written, not merged.
-
The background worker dies while the networking process stays alive. Reproduced in tests. The app cannot detect it directly, so it can only react after the first failure.
-
Error 6. The cause was found in WebKit source code and reproduced on macOS. It did not reproduce on an iPhone with iOS 26.7.1 in four scenarios. Telemetry has been added to tell which conditions trigger it.
-
The worker starts slowly on wake-up. A start longer than 4 seconds reproduces the healthy-looking pattern exactly. Why real devices would be that slow is still unknown. Candidates:
- CPU contention with the page that is loading;
- process startup cost;
- the extension process running at low priority;
- a busy networking process.
Telemetry has been added for this.
-
WebKit cleans up website data every time the extension loads. WebKit change 312231@main, shipped in OS 26.6 and later, does this when an extension's internal base URL changes, which for us happens on every launch and every reload. It delays content scripts and the background start. On a Mac with a large browser cache, the delay was 0.75–1.35 seconds. This explains part of the "right after load" failures. A possible mitigation is to give the extension a stable base URL.
-
Ruled out:
- device lock and iOS data protection;
- an outdated tab URL on iOS;
- a macOS feature flag toggling (as the cause of tabs not connected to the extension);
- low-memory notifications;
- long freezes of the background as a cause of all-tab failures.
-
Not explained yet:
- tabs not connected to the extension on macOS;
- the "no background" cohort;
- WebKit error code 7;
- Lockdown Mode;
- the first page after an extension reload still failing (670 iOS and 232 macOS daily reports).
Relevant WebKit bugs
- Bug 317981: a message sent while the background is still starting is dropped. Fixed upstream, but still present on macOS 26.7.1, where we reproduced it for the first load of a new extension version.
- Bug 324743: a background worker is treated as ready before it has finished starting. Fixed upstream on September 22; not in 26.7 or 27.0. It fits the wake-up pattern, but we have no deterministic reproduction.
- Bug 320812: "Web Extensions load with significant delay on iOS 26.6 when Safari is cold launched". This is the slow website-data cleanup described above. Fixed upstream; which OS release ships the fix is unverified.
- Bug 314194, still open: Lockdown Mode blocks all service workers, so CPM cannot work for those users. We do not know how many users this affects.
- Bug 322881 and bug 324754: issues after a background reload. Probably not relevant to CPM, unproven.
- Bug 319976, fixed: a WebKit callback could fire twice on error. Relevant because the app uses this API.
- Not yet reported to WebKit:
- after a networking process crash, WebKit does not notice that the background worker is dead;
- the idle-unload timer starts before the background finishes loading, which causes error 6.
Historical phase-1 proposal — superseded by the episode report
All values are coarse buckets or fixed labels, with no URLs or identifiers.
- On failure pixels:
- whether the background had finished starting, and how long it took (
bg_ready_after); - how long ago the background was created (
bg_view_age); - whether the app was in the foreground (
app_state); - how many tabs were open and how many were loading (
open_tabs,loading_tabs); - for error 6, the app state and the time until the error (
bg_load_error_app_state,bg_load_error_after).
- whether the background had finished starting, and how long it took (
- On recovery pixels:
- whether the failed page answered late or a later page answered (
recovery_document); - how long after the first failure answers resumed (
recovery_after).
- whether the failed page answered late or a later page answered (
How to read it:
- "Background not ready" with a newly created view identifies an unfinished load/wake at that snapshot; it does not prove why it is slow or how it will end.
- "Background ready" with no native answer still permits several causes: init loss, settings delay, lost page response, or lost dashboard confirmation.
- A dashboard response attributed to the same timed-out measurement proves a late native confirmation. A later navigation in the same tab does not prove that the original page received its initResp.
- Error 6 about 30 seconds after view creation is consistent with the WebKit timer mechanism; it does not establish the natural trigger of every production error.