Before submitting an issue, please:
Environment Information
Stagehand:
- Language/SDK: TypeScript
- Stagehand version: v4 pre-release
AI Provider:
This uses the deterministic locator API; no model or agent call is involved.
Issue Description
On a private React application, an option row in a side panel is rendered as an
<a role="button">. The row is visible and a v4 locator matches exactly one
element.
await option.click() resolves successfully, but the application does not
commit the selection: the side panel remains open and the step counter is
unchanged. A Playwright locator click on the same element immediately closes
the panel and increments the local step counter.
I repeated this on three fresh instances of the flow. The v4 click was a no-op
each time, while the Playwright control committed the local selection each
time. There is no thrown error or timeout from locator.click().
Steps to Reproduce
- Open a React side panel containing a selectable
<a role="button">Option A</a> row.
- Resolve the row with a v4 locator and confirm
count() === 1 and
isVisible() === true.
- Call
await option.click().
- Observe that the panel remains open and the application state is unchanged.
- Reset the UI and click the same row with a Playwright locator.
- Observe that the panel closes and the application state changes.
Minimal Reproduction Code
The labels and selectors below are synthetic because the original application
is private.
// Stagehand imported from the v4 pre-release TypeScript SDK.
const stagehand = new Stagehand({
browser: {
type: "cdp",
cdpUrl: process.env.CDP_URL!,
},
});
await stagehand.init();
const page = await stagehand.context.activePage();
if (!page) throw new Error("No active page");
const option = page.locator(
"xpath=//*[@role='button'][normalize-space(.)='Option A']",
);
console.log({
count: await option.count(), // 1
visible: await option.isVisible(), // true
});
await option.click(); // resolves, but the application does not change
Control against the same open page and element:
import { chromium } from "playwright";
const browser = await chromium.connectOverCDP(process.env.CDP_URL!);
const page = browser.contexts()[0].pages()[0];
await page.getByRole("button", { name: "Option A" }).click();
// The panel closes and the application state changes.
Potential Implementation Lead
This may be related to the v4 Understudy locator click implementation, which
queues mouseMoved, mousePressed, and mouseReleased requests together and
then awaits them with Promise.all:
https://github.com/browserbase/stagehand/blob/v4-spike/packages/server/understudy/locator.ts#L325-L357
That is only a hypothesis, but it seems worth testing whether the pipelined
burst can race a component's hover/pointer state. The Playwright control
serializes the interaction and succeeds.
Error Messages / Log trace
No error. locator.click() resolves normally.
Screenshots / Videos
Not attached because the source application contains private data.
Related Issues
Before submitting an issue, please:
Environment Information
Stagehand:
AI Provider:
This uses the deterministic locator API; no model or agent call is involved.
Issue Description
On a private React application, an option row in a side panel is rendered as an
<a role="button">. The row is visible and a v4 locator matches exactly oneelement.
await option.click()resolves successfully, but the application does notcommit the selection: the side panel remains open and the step counter is
unchanged. A Playwright locator click on the same element immediately closes
the panel and increments the local step counter.
I repeated this on three fresh instances of the flow. The v4 click was a no-op
each time, while the Playwright control committed the local selection each
time. There is no thrown error or timeout from
locator.click().Steps to Reproduce
<a role="button">Option A</a>row.count() === 1andisVisible() === true.await option.click().Minimal Reproduction Code
The labels and selectors below are synthetic because the original application
is private.
Control against the same open page and element:
Potential Implementation Lead
This may be related to the v4 Understudy locator click implementation, which
queues
mouseMoved,mousePressed, andmouseReleasedrequests together andthen awaits them with
Promise.all:https://github.com/browserbase/stagehand/blob/v4-spike/packages/server/understudy/locator.ts#L325-L357
That is only a hypothesis, but it seems worth testing whether the pipelined
burst can race a component's hover/pointer state. The Playwright control
serializes the interaction and succeeds.
Error Messages / Log trace
Screenshots / Videos
Not attached because the source application contains private data.
Related Issues