{"slug": "surviving-dom-churn-browseract-s-state-index-vs-raw-playwright", "title": "Surviving DOM churn: BrowserAct's state index vs raw Playwright", "summary": "BrowserAct, a tool sponsored by Claude Code, outperforms raw Playwright in surviving DOM churn caused by changing build hashes, according to a head-to-head test on a deliberately hostile page. BrowserAct's state index provides a turn-by-turn representation of interactive elements, enabling agents to reassess after each action, whereas Playwright's role/text locators fix specific cases but lack this reasoning capability.", "body_md": "# Surviving DOM churn: BrowserAct's state index vs raw Playwright\n\n[Claude Code](/en/tags/claude%20code/)browser tasks die on the second run. The page looks identical, the button is right there, but the id changed because the build hash rotated — and Playwright's timeout error doesn't tell you a damn thing about why.\n\nFull disclosure before the tech: BrowserAct sponsored this test, and the links in the original post were affiliate-tracked. That said, I ran it against my own deliberately hostile page, head-to-head with raw Playwright.\n\nHere's the shape of the failure. A frontend re-renders with fresh CSS-module or styled-components hashes on every deploy. You write:\n\n``` js\nconst id = await page.locator(\"button\").getAttribute(\"id\");\nawait page.reload();\nawait page.locator(`#${id}`).click({ timeout: 3000 });\n```\n\nWorks the day you write it. Breaks the next time the build hash changes, and the failure is a bare timeout:\n\n```\nlocator.click: Timeout 3000ms exceeded.\n```\n\nPlaywright's own role/text locators fix this specific case — `getByRole(\"button\", { name: \"Submit\" })`\n\nsurvives id/class churn fine, because it never depended on the hash in the first place. That's a real fix, not a workaround. What it doesn't give you is a representation of the page an agent can reason about turn by turn, or a signal that says \"the page under you just changed, stop and re-check.\" That's the gap BrowserAct is actually filling.\n\nThe interaction model is different. BrowserAct doesn't hand [Claude](/en/tags/claude/) Code a selector at all. The loop is: read the current state, choose an action from what's actually there, execute it, reassess.\n\n``` plaintext\n\nstate -> indexed list of interactive elements, as of right\n\n[Next Why We Deprecated These AI Agent Skills →](/en/threads/4562/)", "url": "https://wpnews.pro/news/surviving-dom-churn-browseract-s-state-index-vs-raw-playwright", "canonical_source": "https://promptcube3.com/en/threads/4578/", "published_at": "2026-07-31 19:56:36+00:00", "updated_at": "2026-07-31 20:24:48.964678+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools"], "entities": ["BrowserAct", "Claude Code", "Playwright"], "alternates": {"html": "https://wpnews.pro/news/surviving-dom-churn-browseract-s-state-index-vs-raw-playwright", "markdown": "https://wpnews.pro/news/surviving-dom-churn-browseract-s-state-index-vs-raw-playwright.md", "text": "https://wpnews.pro/news/surviving-dom-churn-browseract-s-state-index-vs-raw-playwright.txt", "jsonld": "https://wpnews.pro/news/surviving-dom-churn-browseract-s-state-index-vs-raw-playwright.jsonld"}}