How Cursor + BrowserAct Handles Dynamic Pages Without Brittle Selectors 💎
TL;DR Modern web applications change constantly. Components are re-rendered, generated attributes may differ between builds. Even when the UI looks identical, browser automation can fail because it still relies on assumptions captured before the page changed. In this article, I used Cursor with Br
TL;DR Modern web applications change constantly. Components are re-rendered, generated attributes may differ between builds. Even when the UI looks identical, browser automation can fail because it still relies on assumptions captured before the page changed. In this article, I used Cursor with BrowserAct CLI to test a dynamic project filter. Instead of relying on unreliable selectors, Cursor used BrowserAct to inspect the current page state and complete the task without relying on brittle selectors. The goal wasn't to eliminate the DOM or replace Playwright. The goal was to give an AI agent a reliable inspect → act → reassess loop that works on modern, dynamic websites. Well, let's get started! 🏎️ A browser test can run successfully for weeks and suddenly fail after a harmless frontend update. The button is still visible. The feature still works. Yet the test fails because the element it expected no longer exists. <!-- Initial page --> <div class="toolbar"> <button id="date-filter-btn">Filter by Date</button> </div> After hydration: <div class="toolbar toolbar--v2"> <div class="toolbar__indent"></div> <button id="status-filter-btn" class="btn btn--active"> <span>⚙️</span> <span>Filter by Date</span> </button> </div> await page.click("#date-filter-btn") This may fail because the selector no longer matches the current page. Modern browser automation works best when the application is already known. Engineers can write reliable Playwright tests because they understand the page structure in advance and maintain those tests as the application evolves. // Playwright: Assumes you know the page structure await page.click('#filter-button'); // Works if this ID exists today await page.waitForTimeout(500); // Hope this is long enough await page.fill('input[name="search"]', 'query'); // Works if DOM hasn't changed The challenge is different for AI agents. When Cursor operates an unfamiliar website, it cannot assume which elements exist or how the interface is structured. After every meaningful interaction, the page may change, introducing new controls or replacing existing ones. Instead of relying on selectors captured earlier, the agent needs to inspect the current page state, choose the next action based on what's actually available, and reassess after the UI updates. This is the gap BrowserAct is designed to address. Instead of asking Cursor to remember selectors captured earlier, BrowserAct lets the agent repeatedly inspect the current browser state before deciding what to do next. The workflow becomes: Open the page Read the current state Choose an action Execute the action Wait until stable Read the state again Verify the result It gives Cursor a compact representation of the current page state, allowing the agent to inspect the page, act on what's currently available, and reassess after every meaningful UI change. Rather than relying on assumptions from an earlier DOM snapshot, Cursor continuously works with the page as it exists now, making it much more resilient to dynamic interfaces. Let's move from words to action. To demonstrate a working workflow, I used a searchable list of projects. To get started, let's install browser-act. uv tool install browser-act-cli --python 3.12 You can check the version as follows: browser-act --version I'm showing the following version. Yours may be newer, but the gist remains the same: With the Cursor app open, let's test getting the current state of our app. To do this, we'll enter the following prompt into the input: Use BrowserAct in Cursor to test the search functionality on EmbedCatalog. Read the current page state before every action. After the page changes, refresh the page state instead of reusing previous indices. Search for a project, open its details page, and verify that the correct project information is displayed. browser-act --session embedcatalog browser open https://embedcatalog.com browser-act --session embedcatalog state After that the testing process will begin. Please note that Cursor may ask you for permission to execute commands at the time of generation. This will look something like this: After clicking the run button, after a while our first command should execute, opening the browser. If this is your first time using automation tools, the browser may ask you to confirm the action. Simply click allow, and then the website will open: While you're running tests, you may experience automatic browser actions. Don't worry, this is BrowserAct at work. Based on our commands, it can click buttons, scroll, and do other things to get the current page state. Instead of relying on selectors captured earlier, BrowserAct generated a compact representation of the interactive elements currently available on the page. Don't close the page while it's running, or you may encounter an error. After my Composer 2.5 generated the response, Cursor gave us the following result: We didn't specify any selectors. Cursor, with the help of BrowserAct, automatically found the required input, searched for the page, and scanned it. We simply generated a simple prompt, without looking at the DOM at all. Now let's try a more complex search option. I'll list the following commands and briefly walk through the workflow: browser-act --session embedcatalog click <CURRENT_INDEX> browser-act --session embedcatalog wait stable browser-act --session embedcatalog state browser-act --session embedcatalog fill <CURRENT_INDEX> "BrowserAct" browser-act --session embedcatalog wait stable browser-act --session embedcatalog state browser-act --session embedcatalog click <CURRENT_INDEX> browser-act --session embedcatalog wait stable browser-act --session embedcatalog get markdown In this workflow, Cursor first opens the search interface and waits for the page to stabilize. It then refreshes the page state, enters "BrowserAct" into the search field, waits for the results to load, and reads the updated state again before selecting the correct result. Finally, it retrieves the page content in Markdown to verify that the expected project page was opened successfully. By entering the same thing into Cursor and adding our commands, after a while we get the following result: The test completed successfully. After every interaction, Cursor refreshed the current page state before continuing, allowing it to adapt to the updated interface. The verification confirmed that the correct project was opened. The project name, description, last updated date, star count, tags, and project URL all matched the search result, so the workflow finished with a PASS result without relying on hard-coded selectors. Вот более компактная версия. Она сохраняет основную мысль, но читается заметно легче. BrowserAct doesn't create a selector that never breaks. Instead, it gives AI agents a better way to recover from UI changes by repeatedly inspecting the current page state before deciding what to do next. Rather than relying on an ID, CSS selector, or XPath captured earlier, the agent works with the page as it exists now. This shifts the workflow from: Remember → Click → Hope to: Inspect → Act → Wait → Inspect Again Making browser automation more resilient on dynamic websites. This isn't a replacement for Playwright. Playwright remains an excellent choice for deterministic browser testing, especially when engineers can use stable role locators, text locators, or test IDs. BrowserAct solves a different problem: it helps AI agents operate unfamiliar or constantly changing websites by making decisions from the current page state instead of relying on previously captured selectors. The two tools are complementary rather than competing solutions. Although BrowserAct handled the dynamic page updates, I still verified the final result explicitly. A successful interaction doesn't always mean the task completed correctly loading issues, authentication, or application state can still affect the outcome. That's why the final step validated the page content rather than assuming that the previous action had succeeded. This makes the workflow more reliable regardless of the browser automation framework being used. Today, with the help of Playwright, of course, you can write application testing, but you should understand that this practice is not ideal, especially for long-term testing of the application. Rewriting the code with new id, class, etc. will take time, when it is easier to configure the Browser layer using BrowserAct and simply work with interactivity, reading it from the browser page. You can write your thoughts about the new features in the comments, it will be interesting to read! If you'd like to learn more about the product, BrowserAct has a YouTube channel and a Discord account where you can discuss how the tool works. Official website: https://www.browseract.ai/Anthony BrowserAct GitHub: https://www.browseract.com/?co-from=Anthony&redirect=https://github.com/browser-act/skills/tree/main BrowserAct skill: https://github.com/browser-act/skills/tree/main/browser-act Affiliate program: https://www.browseract.com/affiliate 💎 Star BrowserAct ☆ Thanks for reading this article! ❤️
Key Takeaways
- •TL;DR Modern web applications change constantly
- •This story was reported by Dev.to, covering developments in the dev space.
- •AI advancements continue to reshape industries — read the full article on Dev.to for complete coverage.
📖 Continue reading the full article:
Read Full Article on Dev.to →


