Skip to content

Conversation

@seanmcguire12
Copy link
Member

why

  • we needed to reload OOPIFs so that our shadow-root piercing JS was able to intercept the attachShadow() call
  • this is wasteful, and can cause unpredictable behaviour

what changed

  • swapped iframe reload logic for new logic that clones, and replaces shadow root nodes
  • this triggers the patched attachShadow() function

test plan

  • existing unit tests & evals should sufficiently cover shadow root piercing

@changeset-bot
Copy link

changeset-bot bot commented Nov 16, 2025

🦋 Changeset detected

Latest commit: bc88104

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@browserbasehq/stagehand Patch
@browserbasehq/stagehand-evals Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

3 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@browserbase browserbase deleted a comment from greptile-apps bot Nov 16, 2025
@seanmcguire12 seanmcguire12 added the act These changes pertain to the act function label Nov 16, 2025
@seanmcguire12
Copy link
Member Author

@greptileai

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Nov 16, 2025

Greptile Overview

Greptile Summary

This PR replaces wasteful OOPIF reload logic with an elegant clone-and-replace approach for shadow root piercing. Previously, when the shadow root piercer was injected after custom elements had already created their shadow roots, the code would reload entire iframes to trigger re-creation. The new approach walks the DOM, identifies custom elements missing tracked shadow roots, and clones/replaces them to trigger the connectedCallback() lifecycle method, which re-creates the shadow root under the patched attachShadow() hook.

Key Changes

  • Removed complex iframe reload logic (~66 lines) including waitingForDebugger parameter handling and 3-second load timeouts
  • Added rerenderMissingShadows.runtime.ts with safe, focused logic to clone and replace custom elements
  • Simplified onAttachedToTarget() flow by removing timing-sensitive reload coordination
  • Changed ensurePiercer() to return boolean for better error handling
  • Added build process for new rerender script in genDomScripts.ts

Analysis

The implementation is well-designed with proper error handling at multiple levels (try-catch in rerender loop, catch blocks on CDP calls). The clone-and-replace approach is more predictable than page reloads and avoids race conditions. The only edge case is custom elements that create shadow roots in constructors before connection, which is already discouraged by web component best practices.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk - it replaces fragile reload logic with a cleaner approach
  • Score of 5 reflects well-architected solution with comprehensive error handling, removal of timing-sensitive reload logic, proper integration with existing piercer system, and extensive try-catch blocks preventing failures. The approach is more deterministic than the previous reload-based solution.
  • No files require special attention

Important Files Changed

File Analysis

Filename Score Overview
packages/core/lib/v3/dom/rerenderMissingShadows.runtime.ts 5/5 Implements clone-and-replace logic for custom elements missing shadow roots, safe error handling included
packages/core/lib/v3/understudy/context.ts 5/5 Removed complex iframe reload logic and waitingForDebugger handling, simplified OOPIF initialization flow
packages/core/lib/v3/understudy/piercer.ts 5/5 Added rerender script execution after piercer installation, changed return type to boolean for error handling

Sequence Diagram

sequenceDiagram
    participant Browser as Chrome/Browser
    participant CDP as CDP Session
    participant Context as V3Context
    participant Piercer as installV3PiercerIntoSession
    participant Document as OOPIF Document
    participant CustomEl as Custom Elements

    Browser->>CDP: Target.attachedToTarget (OOPIF)
    CDP->>Context: onAttachedToTarget()
    Context->>Context: executionContexts.attachSession()
    Context->>Piercer: ensurePiercer(session)
    
    Note over Piercer: Install shadow root piercer
    Piercer->>Document: Page.addScriptToEvaluateOnNewDocument(v3ScriptContent)
    Piercer->>Document: Runtime.evaluate(v3ScriptContent)
    Note over Document: attachShadow() now patched
    
    Note over Piercer: Run rerender script
    Piercer->>Document: Runtime.evaluate(reRenderScriptContent)
    Document->>Document: createTreeWalker() - find custom elements
    Document->>Document: filter elements with missing shadow roots
    
    loop For each missing shadow root
        Document->>CustomEl: cloneNode(true)
        Document->>CustomEl: replaceWith(clone)
        CustomEl->>CustomEl: connectedCallback() triggered
        CustomEl->>Document: attachShadow() [PATCHED]
        Note over Document: Shadow root now tracked!
    end
    
    Piercer-->>Context: return true (success)
    Context->>Context: Continue OOPIF initialization
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@seanmcguire12 seanmcguire12 merged commit ab51232 into main Nov 16, 2025
15 checks passed
@github-actions github-actions bot mentioned this pull request Nov 16, 2025
seanmcguire12 pushed a commit that referenced this pull request Nov 16, 2025
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @browserbasehq/[email protected]

### Patch Changes

- [#1273](#1273)
[`ab51232`](ab51232)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix:
trigger shadow root rerender in OOPIFs by cloning & replacing instead of
reloading

- [#1268](#1268)
[`c76ade0`](c76ade0)
Thanks [@tkattkat](https://github.com/tkattkat)! - Expose reasoning, and
cached input tokens in stagehand metrics

- [#1267](#1267)
[`ffb5e5d`](ffb5e5d)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix: file
uploads failing on Browserbase

- [#1269](#1269)
[`772e735`](772e735)
Thanks [@tkattkat](https://github.com/tkattkat)! - Add example using
playwright screen recording

## @browserbasehq/[email protected]

### Patch Changes

- Updated dependencies
\[[`ab51232`](ab51232),
[`c76ade0`](c76ade0),
[`ffb5e5d`](ffb5e5d),
[`772e735`](772e735)]:
    -   @browserbasehq/[email protected]

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Copy link

@madcio-rgb madcio-rgb left a comment

Choose a reason for hiding this comment

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

T

michaelfp930-WB added a commit to michaelfp930-WB/stagehand that referenced this pull request Jan 12, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @browserbasehq/[email protected]

### Patch Changes

- [#1273](browserbase/stagehand#1273)
[`ab51232`](browserbase/stagehand@ab51232)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix:
trigger shadow root rerender in OOPIFs by cloning & replacing instead of
reloading

- [#1268](browserbase/stagehand#1268)
[`c76ade0`](browserbase/stagehand@c76ade0)
Thanks [@tkattkat](https://github.com/tkattkat)! - Expose reasoning, and
cached input tokens in stagehand metrics

- [#1267](browserbase/stagehand#1267)
[`ffb5e5d`](browserbase/stagehand@ffb5e5d)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix: file
uploads failing on Browserbase

- [#1269](browserbase/stagehand#1269)
[`772e735`](browserbase/stagehand@772e735)
Thanks [@tkattkat](https://github.com/tkattkat)! - Add example using
playwright screen recording

## @browserbasehq/[email protected]

### Patch Changes

- Updated dependencies
\[[`ab51232`](browserbase/stagehand@ab51232),
[`c76ade0`](browserbase/stagehand@c76ade0),
[`ffb5e5d`](browserbase/stagehand@ffb5e5d),
[`772e735`](browserbase/stagehand@772e735)]:
    -   @browserbasehq/[email protected]

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

act These changes pertain to the act function

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants