Skip to content

fix: create render pages in background to avoid focus stealing#70

Open
wangpi26 wants to merge 1 commit into
tamnd:mainfrom
wangpi26:fix/background-page-no-focus-steal
Open

fix: create render pages in background to avoid focus stealing#70
wangpi26 wants to merge 1 commit into
tamnd:mainfrom
wangpi26:fix/background-page-no-focus-steal

Conversation

@wangpi26

@wangpi26 wangpi26 commented Jul 9, 2026

Copy link
Copy Markdown

Problem

In headful mode (e.g. attaching to a logged-in browser via --control-url), every page created during a crawl opens in the foreground. This activates the Chrome window and steals focus from the user's active app on each page render, making the machine unusable for other work while kage runs.

Root cause

Pool.Render creates each page via stealth.Page(b), which calls b.Page(proto.TargetCreateTarget{}). The zero-value Background field defaults to false, so Chrome creates and activates the tab in the foreground.

Fix

Replace stealth.Page(b) with an explicit call that sets Background: true, then inject the same stealth.JS anti-detection script via EvalOnNewDocument. Behaviour is identical to before — the page is still a stealth page — except it now opens in the background and does not steal focus.

// 在后台创建页面,避免 headful 模式下每次新建 tab 都把 Chrome 窗口拉到前台抢夺焦点。
page, err := b.Page(proto.TargetCreateTarget{Background: true})
if err != nil {
    return RenderResult{}, fmt.Errorf("new page: %w", err)
}
defer func() { _ = page.Close() }()
if _, err := page.EvalOnNewDocument(stealth.JS); err != nil {
    return RenderResult{}, fmt.Errorf("inject stealth: %w", err)
}

This mirrors exactly what stealth.Page does internally, minus the one-line difference (Background: true).

Verification

  • go build ./... and go vet ./browser/ pass.
  • Tested headful mode with --control-url attaching to a logged-in Chrome: pages now open in background tabs without stealing focus, and crawl results are unchanged.

Impact

  • Headless mode (the default release build): no change — background/foreground is irrelevant with no visible window.
  • Headful mode (--control-url, --headful): pages no longer steal focus. This is particularly important when attaching to a browser that the user is actively using for authenticated crawls.

In headful mode (e.g. --control-url attaching to a logged-in browser),
every new page created via stealth.Page() was opened in the foreground,
which activated the Chrome window and stole focus from the user's
active app on each page render.

Replace stealth.Page(b) with an explicit b.Page() using
TargetCreateTarget{Background: true}, then inject the same stealth.JS
anti-detection script via EvalOnNewDocument. Behaviour is identical
except pages now open in the background, so focus is no longer
disrupted during a crawl.
@wangpi26

wangpi26 commented Jul 9, 2026

Copy link
Copy Markdown
Author

The failing govulncheck check is unrelated to the changes in this PR.

Failure cause: Go standard library vulnerability GO-2026-5856 — "Invoking Encrypted Client Hello privacy leak in crypto/tls".

  • Affected: crypto/tls@go1.26.4
  • Fixed in: crypto/tls@go1.26.5

The repo's go.mod currently declares go 1.26.4, and CI runs govulncheck with GOTOOLCHAIN: local, so it scans against the vulnerable version. The analysis reports 5 call chains reaching crypto/tls (e.g. cli.runEmbeddedViewerhttp.Server.Servetls.Conn.HandshakeContext), so it is flagged as actually affected rather than just a transitive dependency.

This is a pre-existing issue from the go.mod version directive, not something introduced by this PR's focus-stealing fix.

Suggested fix (independent of this PR): bump go.mod's go directive from 1.26.4 to 1.26.5.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant