Skip to content

[WEP] keep WebViews running while hidden - #5920

Open
julianstorer wants to merge 2 commits into
wailsapp:masterfrom
juggler-ai:wep/keep-running-when-hidden
Open

[WEP] keep WebViews running while hidden#5920
julianstorer wants to merge 2 commits into
wailsapp:masterfrom
juggler-ai:wep/keep-running-when-hidden

Conversation

@julianstorer

@julianstorer julianstorer commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Add an opt-in per-window preference that stops the platform WebView from throttling JavaScript while the window is hidden

FYI, here's my reference implementation:
https://github.com/juggler-ai/wails/tree/feat/mac-dock-bounce-on-flash

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This proposal defines an opt-in, per-window KeepRunningWhenHidden preference. macOS uses optional.Bool and WKPreferences.inactiveSchedulingPolicy. Windows uses a bool and keeps the WebView2 controller visible while the window is hidden. Linux is excluded.

Changes

Keep Running When Hidden

Layer / File(s) Summary
Preference proposal and platform behavior
v3/wep/proposals/keep-running-when-hidden/proposal.md
Defines macOS and Windows public fields, platform behavior, default throttling, usage, compatibility, constraints, alternatives, testing, security, and maintenance considerations.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Poem

A rabbit hid the window from sight,
Yet background work continued right.
Mac chose a policy, Windows stayed near,
Linux sat this proposal out of gear.
With opt-in settings, the path is clear.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description states the change but omits the required summary, change type, testing details, configuration, dependencies, issue reference, and checklist. Complete the required template sections, mark the change as a WEP, and document testing, configuration, dependencies, motivation, and checklist status.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the WEP and its primary change: keeping WebViews running while hidden.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
v3/wep/proposals/keep-running-when-hidden/proposal.md (1)

162-171: 🎯 Functional Correctness | 🔵 Trivial | 🏗️ Heavy lift

Expand the acceptance tests to cover the full visibility state machine.

Add tests for:

  • macOS true, false, and unset values.
  • A WebView attached to a hidden or miniaturized NSWindow.
  • macOS versions older than 14.
  • Windows windows hidden before first display.
  • Windows windows shown, then hidden or minimized, then restored.
  • Default behavior with the option disabled.
  • Public-option to native-bridge propagation.

The optional example can supplement these tests, but it cannot replace regression coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v3/wep/proposals/keep-running-when-hidden/proposal.md` around lines 162 -
171, Expand the proposal’s Test Plan to require regression coverage for the
complete visibility state machine: macOS true, false, and unset options;
WebViews in hidden or miniaturized NSWindows; macOS versions before 14; Windows
windows hidden before first display; windows shown, then hidden or minimized,
and restored; disabled-option defaults; and propagation from the public option
through the native bridge. Treat the v3 example as optional supplementary
coverage, not a substitute for these tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@v3/wep/proposals/keep-running-when-hidden/proposal.md`:
- Around line 15-18: Update the macOS proposal contract to use
WKInactiveSchedulingPolicySuspend instead of “OS default (automatic)”, and
describe KeepRunningWhenHidden as assigned while constructing
WKWebViewConfiguration before allocation rather than “at navigation time”.
Verify that the none policy actually prevents throttling for hidden NSWindow
content before exposing the option; otherwise revise or remove the macOS
exposure.
- Around line 26-27: Align the Windows preference wording with its
implementation: either update the hidden-window behavior to keep the WebView2
controller visible across later hide, minimize, and restore transitions, or
explicitly scope the option to windows that are hidden and have never been
shown. Update the Windows option description in the proposal so it matches the
chosen contract.

---

Nitpick comments:
In `@v3/wep/proposals/keep-running-when-hidden/proposal.md`:
- Around line 162-171: Expand the proposal’s Test Plan to require regression
coverage for the complete visibility state machine: macOS true, false, and unset
options; WebViews in hidden or miniaturized NSWindows; macOS versions before 14;
Windows windows hidden before first display; windows shown, then hidden or
minimized, and restored; disabled-option defaults; and propagation from the
public option through the native bridge. Treat the v3 example as optional
supplementary coverage, not a substitute for these tests.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b6a4e44b-db87-44ac-984b-27ee1d82e8e7

📥 Commits

Reviewing files that changed from the base of the PR and between f80dad5 and dcad469.

📒 Files selected for processing (1)
  • v3/wep/proposals/keep-running-when-hidden/proposal.md

Comment on lines +15 to +18
Add an opt-in per-window preference that stops the platform WebView from
throttling JavaScript while the window is hidden. It is exposed as
`Mac.WebviewPreferences.KeepRunningWhenHidden` on macOS and
`Windows.KeepRunningWhenHidden` on Windows. Default behaviour is unchanged.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Repository files for proposal:"
git ls-files | grep -E 'v3/wep/proposals/keep-running-when-hidden|keep-running-when-hidden' || true

echo
echo "Proposal excerpt:"
if [ -f v3/wep/proposals/keep-running-when-hidden/proposal.md ]; then
  nl -ba v3/wep/proposals/keep-running-when-hidden/proposal.md | sed -n '1,120p'
fi

echo
echo "Search for related identifiers:"
rg -n "KeepRunningWhenHidden|inactiveSchedulingPolicy|WKPreferences|SchedulingPolicy|KeepRunning|throttl|suspend|automatic|hidden|miniaturiz" . || true

Repository: wailsapp/wails

Length of output: 297


🌐 Web query:

Apple WKPreferences inactiveSchedulingPolicy WebViews not in window default suspend thrott none

💡 Result:

The inactiveSchedulingPolicy property in Apple's WKPreferences class is used to specify how a WKWebView handles tasks when it is not in a window, such as when it is in a background tab [1][2]. This policy is available for macOS 14.0+ and iOS 17.0+ [2]. The policy can be set to one of the following values, defined in the WKPreferences.InactiveSchedulingPolicy enumeration [3][2]: 1. suspend: This is the default policy [1]. The web view fully suspends tasks, pausing JavaScript execution and page layout when the web view is idle and detached from the view hierarchy [1][3][2]. 2. throttle: The web view limits processing (CPU-throttled) when idle, but does not fully suspend tasks [3][2]. 3. none: No special scheduling behavior is applied, allowing the web view to continue running normally even when idle [3][2]. Web views are generally exempted from these inactive scheduling policies if they are actively playing media, performing media capture, or engaging in other user-interactive activities [1][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Proposal excerpt:"
awk '{printf "%6d\t%s\n", NR, $0}' v3/wep/proposals/keep-running-when-hidden/proposal.md | sed -n '1,140p'

echo
echo "Search for related identifiers:"
rg -n "KeepRunningWhenHidden|inactiveSchedulingPolicy|WKPreferences|SchedulingPolicy|KeepRunning|throttl|suspend|automatic|hidden|miniaturiz|window|attached|allocation|navigation" v3/wep/proposals/keep-running-when-hidden/proposal.md . || true

Repository: wailsapp/wails

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Proposal excerpt:"
awk '{printf "%6d\t%s\n", NR, $0}' v3/wep/proposals/keep-running-when-hidden/proposal.md | sed -n '1,160p'

echo
echo "Exact identifier matches in proposal only:"
rg -n "KeepRunningWhenHidden|inactiveSchedulingPolicy|WKPreferences|SchedulingPolicy|KeepRunning|throttl|suspend|automatic|hidden|miniaturiz|window|at navigation time|allocation|navigation|true|false" v3/wep/proposals/keep-running-when-hidden/proposal.md

Repository: wailsapp/wails

Length of output: 11613


🌐 Web query:

Apple WKPreferences inactiveScheduling policy on hidden NSWindow WKWebView not no window

💡 Result:

The inactiveSchedulingPolicy property in WKPreferences allows developers to control the scheduling behavior of a WKWebView when it is idle and detached from the view hierarchy (i.e., not in a window) [1][2]. Introduced in macOS 14.0 and iOS 17.0, this policy addresses issues where WebKit might aggressively throttle or suspend the WebContent process for web views that are hidden or not currently attached to a window [1][3][4]. The policy provides three modes defined by the WKPreferences.InactiveSchedulingPolicy enumeration [5][1]: 1. WKInactiveSchedulingPolicyNone: The web view runs tasks normally, with no special scheduling behavior applied, even when idle [1]. This is often used to prevent unwanted suspension of background processes or web views that are meant to stay active while hidden [3][4]. 2. WKInactiveSchedulingPolicyThrottle: The web view CPU-throttles tasks when idle but does not fully suspend them [1]. 3. WKInactiveSchedulingPolicySuspend: The web view fully suspends tasks (pausing JavaScript execution and page layout) when idle [1]. Web views are generally not considered idle if they are currently playing media or loading web pages [1][6]. Developers typically use the None policy when they need to ensure that a WKWebView continues to execute JavaScript or maintain state while it is hidden or detached from a visible window [3][4].

Citations:


Align the macOS contract with the API semantics.

WKPreferences.inactiveSchedulingPolicy is intended for WebViews idle and detached from the view hierarchy, not specifically for hidden NSWindow content. Verify that none prevents throttling for the hidden-window use case before exposing this option as described. Also replace “OS default (automatic)” with WKInactiveSchedulingPolicySuspend, and avoid “at navigation time” because the design says the value is assigned when the WKWebViewConfiguration is built before allocation.
[low_effort_and_medium_reward]

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v3/wep/proposals/keep-running-when-hidden/proposal.md` around lines 15 - 18,
Update the macOS proposal contract to use WKInactiveSchedulingPolicySuspend
instead of “OS default (automatic)”, and describe KeepRunningWhenHidden as
assigned while constructing WKWebViewConfiguration before allocation rather than
“at navigation time”. Verify that the none policy actually prevents throttling
for hidden NSWindow content before exposing the option; otherwise revise or
remove the macOS exposure.

Source: MCP tools

Comment on lines +26 to +27
- **Windows**: WebView2 moves a hidden window's controller into "efficiency
mode" (WebView2 issue #2861), driving the page's timers toward 0Hz.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Changed files/stat:"
git diff --stat || true

echo
echo "Candidate proposal file:"
fd -a 'proposal\.md$' . | sed 's#^\./##' | grep -F 'v3/wep/proposals/keep-running-when-hidden/proposal.md' || true

echo
echo "Relevant proposal excerpt:"
if [ -f v3/wep/proposals/keep-running-when-hidden/proposal.md ]; then
  nl -ba v3/wep/proposals/keep-running-when-hidden/proposal.md | sed -n '1,120p'
fi

echo
echo "Repository-wide references to keep-running/hidden/IsVisible:"
rg -n "keep-running|hidden|is_visible|IsVisible|WebView2|PutIsVisible|controller|efficiency" . --glob '!**/.git/**' --glob '!**/node_modules/**' --glob '!**/build/**' --glob '!**/dist/**' | head -n 200

Repository: wailsapp/wails

Length of output: 340


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Changed files/stat:"
git diff --stat || true

echo
echo "Candidate proposal file:"
ls -la v3/wep/proposals/keep-running-when-hidden/proposal.md || true

echo
echo "Relevant proposal excerpt:"
awk '{printf "%6d\t%s\n", NR, $0}' v3/wep/proposals/keep-running-when-hidden/proposal.md | sed -n '1,140p'

echo
echo "Repository-wide references to keep-running/hidden/IsVisible:"
rg -n "keep-running|hidden|is_visible|IsVisible|WebView2|PutIsVisible|controller|efficiency" . --glob '!**/.git/**' --glob '!**/node_modules/**' --glob '!**/build/**' --glob '!**/dist/**' | head -n 200 || true

Repository: wailsapp/wails

Length of output: 50371


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Proposal excerpt:"
awk '{printf "%6d\t%s\n", NR, $0}' v3/wep/proposals/keep-running-when-hidden/proposal.md | sed -n '1,120p'

echo
echo "Focused source references for proposal keywords:"
rg -n -C 3 "KeepRunningWhenHidden|keep-running-when-hidden|KeepRunningWhenHidden|controller.|PutIsVisible|IsVisible|navigationCompleted|HideWindow|hide.*window|min.*window|restore.*window|window hidden|hidden.*window" v3 --glob '!**/*.md' --glob '!**/docs/**' | head -n 300

echo
echo "Candidate window/windowing files in v3:"
git ls-files v3 | rg '(^v3/.*/.*(window|browser|webview|window\.)|(^v3/.*/windows)' | sed -n '1,160p'

Repository: wailsapp/wails

Length of output: 50372


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Focused Go references for windows WebViewOptions, KeepRunningWhenHidden, and PutIsVisible:"
rg -n -C 4 "KeepRunningWhenHidden|PutIsVisible|IsVisible|navigationCompleted|WebView.*Options|Webview.*Options|Chromium\\.(Show|Hide)|Show\\(\\)|Hide\\(" v3/internal v3/pkg v3/lib --glob '*.go' --max-count 200

Repository: wailsapp/wails

Length of output: 50371


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Files containing KeepRunningWhenHidden (Go and proposal):"
rg -n "KeepRunningWhenHidden" . --glob '*.{go,md}' || true

echo
echo "Files containing WebviewWindowOptions + KeepRunningWhenHidden context:"
rg -n "KeepRunningWhenHidden|WebviewWindowOptions|type WindowsWindow|type WindowOptions|type .*Window " . --glob '*.go' | head -n 240

echo
echo "Windows window/windowing Go candidates:"
git ls-files v3 | rg 'windows|window|webview|webkit|platform|platforms|runtime' | head -n 220

echo
echo "webview2 window implementation candidates containing PutIsVisible or navigationCompleted:"
rg -n -C 5 "navigationCompleted|PutIsVisible|Hide\\(\\)|Show\\(|Hidden|WindowsWindow|KeepRunningWhenHidden|ICoreWebView2Controller3|ICoreWebView2Controller2" v3/internal/webview2 --glob '*.go' --max-count 200 || true

Repository: wailsapp/wails

Length of output: 35353


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "WindowsWindow option type and KeepRunningWhenHidden:"
awk '{printf "%6d\t%s\n", NR, $0}' v3/pkg/application/webview_window_options.go | sed -n '330,375p'

echo
echo "WindowsWebViewWindow field and constructor/options handling:"
awk '{printf "%6d\t%s\n", NR, $0}' v3/pkg/application/webview_window_windows.go | sed -n '1,180p'
rg -n -C 4 "navigationCompleted|PutIsVisible|IsVisible|Show\\(|Hide\\(|Hidden|W32|WWebView|windowsWebviewWindow|NewWithOptions|WebviewWindowOptions" v3/pkg/application/webview_window_windows.go | sed -n '1,260p'

echo
echo "WindowsWebViewWindow Hide.Show implementations nearby:"
awk '{printf "%6d\t%s\n", NR, $0}' v3/pkg/application/webview_window_windows.go | rg 'Hide|Show|Navigation|Controller|PutIsVisible|KeepRunningWhenHidden' -n -C 3 || true

Repository: wailsapp/wails

Length of output: 33417


🌐 Web query:

Microsoft WebView2 PutIsVisible IsVisible efficiency mode issue 2861

💡 Result:

The issue referenced as #2861 in the Wails repository [1] relates to scenarios where WebView2 applications may fail to display or become unresponsive due to Windows Efficiency Mode. In Microsoft WebView2, Efficiency Mode is a resource-management feature that can throttle or suspend processes—typically renderer processes associated with the WebView2 control—when the system determines the control is inactive or not visible [2][3]. The PutIsVisible method (available via the ICoreWebView2Controller interface) [4][5][6] is the primary API used to manage the visibility state of a WebView2 control. The official guidance from Microsoft is to keep the IsVisible property set to true to indicate that the control is active and to avoid unnecessary throttling by Efficiency Mode [2][3]. Key technical points regarding this issue include: - Behavior: When IsVisible is set to false, WebView2 may purge memory or throttle activity [4]. While this is a documented performance optimization (e.g., when a window is minimized) [4], it can interfere with applications if the system incorrectly flags the WebView2 instance as inactive, leading to scenarios where the window fails to render or loses communication with the host application runtime [1]. - Wails Implementation: The Wails project has implemented workarounds for this behavior in its window management logic [7]. These workarounds include ensuring the window is shown and, if navigation is delayed, triggering a forced call to the show logic to prevent the WebView2 from remaining permanently invisible or suspended due to system-level Efficiency Mode management [7]. - Documentation: Microsoft notes that developers should handle WM_SIZE messages to toggle IsVisible (e.g., FALSE when minimized, TRUE when restored) to balance resource usage and performance correctly [4]. However, relying on this to avoid Efficiency Mode issues remains a common point of discussion, as developers sometimes require the control to stay active regardless of apparent UI visibility [3].

Citations:


Scope the Windows option to the hidden-and-never-shown case.

The design says the Windows preference keeps the controller visible while the window is hidden, but the implementation leaves every later hide/minimize/restore transition on the existing Show()/Hide() paths. Keep the same contract in that implementation, or change the option wording to mean only a hidden window that has never been shown.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v3/wep/proposals/keep-running-when-hidden/proposal.md` around lines 26 - 27,
Align the Windows preference wording with its implementation: either update the
hidden-window behavior to keep the WebView2 controller visible across later
hide, minimize, and restore transitions, or explicitly scope the option to
windows that are hidden and have never been shown. Update the Windows option
description in the proposal so it matches the chosen contract.

Source: MCP tools

@github-actions github-actions Bot added Documentation Improvements or additions to documentation v3-alpha labels Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Documentation Improvements or additions to documentation v3-alpha

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant