[{"data":1,"prerenderedAt":4931},["ShallowReactive",2],{"/blog/agent-browser-vs-puppeteer-and-playwright":3,"related-/blog/agent-browser-vs-puppeteer-and-playwright":2475},{"id":4,"title":5,"authorId":6,"body":7,"category":2431,"created":2432,"description":2433,"extension":2434,"faqs":2435,"featurePriority":2451,"head":2452,"landingPath":2452,"meta":2453,"navigation":1094,"ogImage":2452,"path":2467,"robots":2452,"schemaOrg":2452,"seo":2468,"sitemap":2469,"stem":2470,"tags":2471,"__hash__":2474},"blog/blog/1038.agent-browser-vs-puppeteer-and-playwright.md","Agent Browser vs. Puppeteer & Playwright","salome-koshadze",{"type":8,"value":9,"toc":2392},"minimark",[10,18,21,43,46,55,60,63,68,73,79,82,86,90,96,99,103,107,112,128,132,135,139,143,154,157,160,163,176,186,190,199,202,205,208,220,227,231,234,415,418,422,425,429,432,457,461,464,467,471,474,477,491,494,506,509,521,525,528,532,535,752,756,763,954,958,969,1203,1207,1210,1269,1273,1280,1397,1400,1404,1407,1415,1977,1984,2108,2116,2194,2200,2204,2207,2211,2214,2231,2235,2238,2242,2246,2249,2253,2256,2260,2263,2266,2270,2273,2276,2280,2283,2286,2290,2293,2297,2300,2304,2307,2351,2354,2358,2361,2378,2381,2388],[11,12,13,14],"p",{},"Choosing between Agent Browser, Puppeteer, and Playwright comes down to one question: ",[15,16,17],"strong",{},"are you building deterministic browser automation, or an AI agent that needs to interpret and adapt to live web pages?",[11,19,20],{},"Here is the short version:",[22,23,24,31,37],"ul",{},[25,26,27,30],"li",{},[15,28,29],{},"Choose Playwright"," if you need the most reliable option for testing, cross-browser automation, and repeatable multi-step workflows.",[25,32,33,36],{},[15,34,35],{},"Choose Puppeteer"," if you want lightweight Chromium automation with direct Chrome DevTools Protocol control.",[25,38,39,42],{},[15,40,41],{},"Choose Vercel agent-browser"," if you are building LLM-driven agents and care about compact page state, persistent sessions, and lower token overhead.",[11,44,45],{},"This guide compares all three tools across architecture, browser support, developer ergonomics, LLM-readiness, and real-world tradeoffs so you can choose the right one for your workflow.",[47,48],"nuxt-picture",{":width":49,"alt":50,"format":51,"loading":52,"src":53,"provider":54},"900","Agent Browser vs Puppeteer and Playwright comparison overview","webp","eager","/blog/agent-browser-vs-puppeteer-and-playwright/1.svg","none",[56,57,59],"h2",{"id":58},"tool-overviews-key-facts","Tool Overviews & Key Facts",[11,61,62],{},"Web automation tools currently show a division between those that require precise, scripted commands and those built for higher-level, goal-oriented interactions, often working with artificial intelligence agents. This section details the core characteristics and capabilities of Puppeteer and Playwright, alongside the newer \"Agent Browser\" solution from Vercel Labs, providing an initial understanding of each tool.",[64,65,67],"h3",{"id":66},"puppeteer","Puppeteer",[47,69],{":width":49,"alt":70,"format":51,"loading":71,"src":72},"Puppeteer GitHub repository","lazy","/blog/agent-browser-vs-puppeteer-and-playwright/puppeteer-github.png",[11,74,75,76,78],{},"Google launched ",[15,77,67],{}," in 2017 as a Node.js library designed for controlling Chrome and Chromium browsers. It operates by communicating directly with the browser through the Chrome DevTools Protocol (CDP), offering low-level access to browser functions. While primarily focused on Chromium, it also extended support to Firefox later. Its API is exclusive to JavaScript and TypeScript development environments.",[11,80,81],{},"The tool has a sizable community, reflected by approximately 94,000 stars on GitHub and millions of weekly npm downloads for its various core packages. Puppeteer is recognized for its maturity, its relatively light operational footprint when performing Chromium-specific tasks, and its direct access to browser internals. Its common uses include web scraping, generating PDF documents or screenshots, and performing basic, repeatable browser automation routines.",[64,83,85],{"id":84},"playwright","Playwright",[47,87],{":width":49,"alt":88,"format":51,"loading":71,"src":89},"Playwright GitHub repository","/blog/agent-browser-vs-puppeteer-and-playwright/playwright-github.png",[11,91,92,93,95],{},"Microsoft introduced ",[15,94,85],{}," in 2020, aiming to provide a unified API for browser automation and testing across multiple browser engines. It supports Chromium, Firefox, and WebKit (Safari), allowing developers to write code once and run it across these different browsers. Playwright extends its API language support beyond JavaScript and TypeScript to include Python, Java, and .NET, serving a broader developer audience.",[11,97,98],{},"Playwright has achieved considerable growth, with about 85,000 stars on GitHub and over 3.2 million weekly npm downloads, indicating its increasing adoption. Its major capabilities include automatic waiting for elements, which helps reduce script flakiness, and the use of browser contexts for efficient and lightweight session isolation. It also features a built-in test runner, tracing tools for debugging, and extensive device emulation options. Playwright is frequently used for end-to-end testing, automating complex web workflows, and ensuring cross-browser compatibility.",[64,100,102],{"id":101},"vercel-agent-browser","Vercel agent-browser",[47,104],{":width":49,"alt":105,"format":51,"loading":71,"src":106},"Vercel agent-browser GitHub repository","/blog/agent-browser-vs-puppeteer-and-playwright/agent-browser-github.png",[11,108,109,111],{},[15,110,102],{}," is a native Rust-based command-line interface (CLI) and daemon, specifically designed for AI agents. Released in 2026, it undergoes rapid development, with version 0.23.x available as of late March 2026. This tool establishes direct communication via CDP, removing dependencies on Node.js or Playwright, although it can detect and use existing browser installations. Its client-daemon architecture allows for persistent browsing sessions.",[11,113,114,115,119,120,123,124,127],{},"The tool's main innovation lies in its ",[116,117,118],"code",{},"snapshot"," capability. This command generates a compact accessibility tree, which is a lightweight representation of the page content. Within this tree, interactive elements are assigned ",[116,121,122],{},"@refs"," (e.g., ",[116,125,126],{},"@e1","), allowing AI agents to refer to and interact with them precisely. This method can use substantially fewer tokens than passing raw DOM or verbose page output into a large language model. Optional annotated screenshots provide visual context. While newer, its GitHub presence suggests strong early community interest. Its primary application is to enable LLM-driven agents, such as those powered by Claude or Cursor, to perform web tasks with a page representation that is easier for models to consume.",[64,129,131],{"id":130},"adoption-snapshot-2026","Adoption Snapshot (2026)",[11,133,134],{},"As of 2026, Puppeteer and Playwright maintain a major share in scripted automation and testing, together accumulating over 170,000 GitHub stars and millions of weekly downloads. Vercel's Agent Browser is quickly gaining acceptance, particularly in AI agent, Robotic Process Automation (RPA), and specialized scraping fields, partly due to the increasing difficulty of bypassing anti-bot systems. Vercel's tool focuses on agent-first designs that require minimal context.",[47,136],{":width":49,"alt":137,"format":51,"loading":71,"src":138,"provider":54},"Adoption snapshot of web automation tools in 2026","/blog/agent-browser-vs-puppeteer-and-playwright/2.svg",[56,140,142],{"id":141},"agent-browser-vs-playwright","Agent Browser vs Playwright",[11,144,145,146,149,150,153],{},"For most teams, ",[15,147,148],{},"Playwright is the better choice for deterministic automation",", while ",[15,151,152],{},"Vercel agent-browser is the better fit for open-ended AI agent workflows",".",[11,155,156],{},"Playwright is designed for engineers who want repeatable scripts, strong debugging tools, and support across Chromium, Firefox, and WebKit. If your workflow can be described as a stable sequence of steps-open page, click selector, fill form, assert result-Playwright is usually the safer and more maintainable option.",[11,158,159],{},"Vercel agent-browser takes a different approach. Instead of exposing the full browser primarily through selectors and scripted assertions, it is designed to give language models a compact representation of the page and stable references to interactive elements. That makes it more natural for agents that need to inspect, decide, and adapt from step to step.",[11,161,162],{},"In practice, the tradeoff looks like this:",[22,164,165,170],{},[25,166,167,169],{},[15,168,29],{}," for end-to-end testing, CI pipelines, cross-browser coverage, trace-based debugging, and deterministic production automation.",[25,171,172,175],{},[15,173,174],{},"Choose agent-browser"," for agent loops, research assistants, adaptive form completion, and workflows where the next action depends on interpreting live page state.",[11,177,178,179,182,183,153],{},"The key question is not which tool is universally better. It is whether your system is driven by ",[15,180,181],{},"predefined scripts"," or by ",[15,184,185],{},"model reasoning over changing page context",[56,187,189],{"id":188},"agent-browser-vs-puppeteer","Agent Browser vs Puppeteer",[11,191,192,193,195,196,198],{},"The difference between ",[15,194,67],{}," and ",[15,197,102],{}," is narrower at the browser-engine level, but wider at the workflow level.",[11,200,201],{},"Puppeteer gives developers direct programmatic control over Chromium through a JavaScript API. That makes it a strong fit for scraping jobs, PDF generation, screenshots, and scripted browser tasks where you want tight control over each step.",[11,203,204],{},"Vercel agent-browser is aimed at a different layer. Instead of asking a developer to manage selectors and browser actions directly in code, it exposes page state in a way that is easier for language models to interpret and act on. That makes it better suited to agent workflows where the path is not fully known in advance.",[11,206,207],{},"In practical terms:",[22,209,210,215],{},[25,211,212,214],{},[15,213,35],{}," if your automation is Chromium-only, code-driven, and best expressed as a deterministic script.",[25,216,217,219],{},[15,218,174],{}," if your workflow is agent-driven, changes from page to page, or needs a browser interface optimized for model reasoning rather than raw DOM control.",[11,221,222,223,226],{},"If your question is whether agent-browser can replace Puppeteer, the answer is ",[15,224,225],{},"not entirely",". Puppeteer remains the better tool for low-level scripted automation, while agent-browser is more useful when the browser is just one part of an adaptive AI system.",[56,228,230],{"id":229},"feature-comparison-matrix","Feature Comparison Matrix",[11,232,233],{},"Selecting the most suitable web automation tool often depends on specific project needs, ranging from simple scripting to complex, agent-driven tasks. The following table offers a detailed comparison across various features, highlighting how each tool addresses different aspects of browser automation.",[235,236,237,254],"table",{},[238,239,240],"thead",{},[241,242,243,248,250,252],"tr",{},[244,245,247],"th",{"align":246},"left","Feature",[244,249,67],{"align":246},[244,251,85],{"align":246},[244,253,102],{"align":246},[255,256,257,274,290,306,321,337,353,369,385,400],"tbody",{},[241,258,259,265,268,271],{},[260,261,262],"td",{"align":246},[15,263,264],{},"Browser Support",[260,266,267],{"align":246},"Chromium primary (Firefox)",[260,269,270],{"align":246},"Chromium, Firefox, WebKit",[260,272,273],{"align":246},"Chromium (CDP; detects others)",[241,275,276,281,284,287],{},[260,277,278],{"align":246},[15,279,280],{},"Languages/API",[260,282,283],{"align":246},"JS/TS only",[260,285,286],{"align":246},"Multi-language",[260,288,289],{"align":246},"Shell/CLI (any LLM that runs commands)",[241,291,292,297,300,303],{},[260,293,294],{"align":246},[15,295,296],{},"Control Style",[260,298,299],{"align":246},"Imperative selectors/steps",[260,301,302],{"align":246},"Imperative + auto-wait",[260,304,305],{"align":246},"Ref-based snapshots + semantic find",[241,307,308,313,316,318],{},[260,309,310],{"align":246},[15,311,312],{},"Stealth/Anti-Bot",[260,314,315],{"align":246},"Manual (plugins, proxies, custom hardening)",[260,317,315],{"align":246},[260,319,320],{"align":246},"Agent-oriented workflow; anti-bot claims vary by setup",[241,322,323,328,331,334],{},[260,324,325],{"align":246},[15,326,327],{},"Session Management",[260,329,330],{"align":246},"Manual (cookies, storage)",[260,332,333],{"align":246},"Contexts + manual",[260,335,336],{"align":246},"Persistent daemon + storage commands",[241,338,339,344,347,350],{},[260,340,341],{"align":246},[15,342,343],{},"AI/LLM Optimization",[260,345,346],{"align":246},"Limited by default; often needs custom abstraction",[260,348,349],{"align":246},"Moderate; can expose structured page state",[260,351,352],{"align":246},"High; designed for compact agent-readable page state",[241,354,355,360,363,366],{},[260,356,357],{"align":246},[15,358,359],{},"Scalability",[260,361,362],{"align":246},"Self-managed instances",[260,364,365],{"align":246},"Browser contexts (efficient)",[260,367,368],{"align":246},"Local daemon; can be paired with browser infrastructure",[241,370,371,376,379,382],{},[260,372,373],{"align":246},[15,374,375],{},"Performance Overhead",[260,377,378],{"align":246},"Low for Chromium-only workflows",[260,380,381],{"align":246},"Low-medium depending on browser and tooling",[260,383,384],{"align":246},"Low at the tooling layer; overall runtime depends on agent loop",[241,386,387,392,395,397],{},[260,388,389],{"align":246},[15,390,391],{},"Offline/Local",[260,393,394],{"align":246},"Yes",[260,396,394],{"align":246},[260,398,399],{"align":246},"Yes (local daemon)",[241,401,402,407,410,412],{},[260,403,404],{"align":246},[15,405,406],{},"Pricing",[260,408,409],{"align":246},"Free",[260,411,409],{"align":246},[260,413,414],{"align":246},"Free (open-source)",[11,416,417],{},"The table above illustrates distinct approaches each tool takes regarding core capabilities like browser compatibility and control mechanisms. It also brings attention to differences in stealth features, AI optimization, and deployment models, which range from local open-source solutions to managed cloud services.",[56,419,421],{"id":420},"performance-reliability-data","Performance & Reliability Data",[11,423,424],{},"Understanding the speed and dependability of web automation tools is important for any project, particularly when dealing with large-scale operations or time-sensitive tasks. The performance characteristics vary considerably across Puppeteer, Playwright, and Vercel agent-browser, influenced by their design and deployment models.",[64,426,428],{"id":427},"speed-benchmarks","Speed Benchmarks",[11,430,431],{},"Various tests conducted between 2025 and 2026 provide insights into the execution speed of these tools. The data indicates different strengths based on the complexity of the automation task.",[22,433,434,440,446,451],{},[25,435,436,439],{},[15,437,438],{},"Simple Chrome Scripts/Navigation",": Puppeteer is often viewed as lean and effective for straightforward Chromium automation, especially when you do not need cross-browser support.",[25,441,442,445],{},[15,443,444],{},"Complex/End-to-End/Multi-page",": Playwright is widely regarded as the more robust option for larger automation suites because of its auto-waiting, tracing, and browser context model.",[25,447,448,450],{},[15,449,102],{},": This tool adds overhead from model-driven decision-making and snapshot generation, but its workflow can be more adaptive when tasks are not easily expressed as a fixed selector script.",[25,452,453,456],{},[15,454,455],{},"Scaling",": Playwright's browser contexts prove more efficient for scaling than Puppeteer's approach of launching separate browser instances. Vercel agent-browser, when integrated with cloud providers like Browserbase, can also support increased concurrency.",[64,458,460],{"id":459},"reliability","Reliability",[11,462,463],{},"The dependability of web automation tools is strongly influenced by how they handle dynamic web content and anti-bot measures. Traditional scripting tools often face challenges when website interfaces change, while agentic tools aim for greater resilience.",[11,465,466],{},"Traditional automation scripts can be brittle, with manual selectors frequently breaking due to UI alterations. Vercel agent-browser, with its use of references or AI reasoning based on snapshots, can be more adaptive to such changes. This adaptability, however, can also introduce non-determinism or errors linked to AI processing. On highly protected sites, both Puppeteer and Playwright usually require extra work around proxies, fingerprinting, and traffic patterns rather than succeeding out of the box.",[56,468,470],{"id":469},"pros-cons","Pros & Cons",[11,472,473],{},"Each web automation tool offers a distinct set of advantages and disadvantages, making them more or less suitable for different project requirements. Understanding these points is important for choosing the right solution.",[64,475,67],{"id":476},"puppeteer-1",[22,478,479,485],{},[25,480,481,484],{},[15,482,483],{},"Pros",": It is fast and straightforward for tasks involving Chromium, benefits from a mature ecosystem, and provides deep control through the Chrome DevTools Protocol.",[25,486,487,490],{},[15,488,489],{},"Cons",": Its focus is primarily on Chromium, it is limited to JavaScript environments, and it requires manual effort for waits and stealth features, making it difficult to scale while maintaining stealth.",[64,492,85],{"id":493},"playwright-1",[22,495,496,501],{},[25,497,498,500],{},[15,499,483],{},": Offers cross-browser compatibility, includes auto-wait capabilities which lead to less flaky scripts, supports multiple programming languages, provides excellent testing tools, and uses efficient browser contexts.",[25,502,503,505],{},[15,504,489],{},": Still requires additional plugins or custom setups for robust stealth and proxy integration at scale; it also has a slightly heavier startup overhead compared to Puppeteer.",[64,507,102],{"id":508},"vercel-agent-browser-1",[22,510,511,516],{},[25,512,513,515],{},[15,514,483],{},": Optimized for Large Language Models (LLMs) with low token usage, element references, and semantic locators; delivers native speed due to its Rust implementation; features a persistent daemon for continuous operation; includes security measures; and has no Node.js dependency.",[25,517,518,520],{},[15,519,489],{},": It is a newer tool, which means it is less mature than Puppeteer or Playwright; its focus is CLI-centric, providing less of a traditional \"library\" feel; and its primary browser support is for Chromium.",[56,522,524],{"id":523},"hands-on-code-examples","Hands-On Code Examples",[11,526,527],{},"To illustrate the practical application of each tool, the following code snippets demonstrate basic actions such as navigating to a web page and extracting content. These examples highlight the different syntaxes and approaches taken by Puppeteer, Playwright, and Vercel agent-browser.",[64,529,531],{"id":530},"puppeteer-basic-navigation-content","Puppeteer (basic navigation + content)",[11,533,534],{},"This example shows how to launch a Chromium browser, open a new page, navigate to a URL, and retrieve the page's HTML content using Puppeteer.",[536,537,542],"pre",{"className":538,"code":539,"language":540,"meta":541,"style":541},"language-javascript shiki shiki-themes catppuccin-latte night-owl","const puppeteer = require(\"puppeteer\");\n(async () => {\n  const browser = await puppeteer.launch();\n  const page = await browser.newPage();\n  await page.goto(\"https://example.com\");\n  const html = await page.content();\n  console.log(html);\n  await browser.close();\n})();\n","javascript","",[116,543,544,585,604,632,655,681,704,725,741],{"__ignoreMap":541},[545,546,549,553,557,561,565,569,573,576,578,581],"span",{"class":547,"line":548},"line",1,[545,550,552],{"class":551},"s76yb","const",[545,554,556],{"class":555},"scsc5"," puppeteer",[545,558,560],{"class":559},"s-_ek"," =",[545,562,564],{"class":563},"sNstc"," require",[545,566,568],{"class":567},"s2kId","(",[545,570,572],{"class":571},"sbuKk","\"",[545,574,66],{"class":575},"sfrMT",[545,577,572],{"class":571},[545,579,580],{"class":567},")",[545,582,584],{"class":583},"scGhl",";\n",[545,586,588,590,594,598,601],{"class":547,"line":587},2,[545,589,568],{"class":567},[545,591,593],{"class":592},"srhcd","async",[545,595,597],{"class":596},"sMtgK"," ()",[545,599,600],{"class":551}," =>",[545,602,603],{"class":583}," {\n",[545,605,607,610,613,615,618,621,624,627,630],{"class":547,"line":606},3,[545,608,609],{"class":551},"  const",[545,611,612],{"class":555}," browser",[545,614,560],{"class":559},[545,616,617],{"class":592}," await",[545,619,556],{"class":620},"sP4PM",[545,622,153],{"class":623},"s5FwJ",[545,625,626],{"class":563},"launch",[545,628,629],{"class":567},"()",[545,631,584],{"class":583},[545,633,635,637,640,642,644,646,648,651,653],{"class":547,"line":634},4,[545,636,609],{"class":551},[545,638,639],{"class":555}," page",[545,641,560],{"class":559},[545,643,617],{"class":592},[545,645,612],{"class":620},[545,647,153],{"class":623},[545,649,650],{"class":563},"newPage",[545,652,629],{"class":567},[545,654,584],{"class":583},[545,656,658,661,663,665,668,670,672,675,677,679],{"class":547,"line":657},5,[545,659,660],{"class":592},"  await",[545,662,639],{"class":620},[545,664,153],{"class":623},[545,666,667],{"class":563},"goto",[545,669,568],{"class":567},[545,671,572],{"class":571},[545,673,674],{"class":575},"https://example.com",[545,676,572],{"class":571},[545,678,580],{"class":567},[545,680,584],{"class":583},[545,682,684,686,689,691,693,695,697,700,702],{"class":547,"line":683},6,[545,685,609],{"class":551},[545,687,688],{"class":555}," html",[545,690,560],{"class":559},[545,692,617],{"class":592},[545,694,639],{"class":620},[545,696,153],{"class":623},[545,698,699],{"class":563},"content",[545,701,629],{"class":567},[545,703,584],{"class":583},[545,705,707,710,712,715,717,721,723],{"class":547,"line":706},7,[545,708,709],{"class":620},"  console",[545,711,153],{"class":623},[545,713,714],{"class":563},"log",[545,716,568],{"class":567},[545,718,720],{"class":719},"soAP-","html",[545,722,580],{"class":567},[545,724,584],{"class":583},[545,726,728,730,732,734,737,739],{"class":547,"line":727},8,[545,729,660],{"class":592},[545,731,612],{"class":620},[545,733,153],{"class":623},[545,735,736],{"class":563},"close",[545,738,629],{"class":567},[545,740,584],{"class":583},[545,742,744,747,750],{"class":547,"line":743},9,[545,745,746],{"class":583},"}",[545,748,749],{"class":567},")()",[545,751,584],{"class":583},[64,753,755],{"id":754},"playwright-cross-browser-auto-wait","Playwright (cross-browser + auto-wait)",[11,757,758,759,762],{},"The Playwright example demonstrates launching a Chromium browser, navigating to a URL with a ",[116,760,761],{},"waitUntil"," option to ensure page load completeness, and extracting the page title. Playwright's API is designed for consistency across different browsers.",[536,764,766],{"className":538,"code":765,"language":540,"meta":541,"style":541},"const { chromium } = require(\"playwright\");\n(async () => {\n  const browser = await chromium.launch();\n  const page = await browser.newPage();\n  await page.goto(\"https://example.com\", { waitUntil: \"networkidle\" });\n  const title = await page.title();\n  console.log(title);\n  await browser.close();\n})();\n",[116,767,768,798,810,830,850,894,916,932,946],{"__ignoreMap":541},[545,769,770,772,776,779,782,784,786,788,790,792,794,796],{"class":547,"line":548},[545,771,552],{"class":551},[545,773,775],{"class":774},"sgNGR"," {",[545,777,778],{"class":555}," chromium",[545,780,781],{"class":774}," }",[545,783,560],{"class":559},[545,785,564],{"class":563},[545,787,568],{"class":567},[545,789,572],{"class":571},[545,791,84],{"class":575},[545,793,572],{"class":571},[545,795,580],{"class":567},[545,797,584],{"class":583},[545,799,800,802,804,806,808],{"class":547,"line":587},[545,801,568],{"class":567},[545,803,593],{"class":592},[545,805,597],{"class":596},[545,807,600],{"class":551},[545,809,603],{"class":583},[545,811,812,814,816,818,820,822,824,826,828],{"class":547,"line":606},[545,813,609],{"class":551},[545,815,612],{"class":555},[545,817,560],{"class":559},[545,819,617],{"class":592},[545,821,778],{"class":620},[545,823,153],{"class":623},[545,825,626],{"class":563},[545,827,629],{"class":567},[545,829,584],{"class":583},[545,831,832,834,836,838,840,842,844,846,848],{"class":547,"line":634},[545,833,609],{"class":551},[545,835,639],{"class":555},[545,837,560],{"class":559},[545,839,617],{"class":592},[545,841,612],{"class":620},[545,843,153],{"class":623},[545,845,650],{"class":563},[545,847,629],{"class":567},[545,849,584],{"class":583},[545,851,852,854,856,858,860,862,864,866,868,871,873,876,880,883,886,888,890,892],{"class":547,"line":657},[545,853,660],{"class":592},[545,855,639],{"class":620},[545,857,153],{"class":623},[545,859,667],{"class":563},[545,861,568],{"class":567},[545,863,572],{"class":571},[545,865,674],{"class":575},[545,867,572],{"class":571},[545,869,870],{"class":583},",",[545,872,775],{"class":583},[545,874,875],{"class":567}," waitUntil",[545,877,879],{"class":878},"sVS64",":",[545,881,882],{"class":571}," \"",[545,884,885],{"class":575},"networkidle",[545,887,572],{"class":571},[545,889,781],{"class":583},[545,891,580],{"class":567},[545,893,584],{"class":583},[545,895,896,898,901,903,905,907,909,912,914],{"class":547,"line":683},[545,897,609],{"class":551},[545,899,900],{"class":555}," title",[545,902,560],{"class":559},[545,904,617],{"class":592},[545,906,639],{"class":620},[545,908,153],{"class":623},[545,910,911],{"class":563},"title",[545,913,629],{"class":567},[545,915,584],{"class":583},[545,917,918,920,922,924,926,928,930],{"class":547,"line":706},[545,919,709],{"class":620},[545,921,153],{"class":623},[545,923,714],{"class":563},[545,925,568],{"class":567},[545,927,911],{"class":719},[545,929,580],{"class":567},[545,931,584],{"class":583},[545,933,934,936,938,940,942,944],{"class":547,"line":727},[545,935,660],{"class":592},[545,937,612],{"class":620},[545,939,153],{"class":623},[545,941,736],{"class":563},[545,943,629],{"class":567},[545,945,584],{"class":583},[545,947,948,950,952],{"class":547,"line":743},[545,949,746],{"class":583},[545,951,749],{"class":567},[545,953,584],{"class":583},[64,955,957],{"id":956},"playwright-accessibility-snapshot-for-llm-input","Playwright (accessibility snapshot for LLM input)",[11,959,960,961,964,965,968],{},"When feeding page state to a language model, use ",[116,962,963],{},"ariaSnapshot()"," instead of ",[116,966,967],{},"page.content()",". It returns a compact YAML accessibility tree rather than raw HTML, which is significantly more token-efficient.",[536,970,972],{"className":538,"code":971,"language":540,"meta":541,"style":541},"const { chromium } = require(\"playwright\");\n(async () => {\n  const browser = await chromium.launch();\n  const page = await browser.newPage();\n  await page.goto(\"https://example.com\", { waitUntil: \"networkidle\" });\n\n  // Pass this to your LLM instead of page.content()\n  const snapshot = await page.locator(\"body\").ariaSnapshot();\n  console.log(snapshot);\n  // - heading \"Example Domain\" [level=1]\n  // - paragraph: This domain is for use in illustrative examples in documents.\n  // - link \"More information...\"\n\n  await browser.close();\n})();\n",[116,973,974,1000,1012,1032,1052,1090,1096,1102,1140,1156,1162,1168,1174,1179,1194],{"__ignoreMap":541},[545,975,976,978,980,982,984,986,988,990,992,994,996,998],{"class":547,"line":548},[545,977,552],{"class":551},[545,979,775],{"class":774},[545,981,778],{"class":555},[545,983,781],{"class":774},[545,985,560],{"class":559},[545,987,564],{"class":563},[545,989,568],{"class":567},[545,991,572],{"class":571},[545,993,84],{"class":575},[545,995,572],{"class":571},[545,997,580],{"class":567},[545,999,584],{"class":583},[545,1001,1002,1004,1006,1008,1010],{"class":547,"line":587},[545,1003,568],{"class":567},[545,1005,593],{"class":592},[545,1007,597],{"class":596},[545,1009,600],{"class":551},[545,1011,603],{"class":583},[545,1013,1014,1016,1018,1020,1022,1024,1026,1028,1030],{"class":547,"line":606},[545,1015,609],{"class":551},[545,1017,612],{"class":555},[545,1019,560],{"class":559},[545,1021,617],{"class":592},[545,1023,778],{"class":620},[545,1025,153],{"class":623},[545,1027,626],{"class":563},[545,1029,629],{"class":567},[545,1031,584],{"class":583},[545,1033,1034,1036,1038,1040,1042,1044,1046,1048,1050],{"class":547,"line":634},[545,1035,609],{"class":551},[545,1037,639],{"class":555},[545,1039,560],{"class":559},[545,1041,617],{"class":592},[545,1043,612],{"class":620},[545,1045,153],{"class":623},[545,1047,650],{"class":563},[545,1049,629],{"class":567},[545,1051,584],{"class":583},[545,1053,1054,1056,1058,1060,1062,1064,1066,1068,1070,1072,1074,1076,1078,1080,1082,1084,1086,1088],{"class":547,"line":657},[545,1055,660],{"class":592},[545,1057,639],{"class":620},[545,1059,153],{"class":623},[545,1061,667],{"class":563},[545,1063,568],{"class":567},[545,1065,572],{"class":571},[545,1067,674],{"class":575},[545,1069,572],{"class":571},[545,1071,870],{"class":583},[545,1073,775],{"class":583},[545,1075,875],{"class":567},[545,1077,879],{"class":878},[545,1079,882],{"class":571},[545,1081,885],{"class":575},[545,1083,572],{"class":571},[545,1085,781],{"class":583},[545,1087,580],{"class":567},[545,1089,584],{"class":583},[545,1091,1092],{"class":547,"line":683},[545,1093,1095],{"emptyLinePlaceholder":1094},true,"\n",[545,1097,1098],{"class":547,"line":706},[545,1099,1101],{"class":1100},"sDmS1","  // Pass this to your LLM instead of page.content()\n",[545,1103,1104,1106,1109,1111,1113,1115,1117,1120,1122,1124,1127,1129,1131,1133,1136,1138],{"class":547,"line":727},[545,1105,609],{"class":551},[545,1107,1108],{"class":555}," snapshot",[545,1110,560],{"class":559},[545,1112,617],{"class":592},[545,1114,639],{"class":620},[545,1116,153],{"class":623},[545,1118,1119],{"class":563},"locator",[545,1121,568],{"class":567},[545,1123,572],{"class":571},[545,1125,1126],{"class":575},"body",[545,1128,572],{"class":571},[545,1130,580],{"class":567},[545,1132,153],{"class":623},[545,1134,1135],{"class":563},"ariaSnapshot",[545,1137,629],{"class":567},[545,1139,584],{"class":583},[545,1141,1142,1144,1146,1148,1150,1152,1154],{"class":547,"line":743},[545,1143,709],{"class":620},[545,1145,153],{"class":623},[545,1147,714],{"class":563},[545,1149,568],{"class":567},[545,1151,118],{"class":719},[545,1153,580],{"class":567},[545,1155,584],{"class":583},[545,1157,1159],{"class":547,"line":1158},10,[545,1160,1161],{"class":1100},"  // - heading \"Example Domain\" [level=1]\n",[545,1163,1165],{"class":547,"line":1164},11,[545,1166,1167],{"class":1100},"  // - paragraph: This domain is for use in illustrative examples in documents.\n",[545,1169,1171],{"class":547,"line":1170},12,[545,1172,1173],{"class":1100},"  // - link \"More information...\"\n",[545,1175,1177],{"class":547,"line":1176},13,[545,1178,1095],{"emptyLinePlaceholder":1094},[545,1180,1182,1184,1186,1188,1190,1192],{"class":547,"line":1181},14,[545,1183,660],{"class":592},[545,1185,612],{"class":620},[545,1187,153],{"class":623},[545,1189,736],{"class":563},[545,1191,629],{"class":567},[545,1193,584],{"class":583},[545,1195,1197,1199,1201],{"class":547,"line":1196},15,[545,1198,746],{"class":583},[545,1200,749],{"class":567},[545,1202,584],{"class":583},[64,1204,1206],{"id":1205},"vercel-agent-browser-ai-friendly-snapshot-ref-interaction","Vercel agent-browser (AI-friendly snapshot + ref interaction)",[11,1208,1209],{},"Vercel agent-browser operates via shell commands, making it suitable for direct execution by LLMs or in scripts. This example shows opening a URL, taking a snapshot with references, and performing a click using one of these references.",[536,1211,1215],{"className":1212,"code":1213,"language":1214,"meta":541,"style":541},"language-bash shiki shiki-themes catppuccin-latte night-owl","  # Terminal/LLM shell commands\n  agent-browser open https://example.com\n  agent-browser snapshot -i   # Returns: heading \"Example Domain\" [ref=e1] ...\n  agent-browser click @e2      # Deterministic click via ref\n  agent-browser screenshot result.png\n","bash",[116,1216,1217,1222,1233,1246,1259],{"__ignoreMap":541},[545,1218,1219],{"class":547,"line":548},[545,1220,1221],{"class":1100},"  # Terminal/LLM shell commands\n",[545,1223,1224,1227,1230],{"class":547,"line":587},[545,1225,1226],{"class":563},"  agent-browser",[545,1228,1229],{"class":575}," open",[545,1231,1232],{"class":575}," https://example.com\n",[545,1234,1235,1237,1239,1243],{"class":547,"line":606},[545,1236,1226],{"class":563},[545,1238,1108],{"class":575},[545,1240,1242],{"class":1241},"sPg8w"," -i",[545,1244,1245],{"class":1100},"   # Returns: heading \"Example Domain\" [ref=e1] ...\n",[545,1247,1248,1250,1253,1256],{"class":547,"line":634},[545,1249,1226],{"class":563},[545,1251,1252],{"class":575}," click",[545,1254,1255],{"class":575}," @e2",[545,1257,1258],{"class":1100},"      # Deterministic click via ref\n",[545,1260,1261,1263,1266],{"class":547,"line":657},[545,1262,1226],{"class":563},[545,1264,1265],{"class":575}," screenshot",[545,1267,1268],{"class":575}," result.png\n",[64,1270,1272],{"id":1271},"batchai-workflow-vercel","Batch/AI workflow (Vercel)",[11,1274,1275,1276,1279],{},"Vercel agent-browser supports chaining commands across multiple steps, which is the natural pattern for an agent loop. Each snapshot call reflects the current DOM state, and ",[116,1277,1278],{},"@ref"," labels remain stable within the session, so the agent can act on a ref it received two steps earlier without re-parsing.",[536,1281,1285],{"className":1282,"code":1283,"language":1284,"meta":541,"style":541},"language-shell shiki shiki-themes catppuccin-latte night-owl","# Multi-step agent loop: switch pricing tier and extract updated values\nagent-browser open https://example-saas.com/pricing\n\nagent-browser snapshot -i\n# Output (~260 tokens):\n# heading \"Pricing\" [ref=e1]\n# button \"Monthly\" [ref=e2]\n# button \"Annual\" [ref=e3]\n# text \"Starter - $29/mo\" [ref=e4]\n# text \"Pro - $99/mo\" [ref=e5]\n\nagent-browser click @e3          # Switch to annual billing\nagent-browser snapshot -i        # Re-snapshot after DOM update\n# text \"Starter - $290/yr\" [ref=e4]\n# text \"Pro - $990/yr\" [ref=e5]\n\nagent-browser screenshot pricing-annual.png\n","shell",[116,1286,1287,1292,1302,1306,1315,1320,1325,1330,1335,1340,1345,1349,1361,1372,1377,1382,1387],{"__ignoreMap":541},[545,1288,1289],{"class":547,"line":548},[545,1290,1291],{"class":1100},"# Multi-step agent loop: switch pricing tier and extract updated values\n",[545,1293,1294,1297,1299],{"class":547,"line":587},[545,1295,1296],{"class":563},"agent-browser",[545,1298,1229],{"class":575},[545,1300,1301],{"class":575}," https://example-saas.com/pricing\n",[545,1303,1304],{"class":547,"line":606},[545,1305,1095],{"emptyLinePlaceholder":1094},[545,1307,1308,1310,1312],{"class":547,"line":634},[545,1309,1296],{"class":563},[545,1311,1108],{"class":575},[545,1313,1314],{"class":1241}," -i\n",[545,1316,1317],{"class":547,"line":657},[545,1318,1319],{"class":1100},"# Output (~260 tokens):\n",[545,1321,1322],{"class":547,"line":683},[545,1323,1324],{"class":1100},"# heading \"Pricing\" [ref=e1]\n",[545,1326,1327],{"class":547,"line":706},[545,1328,1329],{"class":1100},"# button \"Monthly\" [ref=e2]\n",[545,1331,1332],{"class":547,"line":727},[545,1333,1334],{"class":1100},"# button \"Annual\" [ref=e3]\n",[545,1336,1337],{"class":547,"line":743},[545,1338,1339],{"class":1100},"# text \"Starter - $29/mo\" [ref=e4]\n",[545,1341,1342],{"class":547,"line":1158},[545,1343,1344],{"class":1100},"# text \"Pro - $99/mo\" [ref=e5]\n",[545,1346,1347],{"class":547,"line":1164},[545,1348,1095],{"emptyLinePlaceholder":1094},[545,1350,1351,1353,1355,1358],{"class":547,"line":1170},[545,1352,1296],{"class":563},[545,1354,1252],{"class":575},[545,1356,1357],{"class":575}," @e3",[545,1359,1360],{"class":1100},"          # Switch to annual billing\n",[545,1362,1363,1365,1367,1369],{"class":547,"line":1176},[545,1364,1296],{"class":563},[545,1366,1108],{"class":575},[545,1368,1242],{"class":1241},[545,1370,1371],{"class":1100},"        # Re-snapshot after DOM update\n",[545,1373,1374],{"class":547,"line":1181},[545,1375,1376],{"class":1100},"# text \"Starter - $290/yr\" [ref=e4]\n",[545,1378,1379],{"class":547,"line":1196},[545,1380,1381],{"class":1100},"# text \"Pro - $990/yr\" [ref=e5]\n",[545,1383,1385],{"class":547,"line":1384},16,[545,1386,1095],{"emptyLinePlaceholder":1094},[545,1388,1390,1392,1394],{"class":547,"line":1389},17,[545,1391,1296],{"class":563},[545,1393,1265],{"class":575},[545,1395,1396],{"class":575}," pricing-annual.png\n",[11,1398,1399],{},"Because the daemon stays alive between commands, there is no browser startup cost per step and cookie/session state persists automatically.",[64,1401,1403],{"id":1402},"what-each-format-produces","What each format produces",[11,1405,1406],{},"The token efficiency argument is easier to evaluate with a concrete example. Here is the same contact-form page represented in each format.",[11,1408,1409],{},[15,1410,1411,1412,1414],{},"Raw HTML - ",[116,1413,967],{}," in Puppeteer",[536,1416,1419],{"className":1417,"code":1418,"language":720,"meta":541,"style":541},"language-html shiki shiki-themes catppuccin-latte night-owl","\u003C!DOCTYPE html>\n\u003Chtml lang=\"en\">\n\u003Chead>\n  \u003Cmeta charset=\"UTF-8\">\n  \u003Cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \u003Ctitle>Contact Us\u003C/title>\n  \u003Clink rel=\"stylesheet\" href=\"/styles/main.css\">\n  \u003C!-- scripts, analytics tags, icon fonts ... -->\n\u003C/head>\n\u003Cbody>\n  \u003Cdiv class=\"page-wrapper\" id=\"root\">\n    \u003Cnav class=\"navbar navbar-expand-lg\">\n      \u003C!-- full navigation markup -->\n    \u003C/nav>\n    \u003Cmain class=\"container mt-5\">\n      \u003Cdiv class=\"row justify-content-center\">\n        \u003Cdiv class=\"col-md-6\">\n          \u003Cform id=\"contact-form\" action=\"/submit\" method=\"POST\">\n            \u003Cdiv class=\"form-group mb-3\">\n              \u003Clabel for=\"name\" class=\"form-label\">Your Name\u003C/label>\n              \u003Cinput type=\"text\" class=\"form-control\" id=\"name\" name=\"name\">\n            \u003C/div>\n            \u003C!-- email, message, button ... -->\n          \u003C/form>\n        \u003C/div>\n      \u003C/div>\n    \u003C/main>\n  \u003C/div>\n\u003C/body>\n\u003C/html>\n\u003C!-- Typical result: 20,000–100,000+ tokens for a real-world page -->\n",[116,1420,1421,1437,1461,1470,1492,1524,1543,1576,1581,1589,1597,1630,1651,1656,1665,1685,1705,1725,1771,1792,1835,1888,1898,1904,1914,1924,1934,1943,1953,1962,1971],{"__ignoreMap":541},[545,1422,1423,1427,1431,1434],{"class":547,"line":548},[545,1424,1426],{"class":1425},"sEaUw","\u003C!",[545,1428,1430],{"class":1429},"s18vy","DOCTYPE",[545,1432,688],{"class":1433},"swkLt",[545,1435,1436],{"class":1425},">\n",[545,1438,1439,1443,1446,1449,1452,1454,1457,1459],{"class":547,"line":587},[545,1440,1442],{"class":1441},"s9rnR","\u003C",[545,1444,720],{"class":1445},"sY2RG",[545,1447,1448],{"class":1433}," lang",[545,1450,1451],{"class":1441},"=",[545,1453,572],{"class":571},[545,1455,1456],{"class":575},"en",[545,1458,572],{"class":571},[545,1460,1436],{"class":1441},[545,1462,1463,1465,1468],{"class":547,"line":606},[545,1464,1442],{"class":1441},[545,1466,1467],{"class":1445},"head",[545,1469,1436],{"class":1441},[545,1471,1472,1475,1478,1481,1483,1485,1488,1490],{"class":547,"line":634},[545,1473,1474],{"class":1441},"  \u003C",[545,1476,1477],{"class":1445},"meta",[545,1479,1480],{"class":1433}," charset",[545,1482,1451],{"class":1441},[545,1484,572],{"class":571},[545,1486,1487],{"class":575},"UTF-8",[545,1489,572],{"class":571},[545,1491,1436],{"class":1441},[545,1493,1494,1496,1498,1501,1503,1505,1508,1510,1513,1515,1517,1520,1522],{"class":547,"line":657},[545,1495,1474],{"class":1441},[545,1497,1477],{"class":1445},[545,1499,1500],{"class":1433}," name",[545,1502,1451],{"class":1441},[545,1504,572],{"class":571},[545,1506,1507],{"class":575},"viewport",[545,1509,572],{"class":571},[545,1511,1512],{"class":1433}," content",[545,1514,1451],{"class":1441},[545,1516,572],{"class":571},[545,1518,1519],{"class":575},"width=device-width, initial-scale=1.0",[545,1521,572],{"class":571},[545,1523,1436],{"class":1441},[545,1525,1526,1528,1530,1533,1536,1539,1541],{"class":547,"line":683},[545,1527,1474],{"class":1441},[545,1529,911],{"class":1445},[545,1531,1532],{"class":1441},">",[545,1534,1535],{"class":567},"Contact Us",[545,1537,1538],{"class":1441},"\u003C/",[545,1540,911],{"class":1445},[545,1542,1436],{"class":1441},[545,1544,1545,1547,1550,1553,1555,1557,1560,1562,1565,1567,1569,1572,1574],{"class":547,"line":706},[545,1546,1474],{"class":1441},[545,1548,1549],{"class":1445},"link",[545,1551,1552],{"class":1433}," rel",[545,1554,1451],{"class":1441},[545,1556,572],{"class":571},[545,1558,1559],{"class":575},"stylesheet",[545,1561,572],{"class":571},[545,1563,1564],{"class":1433}," href",[545,1566,1451],{"class":1441},[545,1568,572],{"class":571},[545,1570,1571],{"class":575},"/styles/main.css",[545,1573,572],{"class":571},[545,1575,1436],{"class":1441},[545,1577,1578],{"class":547,"line":727},[545,1579,1580],{"class":1100},"  \u003C!-- scripts, analytics tags, icon fonts ... -->\n",[545,1582,1583,1585,1587],{"class":547,"line":743},[545,1584,1538],{"class":1441},[545,1586,1467],{"class":1445},[545,1588,1436],{"class":1441},[545,1590,1591,1593,1595],{"class":547,"line":1158},[545,1592,1442],{"class":1441},[545,1594,1126],{"class":1445},[545,1596,1436],{"class":1441},[545,1598,1599,1601,1604,1607,1609,1611,1614,1616,1619,1621,1623,1626,1628],{"class":547,"line":1164},[545,1600,1474],{"class":1441},[545,1602,1603],{"class":1445},"div",[545,1605,1606],{"class":1433}," class",[545,1608,1451],{"class":1441},[545,1610,572],{"class":571},[545,1612,1613],{"class":575},"page-wrapper",[545,1615,572],{"class":571},[545,1617,1618],{"class":1433}," id",[545,1620,1451],{"class":1441},[545,1622,572],{"class":571},[545,1624,1625],{"class":575},"root",[545,1627,572],{"class":571},[545,1629,1436],{"class":1441},[545,1631,1632,1635,1638,1640,1642,1644,1647,1649],{"class":547,"line":1170},[545,1633,1634],{"class":1441},"    \u003C",[545,1636,1637],{"class":1445},"nav",[545,1639,1606],{"class":1433},[545,1641,1451],{"class":1441},[545,1643,572],{"class":571},[545,1645,1646],{"class":575},"navbar navbar-expand-lg",[545,1648,572],{"class":571},[545,1650,1436],{"class":1441},[545,1652,1653],{"class":547,"line":1176},[545,1654,1655],{"class":1100},"      \u003C!-- full navigation markup -->\n",[545,1657,1658,1661,1663],{"class":547,"line":1181},[545,1659,1660],{"class":1441},"    \u003C/",[545,1662,1637],{"class":1445},[545,1664,1436],{"class":1441},[545,1666,1667,1669,1672,1674,1676,1678,1681,1683],{"class":547,"line":1196},[545,1668,1634],{"class":1441},[545,1670,1671],{"class":1445},"main",[545,1673,1606],{"class":1433},[545,1675,1451],{"class":1441},[545,1677,572],{"class":571},[545,1679,1680],{"class":575},"container mt-5",[545,1682,572],{"class":571},[545,1684,1436],{"class":1441},[545,1686,1687,1690,1692,1694,1696,1698,1701,1703],{"class":547,"line":1384},[545,1688,1689],{"class":1441},"      \u003C",[545,1691,1603],{"class":1445},[545,1693,1606],{"class":1433},[545,1695,1451],{"class":1441},[545,1697,572],{"class":571},[545,1699,1700],{"class":575},"row justify-content-center",[545,1702,572],{"class":571},[545,1704,1436],{"class":1441},[545,1706,1707,1710,1712,1714,1716,1718,1721,1723],{"class":547,"line":1389},[545,1708,1709],{"class":1441},"        \u003C",[545,1711,1603],{"class":1445},[545,1713,1606],{"class":1433},[545,1715,1451],{"class":1441},[545,1717,572],{"class":571},[545,1719,1720],{"class":575},"col-md-6",[545,1722,572],{"class":571},[545,1724,1436],{"class":1441},[545,1726,1728,1731,1734,1736,1738,1740,1743,1745,1748,1750,1752,1755,1757,1760,1762,1764,1767,1769],{"class":547,"line":1727},18,[545,1729,1730],{"class":1441},"          \u003C",[545,1732,1733],{"class":1445},"form",[545,1735,1618],{"class":1433},[545,1737,1451],{"class":1441},[545,1739,572],{"class":571},[545,1741,1742],{"class":575},"contact-form",[545,1744,572],{"class":571},[545,1746,1747],{"class":1433}," action",[545,1749,1451],{"class":1441},[545,1751,572],{"class":571},[545,1753,1754],{"class":575},"/submit",[545,1756,572],{"class":571},[545,1758,1759],{"class":1433}," method",[545,1761,1451],{"class":1441},[545,1763,572],{"class":571},[545,1765,1766],{"class":575},"POST",[545,1768,572],{"class":571},[545,1770,1436],{"class":1441},[545,1772,1774,1777,1779,1781,1783,1785,1788,1790],{"class":547,"line":1773},19,[545,1775,1776],{"class":1441},"            \u003C",[545,1778,1603],{"class":1445},[545,1780,1606],{"class":1433},[545,1782,1451],{"class":1441},[545,1784,572],{"class":571},[545,1786,1787],{"class":575},"form-group mb-3",[545,1789,572],{"class":571},[545,1791,1436],{"class":1441},[545,1793,1795,1798,1801,1804,1806,1808,1811,1813,1815,1817,1819,1822,1824,1826,1829,1831,1833],{"class":547,"line":1794},20,[545,1796,1797],{"class":1441},"              \u003C",[545,1799,1800],{"class":1445},"label",[545,1802,1803],{"class":1433}," for",[545,1805,1451],{"class":1441},[545,1807,572],{"class":571},[545,1809,1810],{"class":575},"name",[545,1812,572],{"class":571},[545,1814,1606],{"class":1433},[545,1816,1451],{"class":1441},[545,1818,572],{"class":571},[545,1820,1821],{"class":575},"form-label",[545,1823,572],{"class":571},[545,1825,1532],{"class":1441},[545,1827,1828],{"class":567},"Your Name",[545,1830,1538],{"class":1441},[545,1832,1800],{"class":1445},[545,1834,1436],{"class":1441},[545,1836,1838,1840,1843,1846,1848,1850,1853,1855,1857,1859,1861,1864,1866,1868,1870,1872,1874,1876,1878,1880,1882,1884,1886],{"class":547,"line":1837},21,[545,1839,1797],{"class":1441},[545,1841,1842],{"class":1445},"input",[545,1844,1845],{"class":1433}," type",[545,1847,1451],{"class":1441},[545,1849,572],{"class":571},[545,1851,1852],{"class":575},"text",[545,1854,572],{"class":571},[545,1856,1606],{"class":1433},[545,1858,1451],{"class":1441},[545,1860,572],{"class":571},[545,1862,1863],{"class":575},"form-control",[545,1865,572],{"class":571},[545,1867,1618],{"class":1433},[545,1869,1451],{"class":1441},[545,1871,572],{"class":571},[545,1873,1810],{"class":575},[545,1875,572],{"class":571},[545,1877,1500],{"class":1433},[545,1879,1451],{"class":1441},[545,1881,572],{"class":571},[545,1883,1810],{"class":575},[545,1885,572],{"class":571},[545,1887,1436],{"class":1441},[545,1889,1891,1894,1896],{"class":547,"line":1890},22,[545,1892,1893],{"class":1441},"            \u003C/",[545,1895,1603],{"class":1445},[545,1897,1436],{"class":1441},[545,1899,1901],{"class":547,"line":1900},23,[545,1902,1903],{"class":1100},"            \u003C!-- email, message, button ... -->\n",[545,1905,1907,1910,1912],{"class":547,"line":1906},24,[545,1908,1909],{"class":1441},"          \u003C/",[545,1911,1733],{"class":1445},[545,1913,1436],{"class":1441},[545,1915,1917,1920,1922],{"class":547,"line":1916},25,[545,1918,1919],{"class":1441},"        \u003C/",[545,1921,1603],{"class":1445},[545,1923,1436],{"class":1441},[545,1925,1927,1930,1932],{"class":547,"line":1926},26,[545,1928,1929],{"class":1441},"      \u003C/",[545,1931,1603],{"class":1445},[545,1933,1436],{"class":1441},[545,1935,1937,1939,1941],{"class":547,"line":1936},27,[545,1938,1660],{"class":1441},[545,1940,1671],{"class":1445},[545,1942,1436],{"class":1441},[545,1944,1946,1949,1951],{"class":547,"line":1945},28,[545,1947,1948],{"class":1441},"  \u003C/",[545,1950,1603],{"class":1445},[545,1952,1436],{"class":1441},[545,1954,1956,1958,1960],{"class":547,"line":1955},29,[545,1957,1538],{"class":1441},[545,1959,1126],{"class":1445},[545,1961,1436],{"class":1441},[545,1963,1965,1967,1969],{"class":547,"line":1964},30,[545,1966,1538],{"class":1441},[545,1968,720],{"class":1445},[545,1970,1436],{"class":1441},[545,1972,1974],{"class":547,"line":1973},31,[545,1975,1976],{"class":1100},"\u003C!-- Typical result: 20,000–100,000+ tokens for a real-world page -->\n",[11,1978,1979],{},[15,1980,1981,1982],{},"Playwright ",[116,1983,963],{},[536,1985,1987],{"className":1282,"code":1986,"language":1284,"meta":541,"style":541},"- heading \"Contact Us\" [level=1]\n- text: Fill in the form below and we will get back to you.\n- textbox \"Your Name\"\n- textbox \"Email Address\"\n- textbox \"Message\"\n- button \"Send Message\"\n# Typical result: ~500–2,000 tokens\n",[116,1988,1989,2006,2049,2063,2076,2089,2103],{"__ignoreMap":541},[545,1990,1991,1994,1997,1999,2001,2003],{"class":547,"line":548},[545,1992,1993],{"class":563},"-",[545,1995,1996],{"class":575}," heading",[545,1998,882],{"class":571},[545,2000,1535],{"class":575},[545,2002,572],{"class":571},[545,2004,2005],{"class":567}," [level=1]\n",[545,2007,2008,2010,2013,2016,2019,2022,2025,2028,2031,2034,2037,2040,2043,2046],{"class":547,"line":587},[545,2009,1993],{"class":563},[545,2011,2012],{"class":575}," text:",[545,2014,2015],{"class":575}," Fill",[545,2017,2018],{"class":575}," in",[545,2020,2021],{"class":575}," the",[545,2023,2024],{"class":575}," form",[545,2026,2027],{"class":575}," below",[545,2029,2030],{"class":575}," and",[545,2032,2033],{"class":575}," we",[545,2035,2036],{"class":575}," will",[545,2038,2039],{"class":575}," get",[545,2041,2042],{"class":575}," back",[545,2044,2045],{"class":575}," to",[545,2047,2048],{"class":575}," you.\n",[545,2050,2051,2053,2056,2058,2060],{"class":547,"line":606},[545,2052,1993],{"class":563},[545,2054,2055],{"class":575}," textbox",[545,2057,882],{"class":571},[545,2059,1828],{"class":575},[545,2061,2062],{"class":571},"\"\n",[545,2064,2065,2067,2069,2071,2074],{"class":547,"line":634},[545,2066,1993],{"class":563},[545,2068,2055],{"class":575},[545,2070,882],{"class":571},[545,2072,2073],{"class":575},"Email Address",[545,2075,2062],{"class":571},[545,2077,2078,2080,2082,2084,2087],{"class":547,"line":657},[545,2079,1993],{"class":563},[545,2081,2055],{"class":575},[545,2083,882],{"class":571},[545,2085,2086],{"class":575},"Message",[545,2088,2062],{"class":571},[545,2090,2091,2093,2096,2098,2101],{"class":547,"line":683},[545,2092,1993],{"class":563},[545,2094,2095],{"class":575}," button",[545,2097,882],{"class":571},[545,2099,2100],{"class":575},"Send Message",[545,2102,2062],{"class":571},[545,2104,2105],{"class":547,"line":706},[545,2106,2107],{"class":1100},"# Typical result: ~500–2,000 tokens\n",[11,2109,2110],{},[15,2111,2112,2113],{},"Vercel agent-browser ",[116,2114,2115],{},"snapshot -i",[536,2117,2119],{"className":1282,"code":2118,"language":1284,"meta":541,"style":541},"heading \"Contact Us\" [ref=e1]\ntextbox \"Your Name\" [ref=e2]\ntextbox \"Email Address\" [ref=e3]\ntextbox \"Message\" [ref=e4]\nbutton \"Send Message\" [ref=e5]\n# Typical result: ~200–400 tokens\n",[116,2120,2121,2135,2149,2162,2175,2189],{"__ignoreMap":541},[545,2122,2123,2126,2128,2130,2132],{"class":547,"line":548},[545,2124,2125],{"class":563},"heading",[545,2127,882],{"class":571},[545,2129,1535],{"class":575},[545,2131,572],{"class":571},[545,2133,2134],{"class":567}," [ref=e1]\n",[545,2136,2137,2140,2142,2144,2146],{"class":547,"line":587},[545,2138,2139],{"class":563},"textbox",[545,2141,882],{"class":571},[545,2143,1828],{"class":575},[545,2145,572],{"class":571},[545,2147,2148],{"class":567}," [ref=e2]\n",[545,2150,2151,2153,2155,2157,2159],{"class":547,"line":606},[545,2152,2139],{"class":563},[545,2154,882],{"class":571},[545,2156,2073],{"class":575},[545,2158,572],{"class":571},[545,2160,2161],{"class":567}," [ref=e3]\n",[545,2163,2164,2166,2168,2170,2172],{"class":547,"line":634},[545,2165,2139],{"class":563},[545,2167,882],{"class":571},[545,2169,2086],{"class":575},[545,2171,572],{"class":571},[545,2173,2174],{"class":567}," [ref=e4]\n",[545,2176,2177,2180,2182,2184,2186],{"class":547,"line":657},[545,2178,2179],{"class":563},"button",[545,2181,882],{"class":571},[545,2183,2100],{"class":575},[545,2185,572],{"class":571},[545,2187,2188],{"class":567}," [ref=e5]\n",[545,2190,2191],{"class":547,"line":683},[545,2192,2193],{"class":1100},"# Typical result: ~200–400 tokens\n",[11,2195,2196,2197,2199],{},"The practical difference between Playwright and agent-browser here is not just token count. Playwright's snapshot requires a separate locate-and-act step to do anything with the output. Agent-browser ",[116,2198,1278],{}," labels feed directly back into CLI commands with no additional parsing.",[56,2201,2203],{"id":2202},"use-cases-when-to-choose","Use Cases & When to Choose",[11,2205,2206],{},"Selecting the appropriate web automation tool largely depends on the specific requirements of a project, including factors like performance, stealth, scalability, and integration with AI.",[47,2208],{":width":49,"alt":2209,"format":51,"loading":71,"src":2210,"provider":54},"Web automation tool selection criteria","/blog/agent-browser-vs-puppeteer-and-playwright/3.svg",[11,2212,2213],{},"Each tool or service is designed with particular strengths that make it suitable for different scenarios.",[22,2215,2216,2221,2226],{},[25,2217,2218,2220],{},[15,2219,67],{},": Choose Puppeteer for quick Chrome-specific tasks such as web scraping or generating PDFs and screenshots. It is also a good choice for local and offline automation needs where only Chromium is required.",[25,2222,2223,2225],{},[15,2224,85],{},": This tool is well-suited for cross-browser end-to-end testing and building reliable multi-page automation workflows. Its comprehensive features and multi-language support make it a strong option for continuous integration/continuous deployment (CI/CD) pipelines.",[25,2227,2228,2230],{},[15,2229,102],{},": Opt for Vercel agent-browser when developing Large Language Model (LLM) agents for tasks like research, form-filling, or other autonomous web interactions. Its design focuses on low-context web interaction and minimal token usage for AI.",[64,2232,2234],{"id":2233},"choosing-guide","Choosing Guide",[11,2236,2237],{},"When making a selection, consider the primary objectives of your automation project. If the main concern is precise control, high speed, and local operation, Puppeteer or Playwright are generally more suitable. For projects that prioritize adaptability for AI agents, Vercel agent-browser becomes a more fitting choice, especially for development and specific agent tasks.",[47,2239],{":width":49,"alt":2240,"format":51,"loading":71,"src":2241,"provider":54},"Vercel agent-browser for AI agent workflows","/blog/agent-browser-vs-puppeteer-and-playwright/4.svg",[56,2243,2245],{"id":2244},"additional-data-trends","Additional Data & Trends",[11,2247,2248],{},"The landscape of web automation is continually shaped by new technologies and evolving web defense mechanisms. Staying informed about current trends and limitations helps in planning future automation strategies.",[64,2250,2252],{"id":2251},"stealthsecurity","Stealth/Security",[11,2254,2255],{},"Traditional automation tools, such as Puppeteer and Playwright, rely on manual configurations and third-party plugins for stealth features.",[47,2257],{":width":49,"alt":2258,"format":51,"loading":71,"src":2259,"provider":54},"Traditional automation tools stealth configuration","/blog/agent-browser-vs-puppeteer-and-playwright/5.svg",[11,2261,2262],{},"These plugins often require regular updates and fine-tuning to counter the increasingly sophisticated anti-bot systems. The effectiveness of these manual approaches can diminish quickly as websites adapt their defenses.",[11,2264,2265],{},"In contrast, Vercel agent-browser is positioned around agent-oriented interaction rather than traditional scripted browser control. Its snapshot-and-reference workflow may reduce how much raw page data needs to be passed through an LLM, but real-world detectability still depends heavily on browser configuration, infrastructure, and target-site defenses.",[64,2267,2269],{"id":2268},"communityecosystem","Community/Ecosystem",[11,2271,2272],{},"Puppeteer and Playwright benefit from large, established communities and extensive ecosystems, offering many plugins, extensions, and shared solutions for various automation challenges. This broad support base can be helpful for troubleshooting and finding pre-built components.",[11,2274,2275],{},"Vercel agent-browser, while newer, is developing its own ecosystem. It integrates with cloud providers like Browserbase for enhanced capabilities and works with AI coding tools.",[64,2277,2279],{"id":2278},"limitations","Limitations",[11,2281,2282],{},"Traditional web automation tools face challenges with brittleness and high maintenance requirements when scaled, especially on dynamic or protected websites. Small UI changes can break scripts, needing constant adjustments.",[11,2284,2285],{},"Vercel agent-browser, while offering adaptability, can introduce potential overhead from AI processing and may exhibit non-deterministic behavior depending on the AI's reasoning.",[64,2287,2289],{"id":2288},"_2026-trend","2026 Trend",[11,2291,2292],{},"The year 2026 sees a growing trend toward agentic automation, where AI agents are increasingly moving away from brittle, precisely scripted interactions.",[47,2294],{":width":49,"alt":2295,"format":51,"loading":71,"src":2296,"provider":54},"2026 trend toward agentic automation","/blog/agent-browser-vs-puppeteer-and-playwright/6.svg",[11,2298,2299],{},"This shift is driven by the need for more adaptive and resilient web task execution. Tools like Vercel agent-browser exemplify this movement by focusing on LLM-optimized interactions. Additionally, hybrid solutions, such as those combining Playwright with LLM-powered \"Multi-modal Control Planes\" (MCPs), are starting to emerge, aiming to blend the precision of traditional automation with the adaptability of AI agents.",[56,2301,2303],{"id":2302},"sources","Sources",[11,2305,2306],{},"The comparison in this article is based primarily on official product documentation and repository materials reviewed in April 2026, with secondary context from industry comparison articles and community discussions.",[22,2308,2309,2338],{},[25,2310,2311,2314,2315],{},[15,2312,2313],{},"Official sources reviewed",":\n",[22,2316,2317,2323,2329],{},[25,2318,2319,2320],{},"Playwright documentation: ",[116,2321,2322],{},"playwright.dev",[25,2324,2325,2326],{},"Puppeteer documentation: ",[116,2327,2328],{},"pptr.dev",[25,2330,2331,2332,195,2335],{},"Vercel agent-browser repository and docs: ",[116,2333,2334],{},"github.com/vercel-labs/agent-browser",[116,2336,2337],{},"agent-browser.dev",[25,2339,2340,2314,2343],{},[15,2341,2342],{},"Secondary sources",[22,2344,2345,2348],{},[25,2346,2347],{},"Comparison articles from browser automation vendors and tooling blogs",[25,2349,2350],{},"Community discussions about automation reliability, scraping maintenance, and agent workflows",[11,2352,2353],{},"Because these tools are evolving quickly, especially in the AI-agent category, it is worth checking the latest official docs before making architecture decisions based on version-specific features.",[56,2355,2357],{"id":2356},"conclusion","Conclusion",[11,2359,2360],{},"If you need a simple decision, use this:",[22,2362,2363,2368,2373],{},[25,2364,2365,2367],{},[15,2366,29],{}," when reliability, cross-browser coverage, and repeatable automation matter most.",[25,2369,2370,2372],{},[15,2371,35],{}," when you want direct Chromium automation with a lighter, Chrome-focused workflow.",[25,2374,2375,2377],{},[15,2376,41],{}," when you are building LLM-driven agents that need compact page state and more adaptive interaction patterns.",[11,2379,2380],{},"Playwright remains the strongest default for engineering teams building test automation or stable browser workflows. Puppeteer still makes sense for focused Chromium scripting where deep CDP control is useful. Agent-browser is most compelling when the browser is part of a larger agent loop rather than a fixed script.",[11,2382,2383,2384,2387],{},"In other words, the choice is less about which tool is universally best and more about ",[15,2385,2386],{},"what kind of system you are building",": a scripted automation stack, a testing platform, or an AI agent that must interpret changing web pages as it works.",[2389,2390,2391],"style",{},"html pre.shiki code .s76yb, html code.shiki .s76yb{--shiki-default:#8839EF;--shiki-dark:#C792EA}html pre.shiki code .scsc5, html code.shiki .scsc5{--shiki-default:#4C4F69;--shiki-default-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic}html pre.shiki code .s-_ek, html code.shiki .s-_ek{--shiki-default:#179299;--shiki-dark:#C792EA}html pre.shiki code .sNstc, html code.shiki .sNstc{--shiki-default:#1E66F5;--shiki-default-font-style:italic;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic}html pre.shiki code .s2kId, html code.shiki .s2kId{--shiki-default:#4C4F69;--shiki-dark:#D6DEEB}html pre.shiki code .sbuKk, html code.shiki .sbuKk{--shiki-default:#40A02B;--shiki-dark:#D9F5DD}html pre.shiki code .sfrMT, html code.shiki .sfrMT{--shiki-default:#40A02B;--shiki-dark:#ECC48D}html pre.shiki code .scGhl, html code.shiki .scGhl{--shiki-default:#7C7F93;--shiki-dark:#D6DEEB}html pre.shiki code .srhcd, html code.shiki .srhcd{--shiki-default:#8839EF;--shiki-default-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic}html pre.shiki code .sMtgK, html code.shiki .sMtgK{--shiki-default:#7C7F93;--shiki-dark:#D9F5DD}html pre.shiki code .sP4PM, html code.shiki .sP4PM{--shiki-default:#4C4F69;--shiki-default-font-style:inherit;--shiki-dark:#7FDBCA;--shiki-dark-font-style:italic}html pre.shiki code .s5FwJ, html code.shiki .s5FwJ{--shiki-default:#179299;--shiki-default-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic}html pre.shiki code .soAP-, html code.shiki .soAP-{--shiki-default:#4C4F69;--shiki-dark:#D7DBE0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sgNGR, html code.shiki .sgNGR{--shiki-default:#7C7F93;--shiki-dark:#C792EA}html pre.shiki code .sVS64, html code.shiki .sVS64{--shiki-default:#179299;--shiki-dark:#D6DEEB}html pre.shiki code .sDmS1, html code.shiki .sDmS1{--shiki-default:#7C7F93;--shiki-default-font-style:italic;--shiki-dark:#637777;--shiki-dark-font-style:italic}html pre.shiki code .sPg8w, html code.shiki .sPg8w{--shiki-default:#40A02B;--shiki-dark:#82AAFF}html pre.shiki code .sEaUw, html code.shiki .sEaUw{--shiki-default:#8839EF;--shiki-dark:#7FDBCA}html pre.shiki code .s18vy, html code.shiki .s18vy{--shiki-default:#8839EF;--shiki-dark:#CAECE6}html pre.shiki code .swkLt, html code.shiki .swkLt{--shiki-default:#DF8E1D;--shiki-default-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic}html pre.shiki code .s9rnR, html code.shiki .s9rnR{--shiki-default:#179299;--shiki-dark:#7FDBCA}html pre.shiki code .sY2RG, html code.shiki .sY2RG{--shiki-default:#1E66F5;--shiki-dark:#CAECE6}",{"title":541,"searchDepth":587,"depth":587,"links":2393},[2394,2400,2401,2402,2403,2407,2412,2420,2423,2429,2430],{"id":58,"depth":587,"text":59,"children":2395},[2396,2397,2398,2399],{"id":66,"depth":606,"text":67},{"id":84,"depth":606,"text":85},{"id":101,"depth":606,"text":102},{"id":130,"depth":606,"text":131},{"id":141,"depth":587,"text":142},{"id":188,"depth":587,"text":189},{"id":229,"depth":587,"text":230},{"id":420,"depth":587,"text":421,"children":2404},[2405,2406],{"id":427,"depth":606,"text":428},{"id":459,"depth":606,"text":460},{"id":469,"depth":587,"text":470,"children":2408},[2409,2410,2411],{"id":476,"depth":606,"text":67},{"id":493,"depth":606,"text":85},{"id":508,"depth":606,"text":102},{"id":523,"depth":587,"text":524,"children":2413},[2414,2415,2416,2417,2418,2419],{"id":530,"depth":606,"text":531},{"id":754,"depth":606,"text":755},{"id":956,"depth":606,"text":957},{"id":1205,"depth":606,"text":1206},{"id":1271,"depth":606,"text":1272},{"id":1402,"depth":606,"text":1403},{"id":2202,"depth":587,"text":2203,"children":2421},[2422],{"id":2233,"depth":606,"text":2234},{"id":2244,"depth":587,"text":2245,"children":2424},[2425,2426,2427,2428],{"id":2251,"depth":606,"text":2252},{"id":2268,"depth":606,"text":2269},{"id":2278,"depth":606,"text":2279},{"id":2288,"depth":606,"text":2289},{"id":2302,"depth":587,"text":2303},{"id":2356,"depth":587,"text":2357},"ai-agents","2026-04-10","Compare Vercel agent-browser, Puppeteer, and Playwright for web automation and AI agents in 2026. Covers architecture, performance benchmarks, stealth, LLM token efficiency, and when to use each tool.","md",[2436,2439,2442,2445,2448],{"question":2437,"answer":2438},"What is an agent browser?","An agent browser is a browser environment designed specifically for AI agent workflows. Instead of exposing raw DOM access or requiring CSS selectors, it provides structured page representations, persistent session state, and observation tools that map cleanly to the way language models plan and act. Puppeteer and Playwright can be configured to behave like agent browsers, but purpose-built solutions go further by handling auth state, anti-bot measures, and multi-step orchestration out of the box.",{"question":2440,"answer":2441},"Can Puppeteer or Playwright be used for AI agents?","Yes. Both tools are widely used as the browser engine underneath AI agent frameworks. Playwright is the more common choice because its accessibility snapshot mode is token-efficient and its Browser Contexts support large parallel agent fleets. Puppeteer remains useful for agents that need deep Chromium control. The main limitation of both tools is that they were designed for deterministic test scripts, not probabilistic agent loops, so reliability in production often requires extra scaffolding.",{"question":2443,"answer":2444},"How does Vercel agent-browser differ from Playwright for AI agents?","Vercel agent-browser is built natively for LLM-driven workflows. Its snapshot command produces a compact accessibility tree with @ref labels (~200–400 tokens per page) rather than full DOM, which makes it significantly more token-efficient than feeding Playwright output to a language model. It also runs as a persistent daemon with no Node.js dependency, and includes built-in stealth features that Playwright requires manual plugins to replicate.",{"question":2446,"answer":2447},"Which tool uses the fewest tokens when feeding page state to an LLM?","Vercel agent-browser is the most token-efficient option. Its snapshot command generates a compact accessibility tree with @ref labels for interactive elements, typically 200–400 tokens per page. Raw DOM from Puppeteer can easily exceed 100,000 tokens. Playwright's accessibility snapshot mode sits in between and is substantially more efficient than raw DOM, but Vercel agent-browser's purpose-built format is the most optimised for LLM consumption.",{"question":2449,"answer":2450},"When should I use Playwright instead of an agent browser?","Playwright is the better choice when you need deterministic, reproducible scripts for testing or when your workflow is simple enough to express as a fixed sequence of clicks and fills. It is also the right tool if you want cross-browser support (Chromium, Firefox, WebKit), network interception, trace recording, or a mature CI/CD integration. Agent browsers add value when your workflow is open-ended, requires persistent state across sessions, or involves tasks too variable to encode as a stable selector chain.",0,null,{"shortTitle":5,"relatedLinks":2454},[2455,2459,2463],{"text":2456,"href":2457,"description":2458},"Playwright vs. Puppeteer for AI Agents","/blog/playwright-vs-puppeteer-which-is-better-for-ai-agent-control","A detailed comparison of Playwright and Puppeteer for building AI browser agents.",{"text":2460,"href":2461,"description":2462},"Top 5 MCP Servers for AI Agent Browser Automation","/blog/the-top-5-best-mcp-servers-for-ai-agent-browser-automation","Compare the five best MCP servers for connecting AI agents to live browsers.",{"text":2464,"href":2465,"description":2466},"Playwright vs. Selenium in 2026","/blog/playwright-vs-selenium-which-automation-tool-is-right-for-you-in-2026","An in-depth look at how Playwright and Selenium compare for modern web automation.","/blog/agent-browser-vs-puppeteer-and-playwright",{"title":5,"description":2433},{"loc":2467},"blog/1038.agent-browser-vs-puppeteer-and-playwright",[2472,2431,66,84,1296,2473],"browser-automation","web-agents","AKr2_4KdxB3g5YTOyB_UZULvkitZ6RuN1ED9WgMhlbc",[2476,4187],{"id":2477,"title":2478,"authorId":2479,"body":2480,"category":2431,"created":4163,"description":4164,"extension":2434,"faqs":2452,"featurePriority":2452,"head":2452,"landingPath":2452,"meta":4165,"navigation":1094,"ogImage":2452,"path":4177,"robots":2452,"schemaOrg":2452,"seo":4178,"sitemap":4179,"stem":4180,"tags":4181,"__hash__":4186},"blog/blog/1012.dom-downsampling-for-llm-based-web-agents.md","DOM Downsampling for LLM-Based Web Agents","thassilo-schiepanski",{"type":8,"value":2481,"toc":4148},[2482,2486,2511,2515,2521,2525,2541,2545,2551,2555,2573,2599,2602,2606,2609,2620,2626,2657,2661,2681,2693,2698,2712,2726,2729,2733,2753,2757,2765,2777,2781,2784,3126,3132,3139,3303,3310,3401,3408,3480,3489,3495,3504,3508,3514,3524,3536,3759,3777,3843,3849,3963,3967,3979,3988,3993,3998,4001,4005,4011,4016,4054,4058,4064,4068,4078,4082,4085,4145],[47,2483],{":width":49,"alt":2484,"format":51,"loading":71,"src":2485},"Downsampling visualised for digital images and HTML","/blog/dom-downsampling-for-web-agents/1.png",[11,2487,2488,2495,2496,2495,2501,2506,2507,2510],{},[2489,2490,2494],"a",{"href":2491,"rel":2492},"https://operator.chatgpt.com",[2493],"nofollow","Operator (OpenAI)",", ",[2489,2497,2500],{"href":2498,"rel":2499},"https://www.director.ai",[2493],"Director (Browserbase)",[2489,2502,2505],{"href":2503,"rel":2504},"https://browser-use.com",[2493],"Browser Use"," – we are currently witnessing the rise of ",[15,2508,2509],{},"web AI agents",". The first iteration of serviceable web agents was enabled by frontier LLMs, which act as instantaneous domain model backends. The domain, hereby, corresponds to the landscape of web application UIs.",[56,2512,2514],{"id":2513},"what-is-a-snapshot","What is a Snapshot?",[11,2516,2517,2518,2520],{},"Web agents provide an LLM with a task, and serialised runtime state of a currently browsed web application (e.g., a screenshot). The LLM is ought to suggest relevant actions to perform in the web application. Serialisation of such runtime state is referred to as a ",[15,2519,118],{},". And the snapshot technique primarily decides the quality of LLM interaction suggestions.",[64,2522,2524],{"id":2523},"gui-snapshots","GUI Snapshots",[11,2526,2527,2528,2531,2532,2536,2537,2540],{},"Screenshots – for consistency reasons referred to as ",[15,2529,2530],{},"GUI snapshots"," – resemble how humans visually perceive web application UIs. LLM APIs subsidise the use of image input through upstream compression. Compresssion, however, irreversibly affects image dimensions, which takes away pixel precision; no way to suggest interactions like ",[2533,2534,2535],"em",{},"“click at 100, 735”",". As a workaround, early web agents used ",[2533,2538,2539],{},"grounded"," GUI snapshots. Grounding describes adding visual cues to the GUI, such as bounding boxes with numerical identifiers. Grounding lets the LLM refer to specific parts of the page by identifier, so the agent can trace back interaction targets.",[47,2542],{":width":49,"alt":2543,"format":51,"loading":71,"src":2544},"Grounded GUI snapshot as implemented by Browser Use","/blog/dom-downsampling-for-web-agents/2.png",[11,2546,2547],{},[2548,2549,2550],"small",{},"Grounded GUI snapshot as implemented by Browser Use.",[64,2552,2554],{"id":2553},"dom-snapshots","DOM Snapshots",[11,2556,2557,2558,2568,2569,2572],{},"LLMs arguably are much better at understanding code than images. Research supports they excel at describing and classifying HTML, and also navigating an inherent UI",[2559,2560,2561],"sup",{},[2489,2562,2567],{"href":2563,"ariaDescribedBy":2564,"dataFootnoteRef":541,"id":2566},"#user-content-fn-1",[2565],"footnote-label","user-content-fnref-1","1",". The DOM (document object model) – a web browser's runtime state model of a web application – translates back to HTML. For this reason, ",[15,2570,2571],{},"DOM snapshots"," offer a compelling alternative to GUI snapshots. DOM snapshots offer a handful of key advantages:",[2574,2575,2576,2579,2582,2585,2588],"ol",{},[25,2577,2578],{},"DOM snapshots connect with LLM code (HTML) interpretation abilities.",[25,2580,2581],{},"DOM snapshots can be compiled from deep clones, hidden from supervision (unlike GUI grounding).",[25,2583,2584],{},"DOM snapshots render text input that on average consume less bandwidth than screnshots.",[25,2586,2587],{},"DOM snapshots allow for exact programmatic targeting of elements (e.g., via CSS selectors).",[25,2589,2590,2591,2594,2595,2598],{},"DOM snapshots are available with the ",[116,2592,2593],{},"DOMContentLoaded"," event (whereas the GUI completes initial rendering with ",[116,2596,2597],{},"load",").",[11,2600,2601],{},"Yet, DOM snapshots have a major problem: potentially exhaustive model context. Whereas GUI snapshot commonly cost four figures of tokens, a raw DOM snapshot can cost into hundreds of thousands of tokens. To connect with LLM code interpretation abilities, however, developers have used element extraction techniques – picking only (likely) important elements from the DOM. Element extraction flattens the DOM tree, which disregards hierarchy as a potential UI feature (how do elements relate to each other?).",[56,2603,2605],{"id":2604},"dom-downsampling-a-novel-approach","DOM Downsampling: A Novel Approach",[11,2607,2608],{},"To enable DOM snapshots for use with web agents, it requires client-side pre-processing – similar to how LLM vision APIs process image input. Downsampling is a fundamental signal processing technique that reduces data that scales out of time or space constraints under the assumption that the majority of relevant features is retained. Picture JPEG compression as an example: put simply, a JPEG image stores only an average colour for patches of pixels. The bigger the patches, the smaller the file. Although some detail is lost, key image features – colours, edges, objects – keep being recognisable – up to a large patch size.",[11,2610,2611,2612,2615,2616,2619],{},"We transfer the concept of ",[15,2613,2614],{},"downsampling"," to ",[15,2617,2618],{},"DOMs",". Particularly, since such an approach retains HTML characteristics that might be valuable for an LLM backend. We define UI features as concepts that, to a substantial degree, facilitate LLM suggestions on how to act in the UI in order to solve related web-based tasks.",[56,2621,2623],{"id":2622},"d2snap",[2533,2624,2625],{},"D2Snap",[11,2627,2628,2629,2637,2645,2653,2654,2656],{},"We recently proposed ",[2489,2630,2633],{"href":2631,"rel":2632},"https://arxiv.org/abs/2508.04412",[2493],[15,2634,2635],{},[2533,2636,2625],{},[2559,2638,2639],{},[2489,2640,2644],{"href":2641,"ariaDescribedBy":2642,"dataFootnoteRef":541,"id":2643},"#user-content-fn-2",[2565],"user-content-fnref-2","2",[2559,2646,2647],{},[2489,2648,2652],{"href":2649,"ariaDescribedBy":2650,"dataFootnoteRef":541,"id":2651},"#user-content-fn-3",[2565],"user-content-fnref-3","3"," – a first-of-its-kind downsampling algorithm for DOMs. Herein, we'll briefly explain how the ",[2533,2655,2625],{}," algorithm works, and how it can be utilised to build efficient and performant web agents.",[64,2658,2660],{"id":2659},"how-it-works","How it works",[11,2662,2663,2664,2666,2667,2495,2670,2673,2674,2677,2678,2598],{},"There are basically three redundant types of DOM nodes, and HTML concepts: elements, text, and attributes. We defined and empirically adjusted three node-specific procedures. ",[2533,2665,2625],{}," downsamples at a variable ratio, configured through procedure-specific parameters  ",[116,2668,2669],{},"k",[116,2671,2672],{},"l",", and ",[116,2675,2676],{},"m"," (",[116,2679,2680],{},"∈ [0, 1]",[2682,2683,2684],"blockquote",{},[11,2685,2686,2687,2692],{},"We used ",[2489,2688,2691],{"href":2689,"rel":2690},"https://openai.com/index/hello-gpt-4o/",[2493],"GPT-4o"," to create a downsampling ground truth dataset by having it classify HTML elements and scoring semantics regarding relevance for understanding the inherent UI – a UI feature degree.",[2694,2695,2697],"h4",{"id":2696},"procedure-elements","Procedure: Elements",[11,2699,2700,2702,2703,195,2706,2708,2709,2711],{},[2533,2701,2625],{}," downsamples (simplifies) elements by merging container elements like ",[116,2704,2705],{},"section",[116,2707,1603],{}," together. A parameter ",[116,2710,2669],{}," controls the merge ratio depending on the total DOM tree height. For competing concepts, such as element name, the ground truth determines which element's characterisitics to keep – comparing UI feature scores.",[11,2713,2714,2715,2495,2717,2719,2720,2725],{},"Elements in content elements (",[116,2716,11],{},[116,2718,2682],{},", ...) are translated to a more comprehensive ",[2489,2721,2724],{"href":2722,"rel":2723},"https://www.markdownguide.org/basic-syntax/",[2493],"Markdown"," representation.",[11,2727,2728],{},"Interactive elements, definite interaction target candidates, are kept as is.",[2694,2730,2732],{"id":2731},"procedure-text","Procedure: Text",[11,2734,2735,2737,2738,2741,2749,2750,2752],{},[2533,2736,2625],{}," downsamples text by dropping a fraction. Natural units of text are space-separated words, or punctuation-separated sentences. We reuse the ",[2533,2739,2740],{},"TextRank",[2559,2742,2743],{},[2489,2744,2748],{"href":2745,"ariaDescribedBy":2746,"dataFootnoteRef":541,"id":2747},"#user-content-fn-4",[2565],"user-content-fnref-4","4"," algorithm to rank sentences in text nodes. The lowest-ranking fraction of sentences, denoted by parameter ",[116,2751,2672],{},", is dropped.",[2694,2754,2756],{"id":2755},"procedure-attributes","Procedure: Attributes",[11,2758,2759,2761,2762,2764],{},[2533,2760,2625],{}," downsamples attributes by dropping those with a name that, according to ground truth, holds a UI feature degree below a threshold. Parameter ",[116,2763,2676],{}," denotes this threshold.",[2682,2766,2767],{},[11,2768,2769,2770,2776],{},"Check out the ",[2489,2771,2773,2775],{"href":2631,"rel":2772},[2493],[2533,2774,2625],{}," paper"," to learn about the algorithm in-depth.",[64,2778,2780],{"id":2779},"example-of-a-downsampled-dom","Example of a Downsampled DOM",[11,2782,2783],{},"Consider a partial DOM state, serialised as HTML:",[536,2785,2787],{"className":1417,"code":2786,"language":720,"meta":541,"style":541},"\u003Csection class=\"container\" tabindex=\"3\" required=\"true\" type=\"example\">\n  \u003Cdiv class=\"mx-auto\" data-topic=\"products\" required=\"false\">\n    \u003Ch1>Our Pizza\u003C/h1>\n    \u003Cdiv>\n      \u003Cdiv class=\"shadow-lg\">\n        \u003Ch2>Margherita\u003C/h2>\n        \u003Cp>\n          A simple classic: mozzarela, tomatoes and basil.\n          An everyday choice!\n        \u003C/p>\n        \u003Cbutton type=\"button\">Add\u003C/button>\n      \u003C/div>\n      \u003Cdiv class=\"shadow-lg\">\n        \u003Ch2>Capricciosa\u003C/h2>\n        \u003Cp>\n          A rich taste: mozzarella, ham, mushrooms, artichokes, and olives.\n          A true favourite!\n          \u003C/p>\n        \u003Cbutton type=\"button\">Add\u003C/button>\n      \u003C/div>\n    \u003C/div>\n  \u003C/div>\n\u003C/section>\n",[116,2788,2789,2842,2884,2902,2910,2929,2946,2954,2959,2964,2972,2999,3007,3025,3042,3050,3055,3060,3068,3094,3102,3110,3118],{"__ignoreMap":541},[545,2790,2791,2793,2795,2797,2799,2801,2804,2806,2809,2811,2813,2815,2817,2820,2822,2824,2827,2829,2831,2833,2835,2838,2840],{"class":547,"line":548},[545,2792,1442],{"class":1441},[545,2794,2705],{"class":1445},[545,2796,1606],{"class":1433},[545,2798,1451],{"class":1441},[545,2800,572],{"class":571},[545,2802,2803],{"class":575},"container",[545,2805,572],{"class":571},[545,2807,2808],{"class":1433}," tabindex",[545,2810,1451],{"class":1441},[545,2812,572],{"class":571},[545,2814,2652],{"class":575},[545,2816,572],{"class":571},[545,2818,2819],{"class":1433}," required",[545,2821,1451],{"class":1441},[545,2823,572],{"class":571},[545,2825,2826],{"class":575},"true",[545,2828,572],{"class":571},[545,2830,1845],{"class":1433},[545,2832,1451],{"class":1441},[545,2834,572],{"class":571},[545,2836,2837],{"class":575},"example",[545,2839,572],{"class":571},[545,2841,1436],{"class":1441},[545,2843,2844,2846,2848,2850,2852,2854,2857,2859,2862,2864,2866,2869,2871,2873,2875,2877,2880,2882],{"class":547,"line":587},[545,2845,1474],{"class":1441},[545,2847,1603],{"class":1445},[545,2849,1606],{"class":1433},[545,2851,1451],{"class":1441},[545,2853,572],{"class":571},[545,2855,2856],{"class":575},"mx-auto",[545,2858,572],{"class":571},[545,2860,2861],{"class":1433}," data-topic",[545,2863,1451],{"class":1441},[545,2865,572],{"class":571},[545,2867,2868],{"class":575},"products",[545,2870,572],{"class":571},[545,2872,2819],{"class":1433},[545,2874,1451],{"class":1441},[545,2876,572],{"class":571},[545,2878,2879],{"class":575},"false",[545,2881,572],{"class":571},[545,2883,1436],{"class":1441},[545,2885,2886,2888,2891,2893,2896,2898,2900],{"class":547,"line":606},[545,2887,1634],{"class":1441},[545,2889,2890],{"class":1445},"h1",[545,2892,1532],{"class":1441},[545,2894,2895],{"class":567},"Our Pizza",[545,2897,1538],{"class":1441},[545,2899,2890],{"class":1445},[545,2901,1436],{"class":1441},[545,2903,2904,2906,2908],{"class":547,"line":634},[545,2905,1634],{"class":1441},[545,2907,1603],{"class":1445},[545,2909,1436],{"class":1441},[545,2911,2912,2914,2916,2918,2920,2922,2925,2927],{"class":547,"line":657},[545,2913,1689],{"class":1441},[545,2915,1603],{"class":1445},[545,2917,1606],{"class":1433},[545,2919,1451],{"class":1441},[545,2921,572],{"class":571},[545,2923,2924],{"class":575},"shadow-lg",[545,2926,572],{"class":571},[545,2928,1436],{"class":1441},[545,2930,2931,2933,2935,2937,2940,2942,2944],{"class":547,"line":683},[545,2932,1709],{"class":1441},[545,2934,56],{"class":1445},[545,2936,1532],{"class":1441},[545,2938,2939],{"class":567},"Margherita",[545,2941,1538],{"class":1441},[545,2943,56],{"class":1445},[545,2945,1436],{"class":1441},[545,2947,2948,2950,2952],{"class":547,"line":706},[545,2949,1709],{"class":1441},[545,2951,11],{"class":1445},[545,2953,1436],{"class":1441},[545,2955,2956],{"class":547,"line":727},[545,2957,2958],{"class":567},"          A simple classic: mozzarela, tomatoes and basil.\n",[545,2960,2961],{"class":547,"line":743},[545,2962,2963],{"class":567},"          An everyday choice!\n",[545,2965,2966,2968,2970],{"class":547,"line":1158},[545,2967,1919],{"class":1441},[545,2969,11],{"class":1445},[545,2971,1436],{"class":1441},[545,2973,2974,2976,2978,2980,2982,2984,2986,2988,2990,2993,2995,2997],{"class":547,"line":1164},[545,2975,1709],{"class":1441},[545,2977,2179],{"class":1445},[545,2979,1845],{"class":1433},[545,2981,1451],{"class":1441},[545,2983,572],{"class":571},[545,2985,2179],{"class":575},[545,2987,572],{"class":571},[545,2989,1532],{"class":1441},[545,2991,2992],{"class":567},"Add",[545,2994,1538],{"class":1441},[545,2996,2179],{"class":1445},[545,2998,1436],{"class":1441},[545,3000,3001,3003,3005],{"class":547,"line":1170},[545,3002,1929],{"class":1441},[545,3004,1603],{"class":1445},[545,3006,1436],{"class":1441},[545,3008,3009,3011,3013,3015,3017,3019,3021,3023],{"class":547,"line":1176},[545,3010,1689],{"class":1441},[545,3012,1603],{"class":1445},[545,3014,1606],{"class":1433},[545,3016,1451],{"class":1441},[545,3018,572],{"class":571},[545,3020,2924],{"class":575},[545,3022,572],{"class":571},[545,3024,1436],{"class":1441},[545,3026,3027,3029,3031,3033,3036,3038,3040],{"class":547,"line":1181},[545,3028,1709],{"class":1441},[545,3030,56],{"class":1445},[545,3032,1532],{"class":1441},[545,3034,3035],{"class":567},"Capricciosa",[545,3037,1538],{"class":1441},[545,3039,56],{"class":1445},[545,3041,1436],{"class":1441},[545,3043,3044,3046,3048],{"class":547,"line":1196},[545,3045,1709],{"class":1441},[545,3047,11],{"class":1445},[545,3049,1436],{"class":1441},[545,3051,3052],{"class":547,"line":1384},[545,3053,3054],{"class":567},"          A rich taste: mozzarella, ham, mushrooms, artichokes, and olives.\n",[545,3056,3057],{"class":547,"line":1389},[545,3058,3059],{"class":567},"          A true favourite!\n",[545,3061,3062,3064,3066],{"class":547,"line":1727},[545,3063,1909],{"class":1441},[545,3065,11],{"class":1445},[545,3067,1436],{"class":1441},[545,3069,3070,3072,3074,3076,3078,3080,3082,3084,3086,3088,3090,3092],{"class":547,"line":1773},[545,3071,1709],{"class":1441},[545,3073,2179],{"class":1445},[545,3075,1845],{"class":1433},[545,3077,1451],{"class":1441},[545,3079,572],{"class":571},[545,3081,2179],{"class":575},[545,3083,572],{"class":571},[545,3085,1532],{"class":1441},[545,3087,2992],{"class":567},[545,3089,1538],{"class":1441},[545,3091,2179],{"class":1445},[545,3093,1436],{"class":1441},[545,3095,3096,3098,3100],{"class":547,"line":1794},[545,3097,1929],{"class":1441},[545,3099,1603],{"class":1445},[545,3101,1436],{"class":1441},[545,3103,3104,3106,3108],{"class":547,"line":1837},[545,3105,1660],{"class":1441},[545,3107,1603],{"class":1445},[545,3109,1436],{"class":1441},[545,3111,3112,3114,3116],{"class":547,"line":1890},[545,3113,1948],{"class":1441},[545,3115,1603],{"class":1445},[545,3117,1436],{"class":1441},[545,3119,3120,3122,3124],{"class":547,"line":1900},[545,3121,1538],{"class":1441},[545,3123,2705],{"class":1445},[545,3125,1436],{"class":1441},[11,3127,3128,3129,3131],{},"Here are some ",[2533,3130,2625],{}," downsampling results, which are based on different parametric configurations. A percentage denotes the reduced size.",[2694,3133,3135,3138],{"id":3134},"k3-l3-m3-55",[116,3136,3137],{},"k=.3, l=.3, m=.3"," (55%)",[536,3140,3142],{"className":1417,"code":3141,"language":720,"meta":541,"style":541},"\u003Csection tabindex=\"3\" type=\"example\" class=\"container\" required=\"true\">\n  # Our Pizza\n  \u003Cdiv class=\"shadow-lg\">\n    ## Margherita\n    A simple classic: mozzarela, tomatoes, and basil.\n    \u003Cbutton type=\"button\">Add\u003C/button>\n    ## Capricciosa\n    A rich taste: mozzarella, ham, mushrooms, artichokes, and olives.\n    \u003Cbutton type=\"button\">Add\u003C/button>\n  \u003C/div>\n\u003C/section>\n",[116,3143,3144,3192,3197,3215,3220,3225,3251,3256,3261,3287,3295],{"__ignoreMap":541},[545,3145,3146,3148,3150,3152,3154,3156,3158,3160,3162,3164,3166,3168,3170,3172,3174,3176,3178,3180,3182,3184,3186,3188,3190],{"class":547,"line":548},[545,3147,1442],{"class":1441},[545,3149,2705],{"class":1445},[545,3151,2808],{"class":1433},[545,3153,1451],{"class":1441},[545,3155,572],{"class":571},[545,3157,2652],{"class":575},[545,3159,572],{"class":571},[545,3161,1845],{"class":1433},[545,3163,1451],{"class":1441},[545,3165,572],{"class":571},[545,3167,2837],{"class":575},[545,3169,572],{"class":571},[545,3171,1606],{"class":1433},[545,3173,1451],{"class":1441},[545,3175,572],{"class":571},[545,3177,2803],{"class":575},[545,3179,572],{"class":571},[545,3181,2819],{"class":1433},[545,3183,1451],{"class":1441},[545,3185,572],{"class":571},[545,3187,2826],{"class":575},[545,3189,572],{"class":571},[545,3191,1436],{"class":1441},[545,3193,3194],{"class":547,"line":587},[545,3195,3196],{"class":567},"  # Our Pizza\n",[545,3198,3199,3201,3203,3205,3207,3209,3211,3213],{"class":547,"line":606},[545,3200,1474],{"class":1441},[545,3202,1603],{"class":1445},[545,3204,1606],{"class":1433},[545,3206,1451],{"class":1441},[545,3208,572],{"class":571},[545,3210,2924],{"class":575},[545,3212,572],{"class":571},[545,3214,1436],{"class":1441},[545,3216,3217],{"class":547,"line":634},[545,3218,3219],{"class":567},"    ## Margherita\n",[545,3221,3222],{"class":547,"line":657},[545,3223,3224],{"class":567},"    A simple classic: mozzarela, tomatoes, and basil.\n",[545,3226,3227,3229,3231,3233,3235,3237,3239,3241,3243,3245,3247,3249],{"class":547,"line":683},[545,3228,1634],{"class":1441},[545,3230,2179],{"class":1445},[545,3232,1845],{"class":1433},[545,3234,1451],{"class":1441},[545,3236,572],{"class":571},[545,3238,2179],{"class":575},[545,3240,572],{"class":571},[545,3242,1532],{"class":1441},[545,3244,2992],{"class":567},[545,3246,1538],{"class":1441},[545,3248,2179],{"class":1445},[545,3250,1436],{"class":1441},[545,3252,3253],{"class":547,"line":706},[545,3254,3255],{"class":567},"    ## Capricciosa\n",[545,3257,3258],{"class":547,"line":727},[545,3259,3260],{"class":567},"    A rich taste: mozzarella, ham, mushrooms, artichokes, and olives.\n",[545,3262,3263,3265,3267,3269,3271,3273,3275,3277,3279,3281,3283,3285],{"class":547,"line":743},[545,3264,1634],{"class":1441},[545,3266,2179],{"class":1445},[545,3268,1845],{"class":1433},[545,3270,1451],{"class":1441},[545,3272,572],{"class":571},[545,3274,2179],{"class":575},[545,3276,572],{"class":571},[545,3278,1532],{"class":1441},[545,3280,2992],{"class":567},[545,3282,1538],{"class":1441},[545,3284,2179],{"class":1445},[545,3286,1436],{"class":1441},[545,3288,3289,3291,3293],{"class":547,"line":1158},[545,3290,1948],{"class":1441},[545,3292,1603],{"class":1445},[545,3294,1436],{"class":1441},[545,3296,3297,3299,3301],{"class":547,"line":1164},[545,3298,1538],{"class":1441},[545,3300,2705],{"class":1445},[545,3302,1436],{"class":1441},[2694,3304,3306,3309],{"id":3305},"k4-l6-m8-27",[116,3307,3308],{},"k=.4, l=.6, m=.8"," (27%)",[536,3311,3313],{"className":1417,"code":3312,"language":720,"meta":541,"style":541},"\u003Csection>\n  # Our Pizza\n  \u003Cdiv>\n    ## Margherita\n    A simple classic:\n    \u003Cbutton>Add\u003C/button>\n    ## Capricciosa\n    A rich taste:\n    \u003Cbutton>Add\u003C/button>\n  \u003C/div>\n\u003C/section>\n",[116,3314,3315,3323,3327,3335,3339,3344,3360,3364,3369,3385,3393],{"__ignoreMap":541},[545,3316,3317,3319,3321],{"class":547,"line":548},[545,3318,1442],{"class":1441},[545,3320,2705],{"class":1445},[545,3322,1436],{"class":1441},[545,3324,3325],{"class":547,"line":587},[545,3326,3196],{"class":567},[545,3328,3329,3331,3333],{"class":547,"line":606},[545,3330,1474],{"class":1441},[545,3332,1603],{"class":1445},[545,3334,1436],{"class":1441},[545,3336,3337],{"class":547,"line":634},[545,3338,3219],{"class":567},[545,3340,3341],{"class":547,"line":657},[545,3342,3343],{"class":567},"    A simple classic:\n",[545,3345,3346,3348,3350,3352,3354,3356,3358],{"class":547,"line":683},[545,3347,1634],{"class":1441},[545,3349,2179],{"class":1445},[545,3351,1532],{"class":1441},[545,3353,2992],{"class":567},[545,3355,1538],{"class":1441},[545,3357,2179],{"class":1445},[545,3359,1436],{"class":1441},[545,3361,3362],{"class":547,"line":706},[545,3363,3255],{"class":567},[545,3365,3366],{"class":547,"line":727},[545,3367,3368],{"class":567},"    A rich taste:\n",[545,3370,3371,3373,3375,3377,3379,3381,3383],{"class":547,"line":743},[545,3372,1634],{"class":1441},[545,3374,2179],{"class":1445},[545,3376,1532],{"class":1441},[545,3378,2992],{"class":567},[545,3380,1538],{"class":1441},[545,3382,2179],{"class":1445},[545,3384,1436],{"class":1441},[545,3386,3387,3389,3391],{"class":547,"line":1158},[545,3388,1948],{"class":1441},[545,3390,1603],{"class":1445},[545,3392,1436],{"class":1441},[545,3394,3395,3397,3399],{"class":547,"line":1164},[545,3396,1538],{"class":1441},[545,3398,2705],{"class":1445},[545,3400,1436],{"class":1441},[2694,3402,3404,3407],{"id":3403},"k-l0-m-35",[116,3405,3406],{},"k→∞, l=0, ∀m"," (35%)",[536,3409,3411],{"className":1417,"code":3410,"language":720,"meta":541,"style":541},"# Our Pizza\n## Margherita\nA simple classic: mozzarela, tomatoes, and basil.\nAn everyday choice!\n\u003Cbutton>Add\u003C/button>\n## Capricciosa\nA rich taste: mozzarella, ham, mushrooms, artichokes, and olives.\nA true favourite!\n\u003Cbutton>Add\u003C/button>\n",[116,3412,3413,3418,3423,3428,3433,3449,3454,3459,3464],{"__ignoreMap":541},[545,3414,3415],{"class":547,"line":548},[545,3416,3417],{"class":567},"# Our Pizza\n",[545,3419,3420],{"class":547,"line":587},[545,3421,3422],{"class":567},"## Margherita\n",[545,3424,3425],{"class":547,"line":606},[545,3426,3427],{"class":567},"A simple classic: mozzarela, tomatoes, and basil.\n",[545,3429,3430],{"class":547,"line":634},[545,3431,3432],{"class":567},"An everyday choice!\n",[545,3434,3435,3437,3439,3441,3443,3445,3447],{"class":547,"line":657},[545,3436,1442],{"class":1441},[545,3438,2179],{"class":1445},[545,3440,1532],{"class":1441},[545,3442,2992],{"class":567},[545,3444,1538],{"class":1441},[545,3446,2179],{"class":1445},[545,3448,1436],{"class":1441},[545,3450,3451],{"class":547,"line":683},[545,3452,3453],{"class":567},"## Capricciosa\n",[545,3455,3456],{"class":547,"line":706},[545,3457,3458],{"class":567},"A rich taste: mozzarella, ham, mushrooms, artichokes, and olives.\n",[545,3460,3461],{"class":547,"line":727},[545,3462,3463],{"class":567},"A true favourite!\n",[545,3465,3466,3468,3470,3472,3474,3476,3478],{"class":547,"line":743},[545,3467,1442],{"class":1441},[545,3469,2179],{"class":1445},[545,3471,1532],{"class":1441},[545,3473,2992],{"class":567},[545,3475,1538],{"class":1441},[545,3477,2179],{"class":1445},[545,3479,1436],{"class":1441},[11,3481,3482,3483,3485,3486,3488],{},"Asymptotic ",[116,3484,2669],{}," (kind of 'infinite' ",[116,3487,2669],{},") completely flattens the DOM, that is, leads to a full content linearisation similar to reader views as present in most browsers. Notably, it preserves all interactive elements like buttons – which are essential for a web agent.",[64,3490,3492],{"id":3491},"adaptived2snap",[2533,3493,3494],{},"AdaptiveD2Snap",[11,3496,3497,3498,3500,3501,3503],{},"Fixed parameters might not be ideal for arbitrary DOMs – sourced from a landscape of web applications. We created ",[2533,3499,3494],{}," – a wrapper for ",[2533,3502,2625],{}," that infers suitable parameters from a given DOM in order to hit a certain token budget.",[64,3505,3507],{"id":3506},"implementation-integration","Implementation & Integration",[11,3509,3510,3511,3513],{},"Picture an LLM-based weg agent that is premised on DOM snapshots. Implementing ",[2533,3512,2625],{}," is simple: Deep clone the DOM, and feed it to the algorithm. Now, take the snapshot; this is, serialise the resulting DOM. Done.",[2682,3515,3516],{},[11,3517,3518,3519,3523],{},"Read our ",[2489,3520,3522],{"href":3521},"/blog/a-gentle-introduction-to-ai-agents-for-the-web","gentle introduction to AI agents for the web"," to get started with high-level web agent concepts.",[11,3525,3526,3527,3529,3530,3535],{},"The open source ",[2533,3528,2625],{}," API, provided as a ",[2489,3531,3534],{"href":3532,"rel":3533},"https://github.com/webfuse-com/D2Snap",[2493],"package on GitHub"," provides the following signature:",[536,3537,3541],{"className":3538,"code":3539,"language":3540,"meta":541,"style":541},"language-ts shiki shiki-themes catppuccin-latte night-owl","type DOM = Document | Element | string;\ntype Options = {\n  assignUniqueIDs?: boolean; // false\n  debug?: boolean;           // true\n};\n\nD2Snap.d2Snap(\n  dom: DOM,\n  k: number, l: number, m: number,\n  options?: Options\n): Promise\u003Cstring>\n\nD2Snap.adaptiveD2Snap(\n  dom: DOM,\n  maxTokens: number = 4096,\n  maxIterations: number = 5,\n  options?: Options\n): Promise\u003Cstring>\n\n","ts",[116,3542,3543,3572,3583,3601,3615,3620,3624,3636,3648,3665,3675,3691,3695,3706,3714,3727,3739,3747],{"__ignoreMap":541},[545,3544,3545,3548,3552,3554,3558,3561,3564,3566,3570],{"class":547,"line":548},[545,3546,3547],{"class":551},"type",[545,3549,3551],{"class":3550},"sXbZB"," DOM ",[545,3553,1451],{"class":559},[545,3555,3557],{"class":3556},"s-DR7"," Document",[545,3559,3560],{"class":1441}," |",[545,3562,3563],{"class":3556}," Element",[545,3565,3560],{"class":1441},[545,3567,3569],{"class":3568},"scrte"," string",[545,3571,584],{"class":583},[545,3573,3574,3576,3579,3581],{"class":547,"line":587},[545,3575,3547],{"class":551},[545,3577,3578],{"class":3550}," Options ",[545,3580,1451],{"class":559},[545,3582,603],{"class":583},[545,3584,3585,3589,3592,3595,3598],{"class":547,"line":606},[545,3586,3588],{"class":3587},"swl0y","  assignUniqueIDs",[545,3590,3591],{"class":1441},"?:",[545,3593,3594],{"class":3568}," boolean",[545,3596,3597],{"class":583},";",[545,3599,3600],{"class":1100}," // false\n",[545,3602,3603,3606,3608,3610,3612],{"class":547,"line":634},[545,3604,3605],{"class":3587},"  debug",[545,3607,3591],{"class":1441},[545,3609,3594],{"class":3568},[545,3611,3597],{"class":583},[545,3613,3614],{"class":1100},"           // true\n",[545,3616,3617],{"class":547,"line":657},[545,3618,3619],{"class":583},"};\n",[545,3621,3622],{"class":547,"line":683},[545,3623,1095],{"emptyLinePlaceholder":1094},[545,3625,3626,3628,3630,3633],{"class":547,"line":706},[545,3627,2625],{"class":567},[545,3629,153],{"class":623},[545,3631,3632],{"class":563},"d2Snap",[545,3634,3635],{"class":567},"(\n",[545,3637,3638,3641,3645],{"class":547,"line":727},[545,3639,3640],{"class":567},"  dom: ",[545,3642,3644],{"class":3643},"sqxXB","DOM",[545,3646,3647],{"class":583},",\n",[545,3649,3650,3653,3655,3658,3660,3663],{"class":547,"line":743},[545,3651,3652],{"class":567},"  k: number",[545,3654,870],{"class":583},[545,3656,3657],{"class":567}," l: number",[545,3659,870],{"class":583},[545,3661,3662],{"class":567}," m: number",[545,3664,3647],{"class":583},[545,3666,3667,3670,3672],{"class":547,"line":1158},[545,3668,3669],{"class":567},"  options",[545,3671,3591],{"class":559},[545,3673,3674],{"class":567}," Options\n",[545,3676,3677,3680,3684,3686,3689],{"class":547,"line":1164},[545,3678,3679],{"class":567},"): ",[545,3681,3683],{"class":3682},"s8Irk","Promise",[545,3685,1442],{"class":559},[545,3687,3688],{"class":567},"string",[545,3690,1436],{"class":559},[545,3692,3693],{"class":547,"line":1170},[545,3694,1095],{"emptyLinePlaceholder":1094},[545,3696,3697,3699,3701,3704],{"class":547,"line":1176},[545,3698,2625],{"class":567},[545,3700,153],{"class":623},[545,3702,3703],{"class":563},"adaptiveD2Snap",[545,3705,3635],{"class":567},[545,3707,3708,3710,3712],{"class":547,"line":1181},[545,3709,3640],{"class":567},[545,3711,3644],{"class":3643},[545,3713,3647],{"class":583},[545,3715,3716,3719,3721,3725],{"class":547,"line":1196},[545,3717,3718],{"class":567},"  maxTokens: number ",[545,3720,1451],{"class":559},[545,3722,3724],{"class":3723},"sZ_Zo"," 4096",[545,3726,3647],{"class":583},[545,3728,3729,3732,3734,3737],{"class":547,"line":1384},[545,3730,3731],{"class":567},"  maxIterations: number ",[545,3733,1451],{"class":559},[545,3735,3736],{"class":3723}," 5",[545,3738,3647],{"class":583},[545,3740,3741,3743,3745],{"class":547,"line":1389},[545,3742,3669],{"class":567},[545,3744,3591],{"class":559},[545,3746,3674],{"class":567},[545,3748,3749,3751,3753,3755,3757],{"class":547,"line":1727},[545,3750,3679],{"class":567},[545,3752,3683],{"class":3682},[545,3754,1442],{"class":559},[545,3756,3688],{"class":567},[545,3758,1436],{"class":559},[11,3760,3761,3762,3764,3765,3770,3771,3776],{},"Moreover, ",[2533,3763,2625],{}," it is available on the ",[2489,3766,3769],{"href":3767,"rel":3768},"https://dev.webfuse.com/automation-api",[2493],"Webfuse Automation API",". ",[2489,3772,3775],{"href":3773,"rel":3774},"https://www.webfuse.com",[2493],"Webfuse"," essentially is a proxy to seamlessly serve any existing web application with custom augmentations, such as a web agent widget.",[536,3778,3782],{"className":3779,"code":3780,"language":3781,"meta":541,"style":541},"language-js shiki shiki-themes catppuccin-latte night-owl","const domSnapshot = await browser.webfuseSession\n    .automation\n    .take_dom_snapshot({ modifier: 'downsample' })\n","js",[116,3783,3784,3803,3812],{"__ignoreMap":541},[545,3785,3786,3788,3791,3793,3795,3797,3799],{"class":547,"line":548},[545,3787,552],{"class":551},[545,3789,3790],{"class":555}," domSnapshot",[545,3792,560],{"class":559},[545,3794,617],{"class":592},[545,3796,612],{"class":620},[545,3798,153],{"class":623},[545,3800,3802],{"class":3801},"s8apv","webfuseSession\n",[545,3804,3805,3808],{"class":547,"line":587},[545,3806,3807],{"class":623},"    .",[545,3809,3811],{"class":3810},"sL4Ga","automation\n",[545,3813,3814,3816,3819,3821,3824,3827,3829,3832,3835,3838,3840],{"class":547,"line":606},[545,3815,3807],{"class":623},[545,3817,3818],{"class":563},"take_dom_snapshot",[545,3820,568],{"class":567},[545,3822,3823],{"class":583},"{",[545,3825,3826],{"class":567}," modifier",[545,3828,879],{"class":878},[545,3830,3831],{"class":571}," '",[545,3833,3834],{"class":575},"downsample",[545,3836,3837],{"class":571},"'",[545,3839,781],{"class":583},[545,3841,3842],{"class":567},")\n",[11,3844,3845,3846,3848],{},"Need precise control over the underlying ",[2533,3847,2625],{}," invocation? Configure it exactly how you want:",[536,3850,3852],{"className":3779,"code":3851,"language":3781,"meta":541,"style":541},"const domSnapshot = await browser.webfuseSession\n    .automation\n    .take_dom_snapshot({\n        modifier: {\n            name: 'D2Snap',\n            params: { hierarchyRatio: 0.6, textRatio: 0.2, attributeRatio: 0.8 }\n        }\n    })\n",[116,3853,3854,3870,3876,3887,3896,3911,3951,3956],{"__ignoreMap":541},[545,3855,3856,3858,3860,3862,3864,3866,3868],{"class":547,"line":548},[545,3857,552],{"class":551},[545,3859,3790],{"class":555},[545,3861,560],{"class":559},[545,3863,617],{"class":592},[545,3865,612],{"class":620},[545,3867,153],{"class":623},[545,3869,3802],{"class":3801},[545,3871,3872,3874],{"class":547,"line":587},[545,3873,3807],{"class":623},[545,3875,3811],{"class":3810},[545,3877,3878,3880,3882,3884],{"class":547,"line":606},[545,3879,3807],{"class":623},[545,3881,3818],{"class":563},[545,3883,568],{"class":567},[545,3885,3886],{"class":583},"{\n",[545,3888,3889,3892,3894],{"class":547,"line":634},[545,3890,3891],{"class":567},"        modifier",[545,3893,879],{"class":878},[545,3895,603],{"class":583},[545,3897,3898,3901,3903,3905,3907,3909],{"class":547,"line":657},[545,3899,3900],{"class":567},"            name",[545,3902,879],{"class":878},[545,3904,3831],{"class":571},[545,3906,2625],{"class":575},[545,3908,3837],{"class":571},[545,3910,3647],{"class":583},[545,3912,3913,3916,3918,3920,3923,3925,3928,3930,3933,3935,3938,3940,3943,3945,3948],{"class":547,"line":683},[545,3914,3915],{"class":567},"            params",[545,3917,879],{"class":878},[545,3919,775],{"class":583},[545,3921,3922],{"class":567}," hierarchyRatio",[545,3924,879],{"class":878},[545,3926,3927],{"class":3723}," 0.6",[545,3929,870],{"class":583},[545,3931,3932],{"class":567}," textRatio",[545,3934,879],{"class":878},[545,3936,3937],{"class":3723}," 0.2",[545,3939,870],{"class":583},[545,3941,3942],{"class":567}," attributeRatio",[545,3944,879],{"class":878},[545,3946,3947],{"class":3723}," 0.8",[545,3949,3950],{"class":583}," }\n",[545,3952,3953],{"class":547,"line":706},[545,3954,3955],{"class":583},"        }\n",[545,3957,3958,3961],{"class":547,"line":727},[545,3959,3960],{"class":583},"    }",[545,3962,3842],{"class":567},[64,3964,3966],{"id":3965},"performance-evaluation","Performance Evaluation",[11,3968,3969,3970,3972,3973,3975,3976,3978],{},"Now for the moment of truth: How does ",[2533,3971,2625],{}," stack up against the industry standard? We evaluated ",[2533,3974,2625],{}," in comparison to a grounded GUI snapshot baseline close to those used by ",[2533,3977,2505],{}," – coloured bounding boxes around visible interactive elements.",[11,3980,3981,3982,3987],{},"To evaluate snapshots isolated from specific agent logic, we crafted a dataset that spans all UI states that occur while solving a related task. We sampled our dataset from the existing ",[2489,3983,3986],{"href":3984,"rel":3985},"https://github.com/OSU-NLP-Group/Online-Mind2Web",[2493],"Online-Mind2Web"," dataset.",[47,3989],{":width":3990,"alt":3991,"format":51,"loading":71,"src":3992},"800","Exemplary solution UI state trajectory of a defined web-based task","/blog/dom-downsampling-for-web-agents/3.png",[11,3994,3995],{},[2548,3996,3997],{},"Exemplary solution UI state trajectory for the task: “View the pricing plan for 'Business'. Specifically, we have 100 users. We need a 1PB storage quota and a 50 TB transfer quota.”",[11,3999,4000],{},"These are our key findings...",[2694,4002,4004],{"id":4003},"substantial-success-rates","Substantial Success Rates",[11,4006,4007,4008,4010],{},"The results exceeded our expectations. Not only did ",[2533,4009,2625],{}," meet the baseline's performance – our best configuration outperformed it by a significant margin. Full linearisation matches performance, and estimated model input token size order of the baseline.",[47,4012],{":width":4013,"alt":4014,"format":51,"loading":71,"src":4015},"550","Success rate per web agent snapshot subject evaluated across the dataset","/blog/dom-downsampling-for-web-agents/4.png",[2548,4017,4018,4019,4026,4027,4029,4030,4033,4034,4037,4038,4041,4042,4045,4046,4049,4050,4053],{},"\n  Success rate per web agent snapshot subject evaluated across the dataset.\n  Labels: ",[116,4020,4021,4022],{},"GUI",[4023,4024,4025],"sub",{}," gr.",": Baseline, ",[116,4028,3644],{},": Raw DOM (cut-off at ~8K tokens), ",[116,4031,4032],{},"k( l m)",": Parameter values; e.g., ",[116,4035,4036],{},".9 .3 .6",", or ",[116,4039,4040],{},".4"," if equal). ",[116,4043,4044],{},"∞",": Linearisation,  ",[116,4047,4048],{},"8192 / 32768",": via token-limited (resp.) ",[4051,4052,3494],"i",{},".\n",[2694,4055,4057],{"id":4056},"containable-token-and-byte-size","Containable Token and Byte Size",[11,4059,4060,4061,4063],{},"Even light downsampling delivers dramatic size reductions. Most ",[2533,4062,2625],{}," configurations average just one token order above the baseline – a massive improvement over raw DOM snapshots. Better yet, most DOMs from the dataset could actually be downsampled to the baseline order. And while image data balloons in file size, our text-based approach stays lean and efficient.",[47,4065],{":width":3990,"alt":4066,"format":51,"loading":71,"src":4067},"Comparison of mean input size across and per subject","/blog/dom-downsampling-for-web-agents/5.png",[2548,4069,4070,4071,4074,4075,4077],{},"\n  Left: Comparison of mean input size (tokens vs bytes) across and per subject.",[4072,4073],"br",{},"\n  Right: Estimated input token size across the dataset created by a single ",[4051,4076,2625],{}," evaluation subject.\n",[2694,4079,4081],{"id":4080},"hierarchy-actually-matters","Hierarchy Actually Matters",[11,4083,4084],{},"Which UI feature matters most for LLM web agent backend performance? We alternated parameter configurations to find out. Interestingly, hierarchy reveals itself as the strongest of the three assessed features. Element extraction throws away hierarchy, which suggests that downsampling is a superior technique.",[2705,4086,4089,4094],{"className":4087,"dataFootnotes":541},[4088],"footnotes",[56,4090,4093],{"className":4091,"id":2565},[4092],"sr-only","Footnotes",[2574,4095,4096,4111,4122,4133],{},[25,4097,4099,4103,4104],{"id":4098},"user-content-fn-1",[2489,4100,4101],{"href":4101,"rel":4102},"https://arxiv.org/abs/2210.03945",[2493]," ",[2489,4105,4110],{"href":4106,"ariaLabel":4107,"className":4108,"dataFootnoteBackref":541},"#user-content-fnref-1","Back to reference 1",[4109],"data-footnote-backref","↩",[25,4112,4114,4103,4117],{"id":4113},"user-content-fn-2",[2489,4115,2631],{"href":2631,"rel":4116},[2493],[2489,4118,4110],{"href":4119,"ariaLabel":4120,"className":4121,"dataFootnoteBackref":541},"#user-content-fnref-2","Back to reference 2",[4109],[25,4123,4125,4103,4128],{"id":4124},"user-content-fn-3",[2489,4126,3532],{"href":3532,"rel":4127},[2493],[2489,4129,4110],{"href":4130,"ariaLabel":4131,"className":4132,"dataFootnoteBackref":541},"#user-content-fnref-3","Back to reference 3",[4109],[25,4134,4136,4103,4140],{"id":4135},"user-content-fn-4",[2489,4137,4138],{"href":4138,"rel":4139},"https://aclanthology.org/W04-3252",[2493],[2489,4141,4110],{"href":4142,"ariaLabel":4143,"className":4144,"dataFootnoteBackref":541},"#user-content-fnref-4","Back to reference 4",[4109],[2389,4146,4147],{},"html pre.shiki code .s9rnR, html code.shiki .s9rnR{--shiki-default:#179299;--shiki-dark:#7FDBCA}html pre.shiki code .sY2RG, html code.shiki .sY2RG{--shiki-default:#1E66F5;--shiki-dark:#CAECE6}html pre.shiki code .swkLt, html code.shiki .swkLt{--shiki-default:#DF8E1D;--shiki-default-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic}html pre.shiki code .sbuKk, html code.shiki .sbuKk{--shiki-default:#40A02B;--shiki-dark:#D9F5DD}html pre.shiki code .sfrMT, html code.shiki .sfrMT{--shiki-default:#40A02B;--shiki-dark:#ECC48D}html pre.shiki code .s2kId, html code.shiki .s2kId{--shiki-default:#4C4F69;--shiki-dark:#D6DEEB}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s76yb, html code.shiki .s76yb{--shiki-default:#8839EF;--shiki-dark:#C792EA}html pre.shiki code .sXbZB, html code.shiki .sXbZB{--shiki-default:#DF8E1D;--shiki-default-font-style:italic;--shiki-dark:#D6DEEB;--shiki-dark-font-style:inherit}html pre.shiki code .s-_ek, html code.shiki .s-_ek{--shiki-default:#179299;--shiki-dark:#C792EA}html pre.shiki code .s-DR7, html code.shiki .s-DR7{--shiki-default:#DF8E1D;--shiki-default-font-style:italic;--shiki-dark:#FFCB8B;--shiki-dark-font-style:inherit}html pre.shiki code .scrte, html code.shiki .scrte{--shiki-default:#8839EF;--shiki-dark:#C5E478}html pre.shiki code .scGhl, html code.shiki .scGhl{--shiki-default:#7C7F93;--shiki-dark:#D6DEEB}html pre.shiki code .swl0y, html code.shiki .swl0y{--shiki-default:#4C4F69;--shiki-default-font-style:italic;--shiki-dark:#D6DEEB;--shiki-dark-font-style:inherit}html pre.shiki code .sDmS1, html code.shiki .sDmS1{--shiki-default:#7C7F93;--shiki-default-font-style:italic;--shiki-dark:#637777;--shiki-dark-font-style:italic}html pre.shiki code .s5FwJ, html code.shiki .s5FwJ{--shiki-default:#179299;--shiki-default-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic}html pre.shiki code .sNstc, html code.shiki .sNstc{--shiki-default:#1E66F5;--shiki-default-font-style:italic;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic}html pre.shiki code .sqxXB, html code.shiki .sqxXB{--shiki-default:#4C4F69;--shiki-dark:#82AAFF}html pre.shiki code .s8Irk, html code.shiki .s8Irk{--shiki-default:#DF8E1D;--shiki-default-font-style:italic;--shiki-dark:#C5E478;--shiki-dark-font-style:inherit}html pre.shiki code .sZ_Zo, html code.shiki .sZ_Zo{--shiki-default:#FE640B;--shiki-dark:#F78C6C}html pre.shiki code .scsc5, html code.shiki .scsc5{--shiki-default:#4C4F69;--shiki-default-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic}html pre.shiki code .srhcd, html code.shiki .srhcd{--shiki-default:#8839EF;--shiki-default-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic}html pre.shiki code .sP4PM, html code.shiki .sP4PM{--shiki-default:#4C4F69;--shiki-default-font-style:inherit;--shiki-dark:#7FDBCA;--shiki-dark-font-style:italic}html pre.shiki code .s8apv, html code.shiki .s8apv{--shiki-default:#4C4F69;--shiki-default-font-style:inherit;--shiki-dark:#BAEBE2;--shiki-dark-font-style:italic}html pre.shiki code .sL4Ga, html code.shiki .sL4Ga{--shiki-default:#4C4F69;--shiki-dark:#BAEBE2}html pre.shiki code .sVS64, html code.shiki .sVS64{--shiki-default:#179299;--shiki-dark:#D6DEEB}",{"title":541,"searchDepth":587,"depth":587,"links":4149},[4150,4154,4155,4162],{"id":2513,"depth":587,"text":2514,"children":4151},[4152,4153],{"id":2523,"depth":606,"text":2524},{"id":2553,"depth":606,"text":2554},{"id":2604,"depth":587,"text":2605},{"id":2622,"depth":587,"text":2625,"children":4156},[4157,4158,4159,4160,4161],{"id":2659,"depth":606,"text":2660},{"id":2779,"depth":606,"text":2780},{"id":3491,"depth":606,"text":3494},{"id":3506,"depth":606,"text":3507},{"id":3965,"depth":606,"text":3966},{"id":2565,"depth":587,"text":4093},"2025-08-18","We propose D2Snap – a first-of-its-kind downsampling algorithm for DOMs. D2Snap can be used as a pre-processing technique for DOM snapshots to optimise web agency context quality and token costs.",{"homepage":1094,"relatedLinks":4166},[4167,4171,4174],{"text":4168,"href":4169,"description":4170},"What is a Website Snapshot?","/blog/snapshots-provide-llms-with-website-state","Learn what a website snapshot is and how to utilise it for web agents",{"text":4172,"href":3521,"description":4173},"What is a Web Agent?","Learn the basics of web agents",{"text":3769,"href":4175,"external":1094,"description":4176},"https://dev.webfuse.com/automation-api#take_dom_snapshot","Check out the Webfuse Automation API","/blog/dom-downsampling-for-llm-based-web-agents",{"title":2478,"description":4164},{"loc":4177},"blog/1012.dom-downsampling-for-llm-based-web-agents",[2431,4182,4183,4184,2473,4185],"browser-agents","llms","llm-context","web-automation","lDh50lEtos4T_tIdGCLKDox16i6ixbPnRxPJoFpKjnE",{"id":4188,"title":4189,"authorId":2479,"body":4190,"category":2431,"created":4915,"description":4916,"extension":2434,"faqs":2452,"featurePriority":587,"head":2452,"landingPath":2452,"meta":4917,"navigation":1094,"ogImage":2452,"path":3521,"robots":2452,"schemaOrg":2452,"seo":4926,"sitemap":4927,"stem":4928,"tags":4929,"__hash__":4930},"blog/blog/1011.a-gentle-introduction-to-ai-agents-for-the-web.md","A Gentle Introduction to AI Agents for the Web",{"type":8,"value":4191,"toc":4896},[4192,4206,4209,4216,4222,4226,4229,4244,4248,4258,4262,4266,4279,4283,4287,4290,4295,4299,4308,4312,4323,4328,4332,4350,4354,4360,4459,4462,4695,4711,4715,4718,4723,4727,4730,4734,4752,4777,4784,4788,4826,4829,4840,4844,4847,4875,4879,4887,4893],[11,4193,4194,4195,2495,4199,2673,4202,4205],{},"In no time, AI became a natural part of modern web interfaces. AI agents for the web enjoy a recent hype, sparked by the means of ",[2489,4196,2494],{"href":4197,"rel":4198},"https://openai.com/index/introducing-operator/",[2493],[2489,4200,2500],{"href":2498,"rel":4201},[2493],[2489,4203,2505],{"href":2503,"rel":4204},[2493],". By now, it is within reach to automate arbitrary web-based tasks, such as booking the cheapest flight from Berlin to Amsterdam.",[56,4207,4172],{"id":4208},"what-is-a-web-agent",[11,4210,4211,4212,4215],{},"For starters, let us break down the term ",[15,4213,4214],{},"web AI agent",": An agent is an entity that autonomously acts on behalf of another entity. An artificially intelligent agent is an application that acts on behalf of a human. In contrast to non-AI computer agents, it solves complex tasks with at least human-grade effectiveness and efficiency. For a human-centric web, web agents have deliberately been designed to browse the web in a human fashion – through UIs rather than APIs.",[47,4217],{":width":4218,"alt":4219,"format":4220,"loading":71,"src":4221},"610","High-level agent description comparing human and computer agents","svg","/blog/a-gentle-introduction-to-ai-agents-for-the-web/1.svg",[64,4223,4225],{"id":4224},"the-role-of-frontier-llms","The Role of Frontier LLMs",[11,4227,4228],{},"Web agents have been a vague desire for a long time. AI agents used to rely on complete models of a problem domain in order to allow (heuristic) search through problem states. Such models would comprise the problem world (e.g., a chessboard), actors (pawns, rooks, etc.), possible actions per actor (rook moves straight), and constraints (i.a., max one piece per field). A heterogeneous space of web application UIs describes the problem domain of a web agent: how to understand a web page, and how to interact with it to solve the declared task?",[11,4230,4231,4232,4239,4240,4243],{},"Frontier LLMs disrupted the AI agent world: explicit problem domain models beyond feasibility can now be replaced by an LLM. The LLM thereby acts as an instantaneous domain model backend that can be consulted with twofold context: serialised problem state, such as a chess position code (",[2533,4233,4234,4235,4238],{},"“",[545,4236,4237],{},"..."," e4 e5 2. Nc3 f5”","), and the respective task (",[2533,4241,4242],{},"“What is the best move for white?”","). For web agents, problem state corresponds to the currently browsed web application's runtime state, for instance, a screenshot.",[64,4245,4247],{"id":4246},"generalist-web-agents","Generalist Web Agents",[11,4249,4250,4251,2673,4254,4257],{},"Generalist web agents are supposed to solve arbitrary tasks through a web browser. Web-based tasks can be as diverse as ",[2533,4252,4253],{},"“Find a picture of a cat.”",[2533,4255,4256],{},"“Book the cheapest flight from Berlin to Amsterdam tomorrow afternoon (business class, window seat).”"," In reality, generalist agents still fail uncommon or too precise tasks. While they have been critically acclaimed, they mainly act as early proofs-of-concept. Tasks that are indeed solvable with a generalist agent promise great results with an according specialist agent.",[47,4259],{":width":49,"alt":4260,"format":51,"loading":71,"src":4261},"Screenshot of a generalist web agent UI (Director)","/blog/a-gentle-introduction-to-ai-agents-for-the-web/2.png",[64,4263,4265],{"id":4264},"specialist-web-agents","Specialist Web Agents",[11,4267,4268,4269,4272,4273,4278],{},"Other than generalist agents, specialist web agents are constrained to a certain task and application domain. Specialist agents bear the major share of commercial value. Most prominently, modal chat agents that provide users with on-page help. Picture a little floating widget that can be chatted to via text or voice input. In most cases, in fact, the term ",[2533,4270,4271],{},"web (AI) agent"," refers to chat agents. Chat agents – text or voice – can be implemented on top of virtually any existing website. Frontier LLMs provide a lot of commonsense out-of-the-box. A ",[2489,4274,4277],{"href":4275,"rel":4276},"https://docs.claude.com/en/docs/build-with-claude/prompt-engineering/system-prompts",[2493],"system prompt"," can, moreover, be leveraged to drive specialist agent quality for the respective problem domain.",[47,4280],{":width":49,"alt":4281,"format":51,"loading":71,"src":4282},"Screenshots of two modal specialist web agent UIs augmenting an underlying website's UI","/blog/a-gentle-introduction-to-ai-agents-for-the-web/3.png",[56,4284,4286],{"id":4285},"how-does-a-web-agent-work","How Does a Web Agent Work?",[11,4288,4289],{},"LLM-based web agents are premised on a more or less uniform architecture. The agent application embodies a mediator between a web browser (environment), and the LLM backend (model).",[47,4291],{":width":4292,"alt":4293,"format":4220,"loading":71,"src":4294},"480","High-level web agent architecture component view","/blog/a-gentle-introduction-to-ai-agents-for-the-web/4.svg",[64,4296,4298],{"id":4297},"the-agent-lifecycle","The Agent Lifecycle",[11,4300,4301,4302,4307],{},"To reduce a user's cognitive load, solving a web-based task is usually chunked into a sequence of UI states. Consider looking for rental apartments on ",[2489,4303,4306],{"href":4304,"rel":4305},"https://www.redfin.com",[2493],"redfin.com",": In the first step, you specify a location. Only subsequently are you provided with a grid of available apartments for that location.",[47,4309],{":width":49,"alt":4310,"format":51,"loading":71,"src":4311},"Example of separated UI states in a rental home search application","/blog/a-gentle-introduction-to-ai-agents-for-the-web/5.png",[11,4313,4314,4315,4322],{},"Web agent logic is iterative; not least for a sequential web interaction model, but also for a conversational agent interaction model. Browsing the web, human and computer agents represent users alike. That said, Norman's well-known ",[2489,4316,4319],{"href":4317,"rel":4318},"https://mitpress.mit.edu/9780262640374/the-design-of-everyday-things/",[2493],[2533,4320,4321],{},"Seven Stages of Action",", which hierarchically model the human cognition cycle, transfer to the web agent lifecycle. For each UI state in a web browser (environment) and web-based task (action intention); decide where to click, type, etc. (action planning), and perform those clicks, etc. (action execution). Afterwards, perceive, interpret, and evaluate the results of those actions in the web browser (state). As long as there is a mismatch between the evaluated state and the declared goal state, repeat that cycle. Potentially prompt the user with more required information.",[47,4324],{":width":4325,"alt":4326,"format":4220,"loading":71,"src":4327},"580","Donald 'Norman's Seven Stages of Action' model of the human cognition cycle that transfers to non-human agents","/blog/a-gentle-introduction-to-ai-agents-for-the-web/6.svg",[64,4329,4331],{"id":4330},"web-context-for-llms","Web Context for LLMs",[11,4333,4334,4335,4337,4338,4341,4342,4345,4346,4349],{},"The gap from an agent towards the environment, according to ",[2533,4336,4321],{},", is known as the ",[2533,4339,4340],{},"gulf of execution",". In real-world scenarios, how to act in the environment in respect to a planned sequence of actions might be difficult (e.g., how to actually open the trunk of a new car?). Arguably, web agents face a novel ",[2533,4343,4344],{},"gulf of intention"," towards the action planning stage: how to serialise a currently browsed web page's runtime state for LLMs? ",[2533,4347,4348],{},"Snapshot"," is a more comprehensive term to describe the serialisation of a web page's current runtime state. Screenshots, for instance, represent a type of snapshot that closely resembles how humans perceive a web page at a given point in time. But are they as accessible to LLMs?",[64,4351,4353],{"id":4352},"agentic-ui-interaction","Agentic UI Interaction",[11,4355,4356,4357,4359],{},"With a qualified set of well-defined actuation methods, web agents are able to close the ",[2533,4358,4340],{}," quite well. HTML element types strongly afford a certain action (e.g., click a button, type to a field). Below is how an actuation schema to present the LLM backend with could look like:",[536,4361,4363],{"className":3538,"code":4362,"language":3540,"meta":541,"style":541},"interface ActuationSchema = {\n    thought: string;\n    action: \"click\"\n        | \"scroll\"\n        | \"type\";\n    cssSelector: string;\n    data?: string;\n}[];\n",[116,4364,4365,4378,4389,4404,4416,4428,4439,4450],{"__ignoreMap":541},[545,4366,4367,4370,4373,4376],{"class":547,"line":548},[545,4368,4369],{"class":551},"interface",[545,4371,4372],{"class":3550}," ActuationSchema",[545,4374,4375],{"class":567}," = ",[545,4377,3886],{"class":583},[545,4379,4380,4383,4385,4387],{"class":547,"line":587},[545,4381,4382],{"class":567},"    thought",[545,4384,879],{"class":1441},[545,4386,3569],{"class":3568},[545,4388,584],{"class":583},[545,4390,4391,4394,4396,4398,4402],{"class":547,"line":606},[545,4392,4393],{"class":567},"    action",[545,4395,879],{"class":1441},[545,4397,882],{"class":571},[545,4399,4401],{"class":4400},"sgAC-","click",[545,4403,2062],{"class":571},[545,4405,4406,4409,4411,4414],{"class":547,"line":634},[545,4407,4408],{"class":1441},"        |",[545,4410,882],{"class":571},[545,4412,4413],{"class":4400},"scroll",[545,4415,2062],{"class":571},[545,4417,4418,4420,4422,4424,4426],{"class":547,"line":657},[545,4419,4408],{"class":1441},[545,4421,882],{"class":571},[545,4423,3547],{"class":4400},[545,4425,572],{"class":571},[545,4427,584],{"class":583},[545,4429,4430,4433,4435,4437],{"class":547,"line":683},[545,4431,4432],{"class":567},"    cssSelector",[545,4434,879],{"class":1441},[545,4436,3569],{"class":3568},[545,4438,584],{"class":583},[545,4440,4441,4444,4446,4448],{"class":547,"line":706},[545,4442,4443],{"class":567},"    data",[545,4445,3591],{"class":1441},[545,4447,3569],{"class":3568},[545,4449,584],{"class":583},[545,4451,4452,4454,4457],{"class":547,"line":727},[545,4453,746],{"class":583},[545,4455,4456],{"class":567},"[]",[545,4458,584],{"class":583},[11,4460,4461],{},"And a suggested actions response could, in turn, look as follows:",[536,4463,4467],{"className":4464,"code":4465,"language":4466,"meta":541,"style":541},"language-json shiki shiki-themes catppuccin-latte night-owl","[\n    {\n        \"thought\": \"Scroll newsletter cta into view\",\n        \"action\": \"scroll\",\n        \"cssSelector\": \"section#newsletter\"\n    },\n    {\n        \"thought\": \"Type email address to newsletter cta\",\n        \"action\": \"type\",\n        \"cssSelector\": \"section#newsletter > input\",\n        \"data\": \"user@example.org\"\n    },\n    {\n        \"thought\": \"Submit newsletter sign up\",\n        \"action\": \"click\",\n        \"cssSelector\": \"section#newsletter > button\"\n    }\n]\n","json",[116,4468,4469,4474,4479,4503,4522,4540,4545,4549,4568,4586,4605,4623,4627,4631,4650,4668,4685,4690],{"__ignoreMap":541},[545,4470,4471],{"class":547,"line":548},[545,4472,4473],{"class":583},"[\n",[545,4475,4476],{"class":547,"line":587},[545,4477,4478],{"class":583},"    {\n",[545,4480,4481,4485,4489,4491,4493,4495,4499,4501],{"class":547,"line":606},[545,4482,4484],{"class":4483},"srFR9","        \"",[545,4486,4488],{"class":4487},"s30W1","thought",[545,4490,572],{"class":4483},[545,4492,879],{"class":583},[545,4494,882],{"class":571},[545,4496,4498],{"class":4497},"sCC8C","Scroll newsletter cta into view",[545,4500,572],{"class":571},[545,4502,3647],{"class":583},[545,4504,4505,4507,4510,4512,4514,4516,4518,4520],{"class":547,"line":634},[545,4506,4484],{"class":4483},[545,4508,4509],{"class":4487},"action",[545,4511,572],{"class":4483},[545,4513,879],{"class":583},[545,4515,882],{"class":571},[545,4517,4413],{"class":4497},[545,4519,572],{"class":571},[545,4521,3647],{"class":583},[545,4523,4524,4526,4529,4531,4533,4535,4538],{"class":547,"line":657},[545,4525,4484],{"class":4483},[545,4527,4528],{"class":4487},"cssSelector",[545,4530,572],{"class":4483},[545,4532,879],{"class":583},[545,4534,882],{"class":571},[545,4536,4537],{"class":4497},"section#newsletter",[545,4539,2062],{"class":571},[545,4541,4542],{"class":547,"line":683},[545,4543,4544],{"class":583},"    },\n",[545,4546,4547],{"class":547,"line":706},[545,4548,4478],{"class":583},[545,4550,4551,4553,4555,4557,4559,4561,4564,4566],{"class":547,"line":727},[545,4552,4484],{"class":4483},[545,4554,4488],{"class":4487},[545,4556,572],{"class":4483},[545,4558,879],{"class":583},[545,4560,882],{"class":571},[545,4562,4563],{"class":4497},"Type email address to newsletter cta",[545,4565,572],{"class":571},[545,4567,3647],{"class":583},[545,4569,4570,4572,4574,4576,4578,4580,4582,4584],{"class":547,"line":743},[545,4571,4484],{"class":4483},[545,4573,4509],{"class":4487},[545,4575,572],{"class":4483},[545,4577,879],{"class":583},[545,4579,882],{"class":571},[545,4581,3547],{"class":4497},[545,4583,572],{"class":571},[545,4585,3647],{"class":583},[545,4587,4588,4590,4592,4594,4596,4598,4601,4603],{"class":547,"line":1158},[545,4589,4484],{"class":4483},[545,4591,4528],{"class":4487},[545,4593,572],{"class":4483},[545,4595,879],{"class":583},[545,4597,882],{"class":571},[545,4599,4600],{"class":4497},"section#newsletter > input",[545,4602,572],{"class":571},[545,4604,3647],{"class":583},[545,4606,4607,4609,4612,4614,4616,4618,4621],{"class":547,"line":1164},[545,4608,4484],{"class":4483},[545,4610,4611],{"class":4487},"data",[545,4613,572],{"class":4483},[545,4615,879],{"class":583},[545,4617,882],{"class":571},[545,4619,4620],{"class":4497},"user@example.org",[545,4622,2062],{"class":571},[545,4624,4625],{"class":547,"line":1170},[545,4626,4544],{"class":583},[545,4628,4629],{"class":547,"line":1176},[545,4630,4478],{"class":583},[545,4632,4633,4635,4637,4639,4641,4643,4646,4648],{"class":547,"line":1181},[545,4634,4484],{"class":4483},[545,4636,4488],{"class":4487},[545,4638,572],{"class":4483},[545,4640,879],{"class":583},[545,4642,882],{"class":571},[545,4644,4645],{"class":4497},"Submit newsletter sign up",[545,4647,572],{"class":571},[545,4649,3647],{"class":583},[545,4651,4652,4654,4656,4658,4660,4662,4664,4666],{"class":547,"line":1196},[545,4653,4484],{"class":4483},[545,4655,4509],{"class":4487},[545,4657,572],{"class":4483},[545,4659,879],{"class":583},[545,4661,882],{"class":571},[545,4663,4401],{"class":4497},[545,4665,572],{"class":571},[545,4667,3647],{"class":583},[545,4669,4670,4672,4674,4676,4678,4680,4683],{"class":547,"line":1384},[545,4671,4484],{"class":4483},[545,4673,4528],{"class":4487},[545,4675,572],{"class":4483},[545,4677,879],{"class":583},[545,4679,882],{"class":571},[545,4681,4682],{"class":4497},"section#newsletter > button",[545,4684,2062],{"class":571},[545,4686,4687],{"class":547,"line":1389},[545,4688,4689],{"class":583},"    }\n",[545,4691,4692],{"class":547,"line":1727},[545,4693,4694],{"class":583},"]\n",[2682,4696,4697],{},[11,4698,4699,4704,4705,4710],{},[2489,4700,4703],{"href":4701,"rel":4702},"https://platform.openai.com/docs/guides/function-calling",[2493],"Function Calling"," and the ",[2489,4706,4709],{"href":4707,"rel":4708},"https://modelcontextprotocol.io",[2493],"Model Context Protocol"," represent two ends to outsource an explicit actuation model – server- and client-side, respectively.",[64,4712,4714],{"id":4713},"agentic-ui-augmentation","Agentic UI Augmentation",[11,4716,4717],{},"An agent represents yet another feature to integrate with an application and its UI. Discoverability and availability, however, are among the most fundamental requirements of a web agent. Evidently, when a user experiences UI/UX friction, at least the agent should be interactive. That said, a scrolling modal web agent UI has been the go-to approach, that is, a little floating widget on top of the underlying application's UI. It comes with a major advantage: the agent application can be decoupled from the underlying, self-contained application.",[47,4719],{":width":4720,"alt":4721,"format":4220,"loading":71,"src":4722},"360","Depiction of a web agent application augmenting an underlying application in an isolated layer","/blog/a-gentle-introduction-to-ai-agents-for-the-web/7.svg",[56,4724,4726],{"id":4725},"how-to-build-a-web-agent","How to Build a Web Agent?",[11,4728,4729],{},"Believe it or not: enhancing an existing web application with a purposeful agent is a lower-hanging fruit. The evolving agent ecosystem provides you with a spectrum of solutions: instantly use a pre-compiled agent, tweak a templated agent, or develop an agent from scratch. Either way, LLMs and web browsers exist for reuse, boiling down agent development to LLM context engineering, and UI augmentation.",[64,4731,4733],{"id":4732},"develop-a-web-agent","Develop a Web Agent",[11,4735,4736,4737,4740,4741,2673,4746,4751],{},"Opting for a ",[15,4738,4739],{},"pre-compiled agent"," does not necessarily involve any actual development step. Instead, pre-compiled agents allow for high-level configuration through an agent-as-a-service provider's interface. Popular agent-as-a-service providers are, i.a., ",[2489,4742,4745],{"href":4743,"rel":4744},"https://elevenlabs.io/conversational-ai",[2493],"ElevenLabs",[2489,4747,4750],{"href":4748,"rel":4749},"https://www.intercom.com/drlp/ai-agent",[2493],"Intercom",". Serviced agents hide LLM communication and potentially interaction with a web browser behind the configuration interface.",[11,4753,4754,4755,4758,4759,4764,4765,4770,4771,4776],{},"Using a ",[15,4756,4757],{},"templated agent"," resembles the agent-as-a-service approach on a lower level. Openly sourced from a ",[2489,4760,4763],{"href":4761,"rel":4762},"https://github.com/webfuse-com/agent-extension-blueprint",[2493],"code repository",", templated agents allow for any kind of development tweaks. Favourably, agent templates shortcut integration with ",[2489,4766,4769],{"href":4767,"rel":4768},"https://openai.com/api/",[2493],"LLM APIs"," and web ",[2489,4772,4775],{"href":4773,"rel":4774},"https://developer.mozilla.org/en-US/docs/Web/API",[2493],"browser APIs",". Using a templated agent usually represents the preferable, best-of-both-worlds approach; common- and best-practice code snippets are available from the beginning, but everything can be customised as desired.",[11,4778,4779,4780,4783],{},"Of course, developing an ",[15,4781,4782],{},"agent from scratch"," is always an option. It is preferable whenever agent requirements deviate to a large extent from what exists in the service or template landscape.",[64,4785,4787],{"id":4786},"deploy-a-web-agent","Deploy a Web Agent",[11,4789,4790,4791,195,4796,4801,4802,4807,4808,4813,4814,4819,4820,4825],{},"When web agent code lives side-by-side with the augmented application's code, agent deployment is covered by a generic pipeline. Something like: ",[2489,4792,4795],{"href":4793,"rel":4794},"https://eslint.org",[2493],"linting",[2489,4797,4800],{"href":4798,"rel":4799},"https://prettier.io",[2493],"formatting"," agent code, ",[2489,4803,4806],{"href":4804,"rel":4805},"https://esbuild.github.io",[2493],"transpiling and bundling"," agent modules, ",[2489,4809,4812],{"href":4810,"rel":4811},"https://www.cypress.io",[2493],"testing"," agent, ",[2489,4815,4818],{"href":4816,"rel":4817},"https://pages.cloudflare.com",[2493],"hosting"," agent bundle, and ",[2489,4821,4824],{"href":4822,"rel":4823},"https://docs.github.com/en/actions/get-started/continuous-integration",[2493],"tiggering"," post deployment events. In that case, an agent represents a modular feature component in the application, no different than, for instance, a sign-up component.",[11,4827,4828],{},"Web agent source code right inside the application codebase comes at a cost:",[22,4830,4831,4834,4837],{},[25,4832,4833],{},"Agent developers can manipulate the source code of the underlying application.",[25,4835,4836],{},"Agent functionality could introduce side effects on the underlying application.",[25,4838,4839],{},"Agent changes require deployment of the entire application.",[64,4841,4843],{"id":4842},"best-practices-of-agentic-ux","Best Practices of Agentic UX",[11,4845,4846],{},"When designing user experiences for agent-enhanced applications, there are a few things to consider:",[22,4848,4849,4850,4849,4859,4849,4867],{},"\n    ",[25,4851,4852,4853,4852,4856,4858],{},"\n        ",[15,4854,4855],{},"Stream input and output to reduce latency",[4072,4857],{},"\n        LLMs (re-)introduce noticeable communication round-trip time. To reduce wait time for the human user, stream chunks of data whenever they are available.\n    ",[25,4860,4852,4861,4852,4864,4866],{},[15,4862,4863],{},"Provide fine-grained feedback to bridge high-latency",[4072,4865],{},"\n        Human attention is sensitive to several seconds of [system response time](https://www.nngroup.com/articles/response-times-3-important-limits/). Periodically provide agent _thoughts_ as feedback to perceptibly break down round-trip time.\n    ",[25,4868,4852,4869,4852,4872,4874],{},[15,4870,4871],{},"Always prompt the human user for consent to perform critical actions",[4072,4873],{},"\n        Some actions in a web application lead to irreversible or significant changes of state. Never have the agent perform such actions on behalf of the user without explicitly asking for the permission.\n    ",[64,4876,4878],{"id":4877},"non-invasive-web-agents-with-webfuse","Non-Invasive Web Agents with Webfuse",[11,4880,4881,4886],{},[2489,4882,4884],{"href":3773,"rel":4883},[2493],[15,4885,3775],{}," is a configurable web proxy that lets you augment any web application. As pictured, web agents represent highly self-contained applications. Moreover, web agents and underlying applications communicate at runtime in the client. This does, in fact, render opportunities to bridge the above-mentioned drawbacks with Webfuse: Develop web agents with a sandbox extension methodology, and deploy them through the low-latency proxy layer. On demand, seamlessly serve users with your agent-enhanced website. Benefit from information hiding, safe code, and fewer deployments.",[4888,4889],"article-signup-cta",{":demoAction":4890,"heading":4891,"subtitle":4892},"{\"text\":\"Read more\",\"showIcon\":false,\"href\":\"https://www.webfuse.com/blog/category/ai-agents\"}","Deploy Web Agents with Webfuse","Develop or deploy web agents in minutes; serve agent-enhanced websites through an isolated application layer.",[2389,4894,4895],{},"html pre.shiki code .scGhl, html code.shiki .scGhl{--shiki-default:#7C7F93;--shiki-dark:#D6DEEB}html pre.shiki code .srFR9, html code.shiki .srFR9{--shiki-default:#7C7F93;--shiki-dark:#7FDBCA}html pre.shiki code .s30W1, html code.shiki .s30W1{--shiki-default:#1E66F5;--shiki-dark:#7FDBCA}html pre.shiki code .sbuKk, html code.shiki .sbuKk{--shiki-default:#40A02B;--shiki-dark:#D9F5DD}html pre.shiki code .sCC8C, html code.shiki .sCC8C{--shiki-default:#40A02B;--shiki-dark:#C789D6}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s76yb, html code.shiki .s76yb{--shiki-default:#8839EF;--shiki-dark:#C792EA}html pre.shiki code .sXbZB, html code.shiki .sXbZB{--shiki-default:#DF8E1D;--shiki-default-font-style:italic;--shiki-dark:#D6DEEB;--shiki-dark-font-style:inherit}html pre.shiki code .s2kId, html code.shiki .s2kId{--shiki-default:#4C4F69;--shiki-dark:#D6DEEB}html pre.shiki code .s9rnR, html code.shiki .s9rnR{--shiki-default:#179299;--shiki-dark:#7FDBCA}html pre.shiki code .scrte, html code.shiki .scrte{--shiki-default:#8839EF;--shiki-dark:#C5E478}html pre.shiki code .sgAC-, html code.shiki .sgAC-{--shiki-default:#40A02B;--shiki-default-font-style:italic;--shiki-dark:#ECC48D;--shiki-dark-font-style:inherit}",{"title":541,"searchDepth":587,"depth":587,"links":4897},[4898,4903,4909],{"id":4208,"depth":587,"text":4172,"children":4899},[4900,4901,4902],{"id":4224,"depth":606,"text":4225},{"id":4246,"depth":606,"text":4247},{"id":4264,"depth":606,"text":4265},{"id":4285,"depth":587,"text":4286,"children":4904},[4905,4906,4907,4908],{"id":4297,"depth":606,"text":4298},{"id":4330,"depth":606,"text":4331},{"id":4352,"depth":606,"text":4353},{"id":4713,"depth":606,"text":4714},{"id":4725,"depth":587,"text":4726,"children":4910},[4911,4912,4913,4914],{"id":4732,"depth":606,"text":4733},{"id":4786,"depth":606,"text":4787},{"id":4842,"depth":606,"text":4843},{"id":4877,"depth":606,"text":4878},"2025-06-15","LLMs only recently enabled serviceable web agents: autonomous systems that browse web on behalf of a human. Get started with fundamental methodology, key design challenges, and technological opportunities.",{"homepage":1094,"relatedLinks":4918},[4919,4920,4924],{"text":4168,"href":4169,"description":4170},{"text":4921,"href":4922,"description":4923},"Develop an AI Agent for Any Website with Webfuse","/blog/develop-an-ai-agent-for-any-website-with-webfuse","Learn how to develop and deploy a web agent for any website with Webfuse",{"text":3769,"href":4925,"external":1094,"description":4176},"https://dev.webfuse.com/automation-api/",{"title":4189,"description":4916},{"loc":3521},"blog/1011.a-gentle-introduction-to-ai-agents-for-the-web",[2431,4182,4183,2473,4185],"NE1cc8w1586RjefKyr028dgV7yBmf460jhZy91LninA",1775834759176]