Skip to content

Feat/cdp disable iframes#2426

Merged
karlseguin merged 3 commits into
mainfrom
feat/cdp-disable-iframes
May 12, 2026
Merged

Feat/cdp disable iframes#2426
karlseguin merged 3 commits into
mainfrom
feat/cdp-disable-iframes

Conversation

@karlseguin
Copy link
Copy Markdown
Collaborator

Minor tweaks to #2401

staylor and others added 3 commits May 8, 2026 17:05
Adds a Lightpanda-specific CDP method that lets drivers opt out of
subframe processing entirely:

  await client.send('LP.setSubframeLoading', { enabled: false });

When disabled, the HTML parser silently bypasses every <iframe> it
encounters: no child Frame is created, no document fetch is issued,
and no Page.frameAttached / Page.frameNavigated /
Runtime.executionContextCreated events are emitted. The driver only
sees the main frame's lifecycle.

Motivation: pages that load large numbers of analytics / pixel
iframes (Shopify storefronts, ad-heavy news sites) trigger #2400
\u2014 each subframe navigation re-registers the main frame's V8 context
under the child's frameId and invalidates the executionContextId the
driver had pinned for the main frame. Subsequent Runtime.evaluate
fails with 'Cannot find context with specified id' (Playwright
surfaces this as 'Execution context was destroyed', Puppeteer hangs
in IsolatedWorld.evaluate waiting for a 'context' event). The proper
fix is per-frame V8 inspector context groups (or per-frame
IsolatedWorld), discussed in #2400; this method gives drivers a
clean opt-in workaround in the meantime.

Mechanism: new bool field Session.subframe_loading_enabled (default
true). Frame.iframeAddedCallback short-circuits when false, marking
the iframe as _executed so the parser doesn't re-deliver it.

Verified against the puppeteer-core repro on
https://www.allbirds.com/products/mens-wool-runners (which
instantiates ~11 web-pixel iframes during initial render):

  baseline (subframe loading ON):
    page.title()  works (lucky timing) but server segfaults on
                  disconnect from the worker re-entrancy bug; iframes
                  do load and trigger the executionContextId churn

  with LP.setSubframeLoading(false):
    [opt-out] LP.setSubframeLoading reply: {}
    [ok] goto status=200 elapsed=6166ms
    [stats] frame_attached_events_seen=0
    [ok] page.title() = "Allbirds Wool Runners, Men's | ..."
    [ok] evaluate(1+1) = 2
    [ok] evaluate(document.title) = "Allbirds Wool Runners, Men's | ..."
    [ok] body.innerHTML.length = 923161

521/521 unit tests still pass.
Complementary to LP.setSubframeLoading (preceding commit): exposes
the same iframe-skip behavior as a CLI option that applies to all
sessions in the process. Useful for:

  * the 'fetch' subcommand (no CDP driver to call LP.setSubframeLoading)
  * 'serve' deployments where the operator wants iframes off by
    default for every connecting client (the LP method can still
    re-enable per-session if needed)
  * Playwright's chromium.connectOverCDP, which can't reliably issue
    custom CDP methods on Lightpanda today: BrowserContext.newCDPSession
    and Browser.newBrowserCDPSession both attach a new CRSession that
    collides with the STARTUP-session reuse from #2399, triggering a
    Playwright internal assertion. With --disable-subframes set on the
    server, Playwright doesn't need to issue any custom CDP \u2014 every
    session inherits subframes-off and the executionContextId churn
    from #2400 never trips.

Verified:

  serve --disable-subframes + plain puppeteer-core goto
    [ok] goto status=200 elapsed=6354ms frameAttached=0

  fetch --disable-subframes --dump html https://www.allbirds.com/...
    exit=0
    html bytes: 1021562
    title: <title>Allbirds Wool Runners, Men's | ...</title>
    iframe count in dumped html: 2  (still in DOM, just not loaded)

521/521 unit tests pass.
Remove repeating description/comment of flag.

Change CDP lp command to be a general configuration endpoint.
@karlseguin karlseguin merged commit e9b2aa4 into main May 12, 2026
36 of 39 checks passed
@karlseguin karlseguin deleted the feat/cdp-disable-iframes branch May 12, 2026 05:16
@github-actions github-actions Bot locked and limited conversation to collaborators May 12, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants