[{"data":1,"prerenderedAt":2950},["ShallowReactive",2],{"/blog/headless-browsers-vs-live-sessions-for-customer-facing-ai-agents":3,"related-/blog/headless-browsers-vs-live-sessions-for-customer-facing-ai-agents":517},{"id":4,"title":5,"authorId":6,"body":7,"category":476,"created":477,"description":478,"extension":479,"faqs":480,"featurePriority":493,"head":494,"landingPath":494,"meta":495,"navigation":506,"ogImage":494,"path":507,"robots":494,"schemaOrg":494,"seo":508,"sitemap":509,"stem":510,"tags":511,"__hash__":516},"blog/blog/1047.headless-browsers-vs-live-sessions-for-customer-facing-ai-agents.md","Headless Browsers vs Live Sessions: Which Is Right for Customer-Facing AI Agents? (2026)","salome-koshadze",{"type":8,"value":9,"toc":459},"minimark",[10,14,17,43,46,49,58,63,66,69,73,76,80,83,86,89,93,98,105,108,134,138,143,146,172,176,179,182,208,213,217,220,223,234,237,240,244,247,250,254,298,302,305,331,335,339,342,368,372,375,378,456],[11,12,13],"p",{},"Customer-facing AI agents need more than text generation. They need to act in a browser, respond quickly enough for live conversation, and work inside the user's authenticated session.",[11,15,16],{},"That usually leads to two implementation models: run a headless browser on remote infrastructure, or run inside the user's live browser session. Both can work, but they solve different problems. Headless browsers are a good fit for background automation. Live sessions are often a better fit for customer-facing voice and support workflows, where latency, authentication, and visibility matter.",[18,19,21],"tldr-box",{"title":20},"Quick Summary",[22,23,24,32,38],"ul",{},[25,26,27,31],"li",{},[28,29,30],"strong",{},"Headless browsers"," are a strong fit for scraping, testing, and batch automation.",[25,33,34,37],{},[28,35,36],{},"Live sessions"," are a better fit when a user is already on the page and needs to see the agent act in real time.",[25,39,40],{},[28,41,42],{},"For voice agents, latency often decides the architecture.",[11,44,45],{},"The main challenge is not deciding what action to take. It is executing that action reliably in a modern web app. A model may produce the right form values, but the action can still fail if the target sits inside an unhydrated React Suspense boundary, an Angular component is still updating, a Salesforce Lightning element is hidden behind Shadow DOM, or a cookie banner blocks the click target.",[11,47,48],{},"Resolving the execution bottleneck forces engineering teams to choose an architecture. The choice dictates the latency profile, the security perimeter, and the integration complexity.",[50,51],"nuxt-picture",{":height":52,":width":53,"alt":54,"loading":55,"src":56,"provider":57},"450","800","Diagram showing an AI agent acting inside a user's live authenticated browser session","lazy","/blog/headless-browsers-vs-live-sessions-for-customer-facing-ai-agents/2.svg","none",[59,60,62],"h2",{"id":61},"evaluating-the-latency-budget","Evaluating the Latency Budget",[11,64,65],{},"Voice-driven interactions leave little room for delay. Natural conversation starts to feel broken once response times drift too high, and web automation has to fit inside that budget rather than sit on top of it.",[11,67,68],{},"Speech recognition, end-of-speech detection, LLM response time, and text-to-speech synthesis already consume most of the available time. In many systems, the full pipeline lands around 1,200 milliseconds before the browser action is even considered.",[50,70],{":height":52,":width":53,"alt":71,"loading":55,"src":72,"provider":57},"Diagram breaking down the voice AI latency budget across speech recognition, LLM, and text-to-speech stages","/blog/headless-browsers-vs-live-sessions-for-customer-facing-ai-agents/3.svg",[11,74,75],{},"Web automation approaches that add hundreds of milliseconds on top of this pipeline produce broken experiences. The execution layer cannot afford to add network round-trips for pixel streaming. The system must operate within the existing browser session to meet the strict timing constraints.",[59,77,79],{"id":78},"headless-browsers","Headless Browsers",[11,81,82],{},"Headless browsers provide a clean, isolated environment for task execution. A server starts a fresh Chromium instance, runs the task, and tears the environment down afterward. That model works well for testing, data extraction, and background automation, where isolation and repeatability matter more than immediacy.",[11,84,85],{},"The tradeoff is that the browser runs outside the user's active session. If the user is authenticated locally, the remote instance does not automatically share that state. To act on the user's behalf, the system usually has to copy session material such as cookies into the remote environment. In regulated settings, that can create governance and compliance concerns.",[11,87,88],{},"It also separates the action from what the user sees. If the remote browser clicks a button and opens a modal, the user does not see that directly unless the system streams screenshots or video back to the client. That extra transport layer adds latency and makes the experience feel slower.",[50,90],{":height":52,":width":53,"alt":91,"loading":55,"src":92,"provider":57},"Diagram showing a remote headless browser streaming screenshots back to the local client and the resulting latency","/blog/headless-browsers-vs-live-sessions-for-customer-facing-ai-agents/4.svg",[94,95,97],"h3",{"id":96},"playwright","Playwright",[50,99],{":height":100,":width":101,"alt":102,"loading":55,"src":103,"format":104},"600","1200","Playwright GitHub social preview","/blog/headless-browsers-vs-live-sessions-for-customer-facing-ai-agents/Playwrite.png","webp",[11,106,107],{},"Playwright is a browser automation framework that drives cross-browser execution for developers. Microsoft maintains this open-source project, which interacts with browsers through a bidirectional WebSocket connection. AI agents use Playwright to load pages, evaluate JavaScript, and extract content for LLM processing. The framework provides rich selectors and auto-waiting mechanisms out of the box.",[22,109,110,116,122,128],{},[25,111,112,115],{},[28,113,114],{},"Multi-page support:"," The API manages multiple browser contexts simultaneously, isolating cookies and local storage between individual execution runs.",[25,117,118,121],{},[28,119,120],{},"Network interception:"," Developers mock network requests or modify HTTP headers during execution to test edge cases and agent error handling.",[25,123,124,127],{},[28,125,126],{},"DOM traversal:"," Agents extract the accessibility tree using built-in methods to feed concise representations to LLMs, reducing overall token consumption.",[25,129,130,133],{},[28,131,132],{},"Trace viewer:"," The system captures execution logs, network payloads, and DOM snapshots to debug failed agent actions post-execution.",[94,135,137],{"id":136},"browserbase","Browserbase",[50,139],{":height":140,":width":141,"alt":137,"loading":55,"src":142},"1508","2880","/blog/headless-browsers-vs-live-sessions-for-customer-facing-ai-agents/browserbase.png",[11,144,145],{},"Browserbase is a serverless platform that hosts headless browsers for AI agents. The infrastructure manages the complexity of scaling browser instances, handling session timeouts, and dealing with bot mitigation systems. Agents connect to the service via standard automation protocols and receive a dedicated, clean execution environment. The platform abstracts away the DevOps burden of maintaining a fleet of Chrome containers.",[22,147,148,154,160,166],{},[25,149,150,153],{},[28,151,152],{},"Session persistence:"," The service keeps browser contexts alive across multiple LLM reasoning cycles to maintain active login states and shopping cart data.",[25,155,156,159],{},[28,157,158],{},"Proxy rotation:"," The infrastructure automatically routes traffic through different IP addresses to avoid rate limits on heavily guarded target domains.",[25,161,162,165],{},[28,163,164],{},"Stealth mode:"," The environment includes built-in configurations to bypass common anti-bot protections and advanced canvas fingerprinting checks.",[25,167,168,171],{},[28,169,170],{},"Debug viewing:"," Developers access a live video stream of the remote browser to monitor agent behavior during complex, multi-step execution workflows.",[94,173,175],{"id":174},"browserless","Browserless",[50,177],{":height":140,":width":141,"alt":175,"loading":55,"src":178},"/blog/headless-browsers-vs-live-sessions-for-customer-facing-ai-agents/Browserless.png",[11,180,181],{},"Browserless is a cloud infrastructure that provisions headless browser APIs for data scrapers. It operates as a managed service offering high-concurrency browser execution environments accessed via REST APIs or WebSocket connections. The platform focuses heavily on raw execution speed and throughput for background tasks. Teams use it to run thousands of parallel agent extraction jobs without managing server clusters.",[22,183,184,190,196,202],{},[25,185,186,189],{},[28,187,188],{},"GraphQL endpoints:"," The API supports structured queries for specific DOM elements, returning clean JSON payloads instead of raw, unparsed HTML.",[25,191,192,195],{},[28,193,194],{},"Concurrent execution:"," The infrastructure scales horizontally to handle massive parallel scraping jobs across geographically distributed worker nodes.",[25,197,198,201],{},[28,199,200],{},"Custom docker images:"," Engineers deploy customized browser binaries with specific Chrome extensions pre-loaded for highly specialized scraping tasks.",[25,203,204,207],{},[28,205,206],{},"Webhook integration:"," The system pushes extracted data back to the originating server once the autonomous agent completes the defined web task.",[209,210],"article-signup-cta",{"heading":211,"subtitle":212},"Give your AI agent a live session to act in","Webfuse injects an execution layer into any website, so voice agents and LLM orchestrators can read the page and act inside the user's own session, at low latency and with a human able to step in at any moment.",[59,214,216],{"id":215},"live-sessions","Live Sessions",[11,218,219],{},"Live sessions run the execution layer inside the browser the customer is already using. The agent works in the same tab and uses the state that already exists there, including authentication, cookies, and local storage.",[11,221,222],{},"That changes a few practical things right away:",[22,224,225,228,231],{},[25,226,227],{},"The agent does not have to recreate the user's session on a remote server.",[25,229,230],{},"Actions appear directly in the page the user is already viewing.",[25,232,233],{},"Existing security controls and analytics stay in the same environment.",[11,235,236],{},"This is why live sessions fit real-time support and voice workflows well. When the agent fills a form or clicks a button, the result shows up immediately instead of being relayed back from a separate browser.",[11,238,239],{},"They can also be more reliable in complex JavaScript applications, where timing and page readiness often break browser automation.",[94,241,243],{"id":242},"webfuse","Webfuse",[50,245],{":height":140,":width":141,"alt":243,"loading":55,"src":246},"/blog/headless-browsers-vs-live-sessions-for-customer-facing-ai-agents/webfuse.png",[11,248,249],{},"Webfuse is a proxy-based execution layer that augments live sessions for enterprise AI platforms. The service acts as an on-demand reverse proxy that injects a virtualization layer into any target website without requiring infrastructure changes from the website owner. Voice agents and LLM orchestrators connect to the session via an MCP server or direct RPC WebSocket, receiving compressed DOM snapshots and issuing actuation commands. The execution happens inside the user's active browser, making it highly suitable for real-time customer support workflows where visual audit trails matter.",[50,251],{":height":52,":width":53,"alt":252,"loading":55,"src":253,"provider":57},"Diagram of the Webfuse proxy injecting a virtualization layer into a live web session for AI agent automation","/blog/headless-browsers-vs-live-sessions-for-customer-facing-ai-agents/6.svg",[22,255,256,267,280,286,292],{},[25,257,258,261,262,266],{},[28,259,260],{},"Cross-shadow targeting:"," The API penetrates Shadow DOM and iframe boundaries to interact with encapsulated components, allowing agents to click elements deep inside Salesforce Lightning interfaces using the ",[263,264,265],"code",{},"wf-id"," attribute.",[25,268,269,272,273,276,277,279],{},[28,270,271],{},"DOM downsampling:"," The ",[263,274,275],{},"applyAdaptiveD2Snap"," algorithm compresses a DOM snapshot to fit a target LLM token budget (around 32K tokens by default), retaining structure and the interactive elements agents target via ",[263,278,265],{},".",[25,281,282,285],{},[28,283,284],{},"Visual audit trails:"," The platform records every agent action and user interaction for strict compliance reporting, storing the output in WORM-compliant storage for financial services audits.",[25,287,288,291],{},[28,289,290],{},"Event simulation:"," Actuation commands fire the complete sequence of framework-level events, including hover and focus states, to satisfy strict React and Angular event listeners.",[25,293,294,297],{},[28,295,296],{},"PII redaction:"," The virtualization layer masks sensitive fields like credit card numbers on the client side before the DOM snapshot ever reaches the external LLM provider.",[94,299,301],{"id":300},"chrome-cdp","Chrome CDP",[11,303,304],{},"Chrome CDP is a protocol layer that exposes internal browser APIs for automation engineers. Connecting an agent to a local debugging port allows the system to drive an already active browser rather than booting a new, isolated container. This attachment method means the AI operates within the authenticated environment the user is actively viewing. Developers utilize this approach when they need granular control over a visible session without injecting external JavaScript libraries.",[22,306,307,313,319,325],{},[25,308,309,312],{},[28,310,311],{},"Active attachment:"," Agents connect directly to a running browser tab, sharing the live session, existing cookies, and local state without transferring credentials to a remote server.",[25,314,315,318],{},[28,316,317],{},"Raw input emulation:"," The protocol bypasses high-level JavaScript events by dispatching low-level input commands, simulating exact mouse coordinates and key presses within the user's window.",[25,320,321,324],{},[28,322,323],{},"Live DOM inspection:"," Engineers query the rendered document object model in real-time, giving agents immediate access to newly painted elements on the user's screen.",[25,326,327,330],{},[28,328,329],{},"Network monitoring:"," The system intercepts live HTTP requests, allowing the automation logic to pause execution until specific backend data finishes loading visually.",[94,332,334],{"id":333},"browser-use","Browser Use",[50,336],{":height":100,":width":101,"alt":337,"loading":55,"src":338,"format":104},"Browser Use GitHub social preview","/blog/headless-browsers-vs-live-sessions-for-customer-facing-ai-agents/browseruse.png",[11,340,341],{},"Browser Use is an open-source library that connects language models to local browsers for agent builders. The framework takes a goal-oriented approach, allowing the developer to pass a prompt and an LLM client, after which the library autonomously determines the required browser actions. It manages the translation between the model's text outputs and the Playwright Python commands required to drive the local Chrome instance. The project emphasizes simplicity, letting developers spin up an agent with minimal initial configuration.",[22,343,344,350,356,362],{},[25,345,346,349],{},[28,347,348],{},"Self-correcting execution:"," The agent evaluates the page state after each action, reading the new DOM to retry the command if the expected outcome fails.",[25,351,352,355],{},[28,353,354],{},"Multi-tab orchestration:"," The library manages workflows that span across several open browser tabs simultaneously, switching contexts to gather scattered data points.",[25,357,358,361],{},[28,359,360],{},"Vision capabilities:"," The system captures screenshots and annotates interactive elements with numeric bounding boxes to feed context to multimodal visual models.",[25,363,364,367],{},[28,365,366],{},"Extensible action space:"," Developers register custom Python functions as tools that the agent calls during its autonomous execution loop to interact with local databases.",[59,369,371],{"id":370},"choosing-between-the-two","Choosing Between the Two",[11,373,374],{},"Headless browsers are a strong fit for background automation: scraping, testing, scheduled tasks, and other workloads where no user is waiting on the screen. They are easy to isolate, easy to scale, and well suited to parallel execution.",[11,376,377],{},"Live sessions are a better fit when the agent needs to work inside a real user's active session. They keep authentication local, provide immediate visual feedback, and avoid the extra round-trips that make real-time interactions feel slow.",[379,380,381,397],"table",{},[382,383,384],"thead",{},[385,386,387,391,394],"tr",{},[388,389,390],"th",{},"Factor",[388,392,393],{},"Headless (remote)",[388,395,396],{},"Live session (in-browser)",[398,399,400,412,423,434,445],"tbody",{},[385,401,402,406,409],{},[403,404,405],"td",{},"Where it runs",[403,407,408],{},"Remote server",[403,410,411],{},"The user's own browser",[385,413,414,417,420],{},[403,415,416],{},"Authentication",[403,418,419],{},"Cookies copied to a remote instance",[403,421,422],{},"Inherited from the active session",[385,424,425,428,431],{},[403,426,427],{},"Visual feedback",[403,429,430],{},"Screenshot streaming",[403,432,433],{},"Native and immediate",[385,435,436,439,442],{},[403,437,438],{},"Latency",[403,440,441],{},"Adds network round-trips",[403,443,444],{},"Local execution",[385,446,447,450,453],{},[403,448,449],{},"Best fit",[403,451,452],{},"Scraping, testing, background jobs",[403,454,455],{},"Real-time customer support and voice",[11,457,458],{},"For voice agents, that last point matters most. The speech pipeline already consumes much of the response budget, so adding remote browser streaming usually pushes the interaction further out of range for natural conversation.",{"title":460,"searchDepth":461,"depth":461,"links":462},"",2,[463,464,470,475],{"id":61,"depth":461,"text":62},{"id":78,"depth":461,"text":79,"children":465},[466,468,469],{"id":96,"depth":467,"text":97},3,{"id":136,"depth":467,"text":137},{"id":174,"depth":467,"text":175},{"id":215,"depth":461,"text":216,"children":471},[472,473,474],{"id":242,"depth":467,"text":243},{"id":300,"depth":467,"text":301},{"id":333,"depth":467,"text":334},{"id":370,"depth":461,"text":371},"ai-agents","2026-06-29","Headless browsers run on remote servers; live sessions run inside the user's own browser. Compare both for customer-facing AI agents across latency, authentication, and governance.","md",[481,484,487,490],{"question":482,"answer":483},"What is the difference between a headless browser and a live session for AI agents?","A headless browser runs on a remote server in a fresh, isolated instance with no graphical interface. A live session runs inside the user's own browser, sharing the cookies, authentication, and page state the user already has open. Headless suits background jobs; live sessions suit customer-facing work.",{"question":485,"answer":486},"Why does latency matter for customer-facing AI agents?","Natural voice conversation has a budget of roughly 800 milliseconds end to end. The speech and language pipeline often uses most of that budget before any web action runs. A remote headless browser that streams screenshots back to the user adds network round-trips the budget cannot absorb, so the experience feels broken.",{"question":488,"answer":489},"Can a headless browser act inside a logged-in user session?","Only by copying the user's session cookies from the local browser into the remote instance. Moving credentials outside the local security perimeter raises compliance problems under frameworks like the EU Digital Operational Resilience Act (DORA). A live session avoids the transfer by acting where the user is already authenticated.",{"question":491,"answer":492},"Which approach suits real-time voice agents?","Live sessions. Running inside the active browser executes actions locally through JavaScript, removes the pixel-streaming round-trip, and shows the user each action as it happens, which keeps the interaction within the latency budget.",0,null,{"shortTitle":496,"relatedLinks":497},"Headless vs Live Sessions",[498,502],{"text":499,"href":500,"description":501},"Agent Browser vs Puppeteer & Playwright","/blog/agent-browser-vs-puppeteer-and-playwright","Compare browser automation approaches for AI agents and where agent-focused control changes the model.",{"text":503,"href":504,"description":505},"Browser Use vs Playwright: Which Is Better for AI Agent Control","/blog/browser-use-vs-playwright-which-is-better-for-ai-agent-control","A look at goal-directed agents against scripted automation for driving a browser.",true,"/blog/headless-browsers-vs-live-sessions-for-customer-facing-ai-agents",{"title":5,"description":478},{"loc":507},"blog/1047.headless-browsers-vs-live-sessions-for-customer-facing-ai-agents",[476,512,513,514,515],"web-agents","browser-automation","voice-ai","headless-browser","2Wvamh1PjHD2j0GkhVLa1ZEM1bssEQLyhyoV4A9qpVo",[518,2189],{"id":519,"title":520,"authorId":521,"body":522,"category":476,"created":2152,"description":2153,"extension":479,"faqs":2154,"featurePriority":494,"head":494,"landingPath":494,"meta":2167,"navigation":506,"ogImage":494,"path":2179,"robots":494,"schemaOrg":494,"seo":2180,"sitemap":2181,"stem":2182,"tags":2183,"__hash__":2188},"blog/blog/1012.dom-downsampling-for-llm-based-web-agents.md","DOM Downsampling for LLM-Based Web Agents","thassilo-schiepanski",{"type":8,"value":523,"toc":2137},[524,529,553,557,564,568,584,588,594,598,616,642,645,649,652,663,669,700,704,724,736,741,757,771,774,778,798,802,810,822,826,829,1221,1227,1234,1398,1405,1496,1503,1575,1584,1590,1599,1603,1609,1619,1631,1864,1881,1903,1909,1952,1956,1968,1977,1981,1986,1989,1993,1999,2004,2042,2046,2052,2056,2066,2070,2073,2133],[50,525],{":width":526,"alt":527,"format":104,"loading":55,"src":528},"900","Downsampling visualised for digital images and HTML","/blog/dom-downsampling-for-web-agents/1.png",[11,530,531,538,539,538,544,548,549,552],{},[532,533,537],"a",{"href":534,"rel":535},"https://operator.chatgpt.com",[536],"nofollow","Operator (OpenAI)",", ",[532,540,543],{"href":541,"rel":542},"https://www.director.ai",[536],"Director (Browserbase)",[532,545,334],{"href":546,"rel":547},"https://browser-use.com",[536]," – we are currently witnessing the rise of ",[28,550,551],{},"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.",[59,554,556],{"id":555},"what-is-a-snapshot","What is a Snapshot?",[11,558,559,560,563],{},"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 ",[28,561,562],{},"snapshot",". And the snapshot technique primarily decides the quality of LLM interaction suggestions.",[94,565,567],{"id":566},"gui-snapshots","GUI Snapshots",[11,569,570,571,574,575,579,580,583],{},"Screenshots – for consistency reasons referred to as ",[28,572,573],{},"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 ",[576,577,578],"em",{},"“click at 100, 735”",". As a workaround, early web agents used ",[576,581,582],{},"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.",[50,585],{":width":526,"alt":586,"format":104,"loading":55,"src":587},"Grounded GUI snapshot as implemented by Browser Use","/blog/dom-downsampling-for-web-agents/2.png",[11,589,590],{},[591,592,593],"small",{},"Grounded GUI snapshot as implemented by Browser Use.",[94,595,597],{"id":596},"dom-snapshots","DOM Snapshots",[11,599,600,601,611,612,615],{},"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",[602,603,604],"sup",{},[532,605,610],{"href":606,"ariaDescribedBy":607,"dataFootnoteRef":460,"id":609},"#user-content-fn-1",[608],"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, ",[28,613,614],{},"DOM snapshots"," offer a compelling alternative to GUI snapshots. DOM snapshots offer a handful of key advantages:",[617,618,619,622,625,628,631],"ol",{},[25,620,621],{},"DOM snapshots connect with LLM code (HTML) interpretation abilities.",[25,623,624],{},"DOM snapshots can be compiled from deep clones, hidden from supervision (unlike GUI grounding).",[25,626,627],{},"DOM snapshots render text input that on average consume less bandwidth than screnshots.",[25,629,630],{},"DOM snapshots allow for exact programmatic targeting of elements (e.g., via CSS selectors).",[25,632,633,634,637,638,641],{},"DOM snapshots are available with the ",[263,635,636],{},"DOMContentLoaded"," event (whereas the GUI completes initial rendering with ",[263,639,640],{},"load",").",[11,643,644],{},"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?).",[59,646,648],{"id":647},"dom-downsampling-a-novel-approach","DOM Downsampling: A Novel Approach",[11,650,651],{},"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,653,654,655,658,659,662],{},"We transfer the concept of ",[28,656,657],{},"downsampling"," to ",[28,660,661],{},"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.",[59,664,666],{"id":665},"d2snap",[576,667,668],{},"D2Snap",[11,670,671,672,680,688,696,697,699],{},"We recently proposed ",[532,673,676],{"href":674,"rel":675},"https://arxiv.org/abs/2508.04412",[536],[28,677,678],{},[576,679,668],{},[602,681,682],{},[532,683,687],{"href":684,"ariaDescribedBy":685,"dataFootnoteRef":460,"id":686},"#user-content-fn-2",[608],"user-content-fnref-2","2",[602,689,690],{},[532,691,695],{"href":692,"ariaDescribedBy":693,"dataFootnoteRef":460,"id":694},"#user-content-fn-3",[608],"user-content-fnref-3","3"," – a first-of-its-kind downsampling algorithm for DOMs. Herein, we'll briefly explain how the ",[576,698,668],{}," algorithm works, and how it can be utilised to build efficient and performant web agents.",[94,701,703],{"id":702},"how-it-works","How it works",[11,705,706,707,709,710,538,713,716,717,720,721,641],{},"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. ",[576,708,668],{}," downsamples at a variable ratio, configured through procedure-specific parameters  ",[263,711,712],{},"k",[263,714,715],{},"l",", and ",[263,718,719],{},"m"," (",[263,722,723],{},"∈ [0, 1]",[725,726,727],"blockquote",{},[11,728,729,730,735],{},"We used ",[532,731,734],{"href":732,"rel":733},"https://openai.com/index/hello-gpt-4o/",[536],"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.",[737,738,740],"h4",{"id":739},"procedure-elements","Procedure: Elements",[11,742,743,745,746,749,750,753,754,756],{},[576,744,668],{}," downsamples (simplifies) elements by merging container elements like ",[263,747,748],{},"section"," and ",[263,751,752],{},"div"," together. A parameter ",[263,755,712],{}," 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,758,759,760,538,762,764,765,770],{},"Elements in content elements (",[263,761,11],{},[263,763,725],{},", ...) are translated to a more comprehensive ",[532,766,769],{"href":767,"rel":768},"https://www.markdownguide.org/basic-syntax/",[536],"Markdown"," representation.",[11,772,773],{},"Interactive elements, definite interaction target candidates, are kept as is.",[737,775,777],{"id":776},"procedure-text","Procedure: Text",[11,779,780,782,783,786,794,795,797],{},[576,781,668],{}," downsamples text by dropping a fraction. Natural units of text are space-separated words, or punctuation-separated sentences. We reuse the ",[576,784,785],{},"TextRank",[602,787,788],{},[532,789,793],{"href":790,"ariaDescribedBy":791,"dataFootnoteRef":460,"id":792},"#user-content-fn-4",[608],"user-content-fnref-4","4"," algorithm to rank sentences in text nodes. The lowest-ranking fraction of sentences, denoted by parameter ",[263,796,715],{},", is dropped.",[737,799,801],{"id":800},"procedure-attributes","Procedure: Attributes",[11,803,804,806,807,809],{},[576,805,668],{}," downsamples attributes by dropping those with a name that, according to ground truth, holds a UI feature degree below a threshold. Parameter ",[263,808,719],{}," denotes this threshold.",[725,811,812],{},[11,813,814,815,821],{},"Check out the ",[532,816,818,820],{"href":674,"rel":817},[536],[576,819,668],{}," paper"," to learn about the algorithm in-depth.",[94,823,825],{"id":824},"example-of-a-downsampled-dom","Example of a Downsampled DOM",[11,827,828],{},"Consider a partial DOM state, serialised as HTML:",[830,831,835],"pre",{"className":832,"code":833,"language":834,"meta":460,"style":460},"language-html shiki shiki-themes catppuccin-latte night-owl","\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","html",[263,836,837,904,947,969,978,999,1018,1027,1033,1039,1049,1078,1088,1107,1125,1134,1140,1146,1156,1183,1192,1202,1212],{"__ignoreMap":460},[838,839,842,846,849,853,856,860,864,866,869,871,873,875,877,880,882,884,887,889,892,894,896,899,901],"span",{"class":840,"line":841},"line",1,[838,843,845],{"class":844},"s9rnR","\u003C",[838,847,748],{"class":848},"sY2RG",[838,850,852],{"class":851},"swkLt"," class",[838,854,855],{"class":844},"=",[838,857,859],{"class":858},"sbuKk","\"",[838,861,863],{"class":862},"sfrMT","container",[838,865,859],{"class":858},[838,867,868],{"class":851}," tabindex",[838,870,855],{"class":844},[838,872,859],{"class":858},[838,874,695],{"class":862},[838,876,859],{"class":858},[838,878,879],{"class":851}," required",[838,881,855],{"class":844},[838,883,859],{"class":858},[838,885,886],{"class":862},"true",[838,888,859],{"class":858},[838,890,891],{"class":851}," type",[838,893,855],{"class":844},[838,895,859],{"class":858},[838,897,898],{"class":862},"example",[838,900,859],{"class":858},[838,902,903],{"class":844},">\n",[838,905,906,909,911,913,915,917,920,922,925,927,929,932,934,936,938,940,943,945],{"class":840,"line":461},[838,907,908],{"class":844},"  \u003C",[838,910,752],{"class":848},[838,912,852],{"class":851},[838,914,855],{"class":844},[838,916,859],{"class":858},[838,918,919],{"class":862},"mx-auto",[838,921,859],{"class":858},[838,923,924],{"class":851}," data-topic",[838,926,855],{"class":844},[838,928,859],{"class":858},[838,930,931],{"class":862},"products",[838,933,859],{"class":858},[838,935,879],{"class":851},[838,937,855],{"class":844},[838,939,859],{"class":858},[838,941,942],{"class":862},"false",[838,944,859],{"class":858},[838,946,903],{"class":844},[838,948,949,952,955,958,962,965,967],{"class":840,"line":467},[838,950,951],{"class":844},"    \u003C",[838,953,954],{"class":848},"h1",[838,956,957],{"class":844},">",[838,959,961],{"class":960},"s2kId","Our Pizza",[838,963,964],{"class":844},"\u003C/",[838,966,954],{"class":848},[838,968,903],{"class":844},[838,970,972,974,976],{"class":840,"line":971},4,[838,973,951],{"class":844},[838,975,752],{"class":848},[838,977,903],{"class":844},[838,979,981,984,986,988,990,992,995,997],{"class":840,"line":980},5,[838,982,983],{"class":844},"      \u003C",[838,985,752],{"class":848},[838,987,852],{"class":851},[838,989,855],{"class":844},[838,991,859],{"class":858},[838,993,994],{"class":862},"shadow-lg",[838,996,859],{"class":858},[838,998,903],{"class":844},[838,1000,1002,1005,1007,1009,1012,1014,1016],{"class":840,"line":1001},6,[838,1003,1004],{"class":844},"        \u003C",[838,1006,59],{"class":848},[838,1008,957],{"class":844},[838,1010,1011],{"class":960},"Margherita",[838,1013,964],{"class":844},[838,1015,59],{"class":848},[838,1017,903],{"class":844},[838,1019,1021,1023,1025],{"class":840,"line":1020},7,[838,1022,1004],{"class":844},[838,1024,11],{"class":848},[838,1026,903],{"class":844},[838,1028,1030],{"class":840,"line":1029},8,[838,1031,1032],{"class":960},"          A simple classic: mozzarela, tomatoes and basil.\n",[838,1034,1036],{"class":840,"line":1035},9,[838,1037,1038],{"class":960},"          An everyday choice!\n",[838,1040,1042,1045,1047],{"class":840,"line":1041},10,[838,1043,1044],{"class":844},"        \u003C/",[838,1046,11],{"class":848},[838,1048,903],{"class":844},[838,1050,1052,1054,1057,1059,1061,1063,1065,1067,1069,1072,1074,1076],{"class":840,"line":1051},11,[838,1053,1004],{"class":844},[838,1055,1056],{"class":848},"button",[838,1058,891],{"class":851},[838,1060,855],{"class":844},[838,1062,859],{"class":858},[838,1064,1056],{"class":862},[838,1066,859],{"class":858},[838,1068,957],{"class":844},[838,1070,1071],{"class":960},"Add",[838,1073,964],{"class":844},[838,1075,1056],{"class":848},[838,1077,903],{"class":844},[838,1079,1081,1084,1086],{"class":840,"line":1080},12,[838,1082,1083],{"class":844},"      \u003C/",[838,1085,752],{"class":848},[838,1087,903],{"class":844},[838,1089,1091,1093,1095,1097,1099,1101,1103,1105],{"class":840,"line":1090},13,[838,1092,983],{"class":844},[838,1094,752],{"class":848},[838,1096,852],{"class":851},[838,1098,855],{"class":844},[838,1100,859],{"class":858},[838,1102,994],{"class":862},[838,1104,859],{"class":858},[838,1106,903],{"class":844},[838,1108,1110,1112,1114,1116,1119,1121,1123],{"class":840,"line":1109},14,[838,1111,1004],{"class":844},[838,1113,59],{"class":848},[838,1115,957],{"class":844},[838,1117,1118],{"class":960},"Capricciosa",[838,1120,964],{"class":844},[838,1122,59],{"class":848},[838,1124,903],{"class":844},[838,1126,1128,1130,1132],{"class":840,"line":1127},15,[838,1129,1004],{"class":844},[838,1131,11],{"class":848},[838,1133,903],{"class":844},[838,1135,1137],{"class":840,"line":1136},16,[838,1138,1139],{"class":960},"          A rich taste: mozzarella, ham, mushrooms, artichokes, and olives.\n",[838,1141,1143],{"class":840,"line":1142},17,[838,1144,1145],{"class":960},"          A true favourite!\n",[838,1147,1149,1152,1154],{"class":840,"line":1148},18,[838,1150,1151],{"class":844},"          \u003C/",[838,1153,11],{"class":848},[838,1155,903],{"class":844},[838,1157,1159,1161,1163,1165,1167,1169,1171,1173,1175,1177,1179,1181],{"class":840,"line":1158},19,[838,1160,1004],{"class":844},[838,1162,1056],{"class":848},[838,1164,891],{"class":851},[838,1166,855],{"class":844},[838,1168,859],{"class":858},[838,1170,1056],{"class":862},[838,1172,859],{"class":858},[838,1174,957],{"class":844},[838,1176,1071],{"class":960},[838,1178,964],{"class":844},[838,1180,1056],{"class":848},[838,1182,903],{"class":844},[838,1184,1186,1188,1190],{"class":840,"line":1185},20,[838,1187,1083],{"class":844},[838,1189,752],{"class":848},[838,1191,903],{"class":844},[838,1193,1195,1198,1200],{"class":840,"line":1194},21,[838,1196,1197],{"class":844},"    \u003C/",[838,1199,752],{"class":848},[838,1201,903],{"class":844},[838,1203,1205,1208,1210],{"class":840,"line":1204},22,[838,1206,1207],{"class":844},"  \u003C/",[838,1209,752],{"class":848},[838,1211,903],{"class":844},[838,1213,1215,1217,1219],{"class":840,"line":1214},23,[838,1216,964],{"class":844},[838,1218,748],{"class":848},[838,1220,903],{"class":844},[11,1222,1223,1224,1226],{},"Here are some ",[576,1225,668],{}," downsampling results, which are based on different parametric configurations. A percentage denotes the reduced size.",[737,1228,1230,1233],{"id":1229},"k3-l3-m3-55",[263,1231,1232],{},"k=.3, l=.3, m=.3"," (55%)",[830,1235,1237],{"className":832,"code":1236,"language":834,"meta":460,"style":460},"\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",[263,1238,1239,1287,1292,1310,1315,1320,1346,1351,1356,1382,1390],{"__ignoreMap":460},[838,1240,1241,1243,1245,1247,1249,1251,1253,1255,1257,1259,1261,1263,1265,1267,1269,1271,1273,1275,1277,1279,1281,1283,1285],{"class":840,"line":841},[838,1242,845],{"class":844},[838,1244,748],{"class":848},[838,1246,868],{"class":851},[838,1248,855],{"class":844},[838,1250,859],{"class":858},[838,1252,695],{"class":862},[838,1254,859],{"class":858},[838,1256,891],{"class":851},[838,1258,855],{"class":844},[838,1260,859],{"class":858},[838,1262,898],{"class":862},[838,1264,859],{"class":858},[838,1266,852],{"class":851},[838,1268,855],{"class":844},[838,1270,859],{"class":858},[838,1272,863],{"class":862},[838,1274,859],{"class":858},[838,1276,879],{"class":851},[838,1278,855],{"class":844},[838,1280,859],{"class":858},[838,1282,886],{"class":862},[838,1284,859],{"class":858},[838,1286,903],{"class":844},[838,1288,1289],{"class":840,"line":461},[838,1290,1291],{"class":960},"  # Our Pizza\n",[838,1293,1294,1296,1298,1300,1302,1304,1306,1308],{"class":840,"line":467},[838,1295,908],{"class":844},[838,1297,752],{"class":848},[838,1299,852],{"class":851},[838,1301,855],{"class":844},[838,1303,859],{"class":858},[838,1305,994],{"class":862},[838,1307,859],{"class":858},[838,1309,903],{"class":844},[838,1311,1312],{"class":840,"line":971},[838,1313,1314],{"class":960},"    ## Margherita\n",[838,1316,1317],{"class":840,"line":980},[838,1318,1319],{"class":960},"    A simple classic: mozzarela, tomatoes, and basil.\n",[838,1321,1322,1324,1326,1328,1330,1332,1334,1336,1338,1340,1342,1344],{"class":840,"line":1001},[838,1323,951],{"class":844},[838,1325,1056],{"class":848},[838,1327,891],{"class":851},[838,1329,855],{"class":844},[838,1331,859],{"class":858},[838,1333,1056],{"class":862},[838,1335,859],{"class":858},[838,1337,957],{"class":844},[838,1339,1071],{"class":960},[838,1341,964],{"class":844},[838,1343,1056],{"class":848},[838,1345,903],{"class":844},[838,1347,1348],{"class":840,"line":1020},[838,1349,1350],{"class":960},"    ## Capricciosa\n",[838,1352,1353],{"class":840,"line":1029},[838,1354,1355],{"class":960},"    A rich taste: mozzarella, ham, mushrooms, artichokes, and olives.\n",[838,1357,1358,1360,1362,1364,1366,1368,1370,1372,1374,1376,1378,1380],{"class":840,"line":1035},[838,1359,951],{"class":844},[838,1361,1056],{"class":848},[838,1363,891],{"class":851},[838,1365,855],{"class":844},[838,1367,859],{"class":858},[838,1369,1056],{"class":862},[838,1371,859],{"class":858},[838,1373,957],{"class":844},[838,1375,1071],{"class":960},[838,1377,964],{"class":844},[838,1379,1056],{"class":848},[838,1381,903],{"class":844},[838,1383,1384,1386,1388],{"class":840,"line":1041},[838,1385,1207],{"class":844},[838,1387,752],{"class":848},[838,1389,903],{"class":844},[838,1391,1392,1394,1396],{"class":840,"line":1051},[838,1393,964],{"class":844},[838,1395,748],{"class":848},[838,1397,903],{"class":844},[737,1399,1401,1404],{"id":1400},"k4-l6-m8-27",[263,1402,1403],{},"k=.4, l=.6, m=.8"," (27%)",[830,1406,1408],{"className":832,"code":1407,"language":834,"meta":460,"style":460},"\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",[263,1409,1410,1418,1422,1430,1434,1439,1455,1459,1464,1480,1488],{"__ignoreMap":460},[838,1411,1412,1414,1416],{"class":840,"line":841},[838,1413,845],{"class":844},[838,1415,748],{"class":848},[838,1417,903],{"class":844},[838,1419,1420],{"class":840,"line":461},[838,1421,1291],{"class":960},[838,1423,1424,1426,1428],{"class":840,"line":467},[838,1425,908],{"class":844},[838,1427,752],{"class":848},[838,1429,903],{"class":844},[838,1431,1432],{"class":840,"line":971},[838,1433,1314],{"class":960},[838,1435,1436],{"class":840,"line":980},[838,1437,1438],{"class":960},"    A simple classic:\n",[838,1440,1441,1443,1445,1447,1449,1451,1453],{"class":840,"line":1001},[838,1442,951],{"class":844},[838,1444,1056],{"class":848},[838,1446,957],{"class":844},[838,1448,1071],{"class":960},[838,1450,964],{"class":844},[838,1452,1056],{"class":848},[838,1454,903],{"class":844},[838,1456,1457],{"class":840,"line":1020},[838,1458,1350],{"class":960},[838,1460,1461],{"class":840,"line":1029},[838,1462,1463],{"class":960},"    A rich taste:\n",[838,1465,1466,1468,1470,1472,1474,1476,1478],{"class":840,"line":1035},[838,1467,951],{"class":844},[838,1469,1056],{"class":848},[838,1471,957],{"class":844},[838,1473,1071],{"class":960},[838,1475,964],{"class":844},[838,1477,1056],{"class":848},[838,1479,903],{"class":844},[838,1481,1482,1484,1486],{"class":840,"line":1041},[838,1483,1207],{"class":844},[838,1485,752],{"class":848},[838,1487,903],{"class":844},[838,1489,1490,1492,1494],{"class":840,"line":1051},[838,1491,964],{"class":844},[838,1493,748],{"class":848},[838,1495,903],{"class":844},[737,1497,1499,1502],{"id":1498},"k-l0-m-35",[263,1500,1501],{},"k→∞, l=0, ∀m"," (35%)",[830,1504,1506],{"className":832,"code":1505,"language":834,"meta":460,"style":460},"# 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",[263,1507,1508,1513,1518,1523,1528,1544,1549,1554,1559],{"__ignoreMap":460},[838,1509,1510],{"class":840,"line":841},[838,1511,1512],{"class":960},"# Our Pizza\n",[838,1514,1515],{"class":840,"line":461},[838,1516,1517],{"class":960},"## Margherita\n",[838,1519,1520],{"class":840,"line":467},[838,1521,1522],{"class":960},"A simple classic: mozzarela, tomatoes, and basil.\n",[838,1524,1525],{"class":840,"line":971},[838,1526,1527],{"class":960},"An everyday choice!\n",[838,1529,1530,1532,1534,1536,1538,1540,1542],{"class":840,"line":980},[838,1531,845],{"class":844},[838,1533,1056],{"class":848},[838,1535,957],{"class":844},[838,1537,1071],{"class":960},[838,1539,964],{"class":844},[838,1541,1056],{"class":848},[838,1543,903],{"class":844},[838,1545,1546],{"class":840,"line":1001},[838,1547,1548],{"class":960},"## Capricciosa\n",[838,1550,1551],{"class":840,"line":1020},[838,1552,1553],{"class":960},"A rich taste: mozzarella, ham, mushrooms, artichokes, and olives.\n",[838,1555,1556],{"class":840,"line":1029},[838,1557,1558],{"class":960},"A true favourite!\n",[838,1560,1561,1563,1565,1567,1569,1571,1573],{"class":840,"line":1035},[838,1562,845],{"class":844},[838,1564,1056],{"class":848},[838,1566,957],{"class":844},[838,1568,1071],{"class":960},[838,1570,964],{"class":844},[838,1572,1056],{"class":848},[838,1574,903],{"class":844},[11,1576,1577,1578,1580,1581,1583],{},"Asymptotic ",[263,1579,712],{}," (kind of 'infinite' ",[263,1582,712],{},") 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.",[94,1585,1587],{"id":1586},"adaptived2snap",[576,1588,1589],{},"AdaptiveD2Snap",[11,1591,1592,1593,1595,1596,1598],{},"Fixed parameters might not be ideal for arbitrary DOMs – sourced from a landscape of web applications. We created ",[576,1594,1589],{}," – a wrapper for ",[576,1597,668],{}," that infers suitable parameters from a given DOM in order to hit a certain token budget.",[94,1600,1602],{"id":1601},"implementation-integration","Implementation & Integration",[11,1604,1605,1606,1608],{},"Picture an LLM-based weg agent that is premised on DOM snapshots. Implementing ",[576,1607,668],{}," is simple: Deep clone the DOM, and feed it to the algorithm. Now, take the snapshot; this is, serialise the resulting DOM. Done.",[725,1610,1611],{},[11,1612,1613,1614,1618],{},"Read our ",[532,1615,1617],{"href":1616},"/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,1620,1621,1622,1624,1625,1630],{},"The open source ",[576,1623,668],{}," API, provided as a ",[532,1626,1629],{"href":1627,"rel":1628},"https://github.com/webfuse-com/D2Snap",[536],"package on GitHub"," provides the following signature:",[830,1632,1636],{"className":1633,"code":1634,"language":1635,"meta":460,"style":460},"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",[263,1637,1638,1671,1683,1702,1716,1721,1726,1740,1752,1770,1780,1796,1800,1811,1819,1832,1844,1852],{"__ignoreMap":460},[838,1639,1640,1644,1648,1651,1655,1658,1661,1663,1667],{"class":840,"line":841},[838,1641,1643],{"class":1642},"s76yb","type",[838,1645,1647],{"class":1646},"sXbZB"," DOM ",[838,1649,855],{"class":1650},"s-_ek",[838,1652,1654],{"class":1653},"s-DR7"," Document",[838,1656,1657],{"class":844}," |",[838,1659,1660],{"class":1653}," Element",[838,1662,1657],{"class":844},[838,1664,1666],{"class":1665},"scrte"," string",[838,1668,1670],{"class":1669},"scGhl",";\n",[838,1672,1673,1675,1678,1680],{"class":840,"line":461},[838,1674,1643],{"class":1642},[838,1676,1677],{"class":1646}," Options ",[838,1679,855],{"class":1650},[838,1681,1682],{"class":1669}," {\n",[838,1684,1685,1689,1692,1695,1698],{"class":840,"line":467},[838,1686,1688],{"class":1687},"swl0y","  assignUniqueIDs",[838,1690,1691],{"class":844},"?:",[838,1693,1694],{"class":1665}," boolean",[838,1696,1697],{"class":1669},";",[838,1699,1701],{"class":1700},"sDmS1"," // false\n",[838,1703,1704,1707,1709,1711,1713],{"class":840,"line":971},[838,1705,1706],{"class":1687},"  debug",[838,1708,1691],{"class":844},[838,1710,1694],{"class":1665},[838,1712,1697],{"class":1669},[838,1714,1715],{"class":1700},"           // true\n",[838,1717,1718],{"class":840,"line":980},[838,1719,1720],{"class":1669},"};\n",[838,1722,1723],{"class":840,"line":1001},[838,1724,1725],{"emptyLinePlaceholder":506},"\n",[838,1727,1728,1730,1733,1737],{"class":840,"line":1020},[838,1729,668],{"class":960},[838,1731,279],{"class":1732},"s5FwJ",[838,1734,1736],{"class":1735},"sNstc","d2Snap",[838,1738,1739],{"class":960},"(\n",[838,1741,1742,1745,1749],{"class":840,"line":1029},[838,1743,1744],{"class":960},"  dom: ",[838,1746,1748],{"class":1747},"sqxXB","DOM",[838,1750,1751],{"class":1669},",\n",[838,1753,1754,1757,1760,1763,1765,1768],{"class":840,"line":1035},[838,1755,1756],{"class":960},"  k: number",[838,1758,1759],{"class":1669},",",[838,1761,1762],{"class":960}," l: number",[838,1764,1759],{"class":1669},[838,1766,1767],{"class":960}," m: number",[838,1769,1751],{"class":1669},[838,1771,1772,1775,1777],{"class":840,"line":1041},[838,1773,1774],{"class":960},"  options",[838,1776,1691],{"class":1650},[838,1778,1779],{"class":960}," Options\n",[838,1781,1782,1785,1789,1791,1794],{"class":840,"line":1051},[838,1783,1784],{"class":960},"): ",[838,1786,1788],{"class":1787},"s8Irk","Promise",[838,1790,845],{"class":1650},[838,1792,1793],{"class":960},"string",[838,1795,903],{"class":1650},[838,1797,1798],{"class":840,"line":1080},[838,1799,1725],{"emptyLinePlaceholder":506},[838,1801,1802,1804,1806,1809],{"class":840,"line":1090},[838,1803,668],{"class":960},[838,1805,279],{"class":1732},[838,1807,1808],{"class":1735},"adaptiveD2Snap",[838,1810,1739],{"class":960},[838,1812,1813,1815,1817],{"class":840,"line":1109},[838,1814,1744],{"class":960},[838,1816,1748],{"class":1747},[838,1818,1751],{"class":1669},[838,1820,1821,1824,1826,1830],{"class":840,"line":1127},[838,1822,1823],{"class":960},"  maxTokens: number ",[838,1825,855],{"class":1650},[838,1827,1829],{"class":1828},"sZ_Zo"," 4096",[838,1831,1751],{"class":1669},[838,1833,1834,1837,1839,1842],{"class":840,"line":1136},[838,1835,1836],{"class":960},"  maxIterations: number ",[838,1838,855],{"class":1650},[838,1840,1841],{"class":1828}," 5",[838,1843,1751],{"class":1669},[838,1845,1846,1848,1850],{"class":840,"line":1142},[838,1847,1774],{"class":960},[838,1849,1691],{"class":1650},[838,1851,1779],{"class":960},[838,1853,1854,1856,1858,1860,1862],{"class":840,"line":1148},[838,1855,1784],{"class":960},[838,1857,1788],{"class":1787},[838,1859,845],{"class":1650},[838,1861,1793],{"class":960},[838,1863,903],{"class":1650},[11,1865,1866,1867,1869,1870,1875,1876,1880],{},"Moreover, ",[576,1868,668],{}," it is available on the ",[532,1871,1874],{"href":1872,"rel":1873},"https://dev.webfuse.com/automation-api",[536],"Webfuse Automation API",". ",[532,1877,243],{"href":1878,"rel":1879},"https://www.webfuse.com",[536]," essentially is a proxy to seamlessly serve any existing web application with custom augmentations, such as a web agent widget.",[830,1882,1886],{"className":1883,"code":1884,"language":1885,"meta":460,"style":460},"language-js shiki shiki-themes catppuccin-latte night-owl","const domSnapshot = await browser.webfuseSession\n    .automation\n    .take_dom_snapshot({ modifier: 'downsample' })\n","js",[263,1887,1888,1893,1898],{"__ignoreMap":460},[838,1889,1890],{"class":840,"line":841},[838,1891,1892],{},"const domSnapshot = await browser.webfuseSession\n",[838,1894,1895],{"class":840,"line":461},[838,1896,1897],{},"    .automation\n",[838,1899,1900],{"class":840,"line":467},[838,1901,1902],{},"    .take_dom_snapshot({ modifier: 'downsample' })\n",[11,1904,1905,1906,1908],{},"Need precise control over the underlying ",[576,1907,668],{}," invocation? Configure it exactly how you want:",[830,1910,1912],{"className":1883,"code":1911,"language":1885,"meta":460,"style":460},"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",[263,1913,1914,1918,1922,1927,1932,1937,1942,1947],{"__ignoreMap":460},[838,1915,1916],{"class":840,"line":841},[838,1917,1892],{},[838,1919,1920],{"class":840,"line":461},[838,1921,1897],{},[838,1923,1924],{"class":840,"line":467},[838,1925,1926],{},"    .take_dom_snapshot({\n",[838,1928,1929],{"class":840,"line":971},[838,1930,1931],{},"        modifier: {\n",[838,1933,1934],{"class":840,"line":980},[838,1935,1936],{},"            name: 'D2Snap',\n",[838,1938,1939],{"class":840,"line":1001},[838,1940,1941],{},"            params: { hierarchyRatio: 0.6, textRatio: 0.2, attributeRatio: 0.8 }\n",[838,1943,1944],{"class":840,"line":1020},[838,1945,1946],{},"        }\n",[838,1948,1949],{"class":840,"line":1029},[838,1950,1951],{},"    })\n",[94,1953,1955],{"id":1954},"performance-evaluation","Performance Evaluation",[11,1957,1958,1959,1961,1962,1964,1965,1967],{},"Now for the moment of truth: How does ",[576,1960,668],{}," stack up against the industry standard? We evaluated ",[576,1963,668],{}," in comparison to a grounded GUI snapshot baseline close to those used by ",[576,1966,334],{}," – coloured bounding boxes around visible interactive elements.",[11,1969,1970,1971,1976],{},"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 ",[532,1972,1975],{"href":1973,"rel":1974},"https://github.com/OSU-NLP-Group/Online-Mind2Web",[536],"Online-Mind2Web"," dataset.",[50,1978],{":width":53,"alt":1979,"format":104,"loading":55,"src":1980},"Exemplary solution UI state trajectory of a defined web-based task","/blog/dom-downsampling-for-web-agents/3.png",[11,1982,1983],{},[591,1984,1985],{},"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,1987,1988],{},"These are our key findings...",[737,1990,1992],{"id":1991},"substantial-success-rates","Substantial Success Rates",[11,1994,1995,1996,1998],{},"The results exceeded our expectations. Not only did ",[576,1997,668],{}," 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.",[50,2000],{":width":2001,"alt":2002,"format":104,"loading":55,"src":2003},"550","Success rate per web agent snapshot subject evaluated across the dataset","/blog/dom-downsampling-for-web-agents/4.png",[591,2005,2006,2007,2014,2015,2017,2018,2021,2022,2025,2026,2029,2030,2033,2034,2037,2038,2041],{},"\n  Success rate per web agent snapshot subject evaluated across the dataset.\n  Labels: ",[263,2008,2009,2010],{},"GUI",[2011,2012,2013],"sub",{}," gr.",": Baseline, ",[263,2016,1748],{},": Raw DOM (cut-off at ~8K tokens), ",[263,2019,2020],{},"k( l m)",": Parameter values; e.g., ",[263,2023,2024],{},".9 .3 .6",", or ",[263,2027,2028],{},".4"," if equal). ",[263,2031,2032],{},"∞",": Linearisation,  ",[263,2035,2036],{},"8192 / 32768",": via token-limited (resp.) ",[2039,2040,1589],"i",{},".\n",[737,2043,2045],{"id":2044},"containable-token-and-byte-size","Containable Token and Byte Size",[11,2047,2048,2049,2051],{},"Even light downsampling delivers dramatic size reductions. Most ",[576,2050,668],{}," 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.",[50,2053],{":width":53,"alt":2054,"format":104,"loading":55,"src":2055},"Comparison of mean input size across and per subject","/blog/dom-downsampling-for-web-agents/5.png",[591,2057,2058,2059,2062,2063,2065],{},"\n  Left: Comparison of mean input size (tokens vs bytes) across and per subject.",[2060,2061],"br",{},"\n  Right: Estimated input token size across the dataset created by a single ",[2039,2064,668],{}," evaluation subject.\n",[737,2067,2069],{"id":2068},"hierarchy-actually-matters","Hierarchy Actually Matters",[11,2071,2072],{},"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.",[748,2074,2077,2082],{"className":2075,"dataFootnotes":460},[2076],"footnotes",[59,2078,2081],{"className":2079,"id":608},[2080],"sr-only","Footnotes",[617,2083,2084,2099,2110,2121],{},[25,2085,2087,2091,2092],{"id":2086},"user-content-fn-1",[532,2088,2089],{"href":2089,"rel":2090},"https://arxiv.org/abs/2210.03945",[536]," ",[532,2093,2098],{"href":2094,"ariaLabel":2095,"className":2096,"dataFootnoteBackref":460},"#user-content-fnref-1","Back to reference 1",[2097],"data-footnote-backref","↩",[25,2100,2102,2091,2105],{"id":2101},"user-content-fn-2",[532,2103,674],{"href":674,"rel":2104},[536],[532,2106,2098],{"href":2107,"ariaLabel":2108,"className":2109,"dataFootnoteBackref":460},"#user-content-fnref-2","Back to reference 2",[2097],[25,2111,2113,2091,2116],{"id":2112},"user-content-fn-3",[532,2114,1627],{"href":1627,"rel":2115},[536],[532,2117,2098],{"href":2118,"ariaLabel":2119,"className":2120,"dataFootnoteBackref":460},"#user-content-fnref-3","Back to reference 3",[2097],[25,2122,2124,2091,2128],{"id":2123},"user-content-fn-4",[532,2125,2126],{"href":2126,"rel":2127},"https://aclanthology.org/W04-3252",[536],[532,2129,2098],{"href":2130,"ariaLabel":2131,"className":2132,"dataFootnoteBackref":460},"#user-content-fnref-4","Back to reference 4",[2097],[2134,2135,2136],"style",{},"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 .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 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}",{"title":460,"searchDepth":461,"depth":461,"links":2138},[2139,2143,2144,2151],{"id":555,"depth":461,"text":556,"children":2140},[2141,2142],{"id":566,"depth":467,"text":567},{"id":596,"depth":467,"text":597},{"id":647,"depth":461,"text":648},{"id":665,"depth":461,"text":668,"children":2145},[2146,2147,2148,2149,2150],{"id":702,"depth":467,"text":703},{"id":824,"depth":467,"text":825},{"id":1586,"depth":467,"text":1589},{"id":1601,"depth":467,"text":1602},{"id":1954,"depth":467,"text":1955},{"id":608,"depth":461,"text":2081},"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.",[2155,2158,2161,2164],{"question":2156,"answer":2157},"What is D2Snap?","D2Snap is a first-of-its-kind downsampling algorithm for DOMs, used as a pre-processing technique for DOM snapshots to optimise context quality and token costs for web agents. It reduces DOM data at a variable ratio while retaining HTML characteristics valuable to an LLM backend. It is available as an open source package on GitHub and via the Webfuse Automation API.",{"question":2159,"answer":2160},"Why are DOM snapshots better than screenshots for web agents?","DOM snapshots connect with the LLM's code interpretation abilities, since LLMs are better at understanding HTML than images. They can be compiled from deep clones hidden from supervision, allow exact programmatic targeting of elements via CSS selectors, and are available with the DOMContentLoaded event. Their main drawback is that a raw DOM snapshot can cost into the hundreds of thousands of tokens.",{"question":2162,"answer":2163},"How does D2Snap reduce DOM size?","D2Snap applies three node-specific procedures to elements, text, and attributes, each controlled by a parameter between 0 and 1. It merges container elements like section and div, drops the lowest-ranking sentences using the TextRank algorithm, and removes attributes whose UI feature degree falls below a threshold. Interactive elements such as buttons are always kept as interaction target candidates.",{"question":2165,"answer":2166},"Which DOM feature matters most for web agent performance?","Hierarchy is the strongest of the three assessed features for LLM web agent backend performance. Because element extraction techniques throw away hierarchy by flattening the DOM tree, the findings suggest downsampling is a superior technique. In evaluation, the best D2Snap configuration outperformed a grounded GUI snapshot baseline by a significant margin.",{"homepage":506,"relatedLinks":2168},[2169,2173,2176],{"text":2170,"href":2171,"description":2172},"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":2174,"href":1616,"description":2175},"What is a Web Agent?","Learn the basics of web agents",{"text":1874,"href":2177,"external":506,"description":2178},"https://dev.webfuse.com/automation-api#take_dom_snapshot","Check out the Webfuse Automation API","/blog/dom-downsampling-for-llm-based-web-agents",{"title":520,"description":2153},{"loc":2179},"blog/1012.dom-downsampling-for-llm-based-web-agents",[476,2184,2185,2186,512,2187],"browser-agents","llms","llm-context","web-automation","3AW7t_LHaZoj6crLrnjTJiPgPcfEFf1yJH9b-zX2Rkw",{"id":2190,"title":2191,"authorId":521,"body":2192,"category":476,"created":2921,"description":2922,"extension":479,"faqs":2923,"featurePriority":494,"head":494,"landingPath":494,"meta":2936,"navigation":506,"ogImage":494,"path":1616,"robots":494,"schemaOrg":494,"seo":2945,"sitemap":2946,"stem":2947,"tags":2948,"__hash__":2949},"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":2193,"toc":2902},[2194,2208,2211,2218,2224,2228,2231,2246,2250,2260,2264,2268,2281,2285,2289,2292,2297,2301,2310,2314,2325,2330,2334,2352,2356,2362,2466,2469,2702,2718,2722,2725,2730,2734,2737,2741,2759,2784,2791,2795,2833,2836,2847,2851,2854,2882,2886,2894,2899],[11,2195,2196,2197,538,2201,716,2204,2207],{},"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 ",[532,2198,537],{"href":2199,"rel":2200},"https://openai.com/index/introducing-operator/",[536],[532,2202,543],{"href":541,"rel":2203},[536],[532,2205,334],{"href":546,"rel":2206},[536],". By now, it is within reach to automate arbitrary web-based tasks, such as booking the cheapest flight from Berlin to Amsterdam.",[59,2209,2174],{"id":2210},"what-is-a-web-agent",[11,2212,2213,2214,2217],{},"For starters, let us break down the term ",[28,2215,2216],{},"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.",[50,2219],{":width":2220,"alt":2221,"format":2222,"loading":55,"src":2223},"610","High-level agent description comparing human and computer agents","svg","/blog/a-gentle-introduction-to-ai-agents-for-the-web/1.svg",[94,2225,2227],{"id":2226},"the-role-of-frontier-llms","The Role of Frontier LLMs",[11,2229,2230],{},"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,2232,2233,2234,2241,2242,2245],{},"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 (",[576,2235,2236,2237,2240],{},"“",[838,2238,2239],{},"..."," e4 e5 2. Nc3 f5”","), and the respective task (",[576,2243,2244],{},"“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.",[94,2247,2249],{"id":2248},"generalist-web-agents","Generalist Web Agents",[11,2251,2252,2253,716,2256,2259],{},"Generalist web agents are supposed to solve arbitrary tasks through a web browser. Web-based tasks can be as diverse as ",[576,2254,2255],{},"“Find a picture of a cat.”",[576,2257,2258],{},"“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.",[50,2261],{":width":526,"alt":2262,"format":104,"loading":55,"src":2263},"Screenshot of a generalist web agent UI (Director)","/blog/a-gentle-introduction-to-ai-agents-for-the-web/2.png",[94,2265,2267],{"id":2266},"specialist-web-agents","Specialist Web Agents",[11,2269,2270,2271,2274,2275,2280],{},"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 ",[576,2272,2273],{},"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 ",[532,2276,2279],{"href":2277,"rel":2278},"https://docs.claude.com/en/docs/build-with-claude/prompt-engineering/system-prompts",[536],"system prompt"," can, moreover, be leveraged to drive specialist agent quality for the respective problem domain.",[50,2282],{":width":526,"alt":2283,"format":104,"loading":55,"src":2284},"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",[59,2286,2288],{"id":2287},"how-does-a-web-agent-work","How Does a Web Agent Work?",[11,2290,2291],{},"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).",[50,2293],{":width":2294,"alt":2295,"format":2222,"loading":55,"src":2296},"480","High-level web agent architecture component view","/blog/a-gentle-introduction-to-ai-agents-for-the-web/4.svg",[94,2298,2300],{"id":2299},"the-agent-lifecycle","The Agent Lifecycle",[11,2302,2303,2304,2309],{},"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 ",[532,2305,2308],{"href":2306,"rel":2307},"https://www.redfin.com",[536],"redfin.com",": In the first step, you specify a location. Only subsequently are you provided with a grid of available apartments for that location.",[50,2311],{":width":526,"alt":2312,"format":104,"loading":55,"src":2313},"Example of separated UI states in a rental home search application","/blog/a-gentle-introduction-to-ai-agents-for-the-web/5.png",[11,2315,2316,2317,2324],{},"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 ",[532,2318,2321],{"href":2319,"rel":2320},"https://mitpress.mit.edu/9780262640374/the-design-of-everyday-things/",[536],[576,2322,2323],{},"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.",[50,2326],{":width":2327,"alt":2328,"format":2222,"loading":55,"src":2329},"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",[94,2331,2333],{"id":2332},"web-context-for-llms","Web Context for LLMs",[11,2335,2336,2337,2339,2340,2343,2344,2347,2348,2351],{},"The gap from an agent towards the environment, according to ",[576,2338,2323],{},", is known as the ",[576,2341,2342],{},"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 ",[576,2345,2346],{},"gulf of intention"," towards the action planning stage: how to serialise a currently browsed web page's runtime state for LLMs? ",[576,2349,2350],{},"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?",[94,2353,2355],{"id":2354},"agentic-ui-interaction","Agentic UI Interaction",[11,2357,2358,2359,2361],{},"With a qualified set of well-defined actuation methods, web agents are able to close the ",[576,2360,2342],{}," 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:",[830,2363,2365],{"className":1633,"code":2364,"language":1635,"meta":460,"style":460},"interface ActuationSchema = {\n    thought: string;\n    action: \"click\"\n        | \"scroll\"\n        | \"type\";\n    cssSelector: string;\n    data?: string;\n}[];\n",[263,2366,2367,2381,2393,2410,2422,2434,2445,2456],{"__ignoreMap":460},[838,2368,2369,2372,2375,2378],{"class":840,"line":841},[838,2370,2371],{"class":1642},"interface",[838,2373,2374],{"class":1646}," ActuationSchema",[838,2376,2377],{"class":960}," = ",[838,2379,2380],{"class":1669},"{\n",[838,2382,2383,2386,2389,2391],{"class":840,"line":461},[838,2384,2385],{"class":960},"    thought",[838,2387,2388],{"class":844},":",[838,2390,1666],{"class":1665},[838,2392,1670],{"class":1669},[838,2394,2395,2398,2400,2403,2407],{"class":840,"line":467},[838,2396,2397],{"class":960},"    action",[838,2399,2388],{"class":844},[838,2401,2402],{"class":858}," \"",[838,2404,2406],{"class":2405},"sgAC-","click",[838,2408,2409],{"class":858},"\"\n",[838,2411,2412,2415,2417,2420],{"class":840,"line":971},[838,2413,2414],{"class":844},"        |",[838,2416,2402],{"class":858},[838,2418,2419],{"class":2405},"scroll",[838,2421,2409],{"class":858},[838,2423,2424,2426,2428,2430,2432],{"class":840,"line":980},[838,2425,2414],{"class":844},[838,2427,2402],{"class":858},[838,2429,1643],{"class":2405},[838,2431,859],{"class":858},[838,2433,1670],{"class":1669},[838,2435,2436,2439,2441,2443],{"class":840,"line":1001},[838,2437,2438],{"class":960},"    cssSelector",[838,2440,2388],{"class":844},[838,2442,1666],{"class":1665},[838,2444,1670],{"class":1669},[838,2446,2447,2450,2452,2454],{"class":840,"line":1020},[838,2448,2449],{"class":960},"    data",[838,2451,1691],{"class":844},[838,2453,1666],{"class":1665},[838,2455,1670],{"class":1669},[838,2457,2458,2461,2464],{"class":840,"line":1029},[838,2459,2460],{"class":1669},"}",[838,2462,2463],{"class":960},"[]",[838,2465,1670],{"class":1669},[11,2467,2468],{},"And a suggested actions response could, in turn, look as follows:",[830,2470,2474],{"className":2471,"code":2472,"language":2473,"meta":460,"style":460},"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",[263,2475,2476,2481,2486,2510,2529,2547,2552,2556,2575,2593,2612,2630,2634,2638,2657,2675,2692,2697],{"__ignoreMap":460},[838,2477,2478],{"class":840,"line":841},[838,2479,2480],{"class":1669},"[\n",[838,2482,2483],{"class":840,"line":461},[838,2484,2485],{"class":1669},"    {\n",[838,2487,2488,2492,2496,2498,2500,2502,2506,2508],{"class":840,"line":467},[838,2489,2491],{"class":2490},"srFR9","        \"",[838,2493,2495],{"class":2494},"s30W1","thought",[838,2497,859],{"class":2490},[838,2499,2388],{"class":1669},[838,2501,2402],{"class":858},[838,2503,2505],{"class":2504},"sCC8C","Scroll newsletter cta into view",[838,2507,859],{"class":858},[838,2509,1751],{"class":1669},[838,2511,2512,2514,2517,2519,2521,2523,2525,2527],{"class":840,"line":971},[838,2513,2491],{"class":2490},[838,2515,2516],{"class":2494},"action",[838,2518,859],{"class":2490},[838,2520,2388],{"class":1669},[838,2522,2402],{"class":858},[838,2524,2419],{"class":2504},[838,2526,859],{"class":858},[838,2528,1751],{"class":1669},[838,2530,2531,2533,2536,2538,2540,2542,2545],{"class":840,"line":980},[838,2532,2491],{"class":2490},[838,2534,2535],{"class":2494},"cssSelector",[838,2537,859],{"class":2490},[838,2539,2388],{"class":1669},[838,2541,2402],{"class":858},[838,2543,2544],{"class":2504},"section#newsletter",[838,2546,2409],{"class":858},[838,2548,2549],{"class":840,"line":1001},[838,2550,2551],{"class":1669},"    },\n",[838,2553,2554],{"class":840,"line":1020},[838,2555,2485],{"class":1669},[838,2557,2558,2560,2562,2564,2566,2568,2571,2573],{"class":840,"line":1029},[838,2559,2491],{"class":2490},[838,2561,2495],{"class":2494},[838,2563,859],{"class":2490},[838,2565,2388],{"class":1669},[838,2567,2402],{"class":858},[838,2569,2570],{"class":2504},"Type email address to newsletter cta",[838,2572,859],{"class":858},[838,2574,1751],{"class":1669},[838,2576,2577,2579,2581,2583,2585,2587,2589,2591],{"class":840,"line":1035},[838,2578,2491],{"class":2490},[838,2580,2516],{"class":2494},[838,2582,859],{"class":2490},[838,2584,2388],{"class":1669},[838,2586,2402],{"class":858},[838,2588,1643],{"class":2504},[838,2590,859],{"class":858},[838,2592,1751],{"class":1669},[838,2594,2595,2597,2599,2601,2603,2605,2608,2610],{"class":840,"line":1041},[838,2596,2491],{"class":2490},[838,2598,2535],{"class":2494},[838,2600,859],{"class":2490},[838,2602,2388],{"class":1669},[838,2604,2402],{"class":858},[838,2606,2607],{"class":2504},"section#newsletter > input",[838,2609,859],{"class":858},[838,2611,1751],{"class":1669},[838,2613,2614,2616,2619,2621,2623,2625,2628],{"class":840,"line":1051},[838,2615,2491],{"class":2490},[838,2617,2618],{"class":2494},"data",[838,2620,859],{"class":2490},[838,2622,2388],{"class":1669},[838,2624,2402],{"class":858},[838,2626,2627],{"class":2504},"user@example.org",[838,2629,2409],{"class":858},[838,2631,2632],{"class":840,"line":1080},[838,2633,2551],{"class":1669},[838,2635,2636],{"class":840,"line":1090},[838,2637,2485],{"class":1669},[838,2639,2640,2642,2644,2646,2648,2650,2653,2655],{"class":840,"line":1109},[838,2641,2491],{"class":2490},[838,2643,2495],{"class":2494},[838,2645,859],{"class":2490},[838,2647,2388],{"class":1669},[838,2649,2402],{"class":858},[838,2651,2652],{"class":2504},"Submit newsletter sign up",[838,2654,859],{"class":858},[838,2656,1751],{"class":1669},[838,2658,2659,2661,2663,2665,2667,2669,2671,2673],{"class":840,"line":1127},[838,2660,2491],{"class":2490},[838,2662,2516],{"class":2494},[838,2664,859],{"class":2490},[838,2666,2388],{"class":1669},[838,2668,2402],{"class":858},[838,2670,2406],{"class":2504},[838,2672,859],{"class":858},[838,2674,1751],{"class":1669},[838,2676,2677,2679,2681,2683,2685,2687,2690],{"class":840,"line":1136},[838,2678,2491],{"class":2490},[838,2680,2535],{"class":2494},[838,2682,859],{"class":2490},[838,2684,2388],{"class":1669},[838,2686,2402],{"class":858},[838,2688,2689],{"class":2504},"section#newsletter > button",[838,2691,2409],{"class":858},[838,2693,2694],{"class":840,"line":1142},[838,2695,2696],{"class":1669},"    }\n",[838,2698,2699],{"class":840,"line":1148},[838,2700,2701],{"class":1669},"]\n",[725,2703,2704],{},[11,2705,2706,2711,2712,2717],{},[532,2707,2710],{"href":2708,"rel":2709},"https://platform.openai.com/docs/guides/function-calling",[536],"Function Calling"," and the ",[532,2713,2716],{"href":2714,"rel":2715},"https://modelcontextprotocol.io",[536],"Model Context Protocol"," represent two ends to outsource an explicit actuation model – server- and client-side, respectively.",[94,2719,2721],{"id":2720},"agentic-ui-augmentation","Agentic UI Augmentation",[11,2723,2724],{},"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.",[50,2726],{":width":2727,"alt":2728,"format":2222,"loading":55,"src":2729},"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",[59,2731,2733],{"id":2732},"how-to-build-a-web-agent","How to Build a Web Agent?",[11,2735,2736],{},"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.",[94,2738,2740],{"id":2739},"develop-a-web-agent","Develop a Web Agent",[11,2742,2743,2744,2747,2748,716,2753,2758],{},"Opting for a ",[28,2745,2746],{},"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., ",[532,2749,2752],{"href":2750,"rel":2751},"https://elevenlabs.io/conversational-ai",[536],"ElevenLabs",[532,2754,2757],{"href":2755,"rel":2756},"https://www.intercom.com/drlp/ai-agent",[536],"Intercom",". Serviced agents hide LLM communication and potentially interaction with a web browser behind the configuration interface.",[11,2760,2761,2762,2765,2766,2771,2772,2777,2778,2783],{},"Using a ",[28,2763,2764],{},"templated agent"," resembles the agent-as-a-service approach on a lower level. Openly sourced from a ",[532,2767,2770],{"href":2768,"rel":2769},"https://github.com/webfuse-com/agent-extension-blueprint",[536],"code repository",", templated agents allow for any kind of development tweaks. Favourably, agent templates shortcut integration with ",[532,2773,2776],{"href":2774,"rel":2775},"https://openai.com/api/",[536],"LLM APIs"," and web ",[532,2779,2782],{"href":2780,"rel":2781},"https://developer.mozilla.org/en-US/docs/Web/API",[536],"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,2785,2786,2787,2790],{},"Of course, developing an ",[28,2788,2789],{},"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.",[94,2792,2794],{"id":2793},"deploy-a-web-agent","Deploy a Web Agent",[11,2796,2797,2798,749,2803,2808,2809,2814,2815,2820,2821,2826,2827,2832],{},"When web agent code lives side-by-side with the augmented application's code, agent deployment is covered by a generic pipeline. Something like: ",[532,2799,2802],{"href":2800,"rel":2801},"https://eslint.org",[536],"linting",[532,2804,2807],{"href":2805,"rel":2806},"https://prettier.io",[536],"formatting"," agent code, ",[532,2810,2813],{"href":2811,"rel":2812},"https://esbuild.github.io",[536],"transpiling and bundling"," agent modules, ",[532,2816,2819],{"href":2817,"rel":2818},"https://www.cypress.io",[536],"testing"," agent, ",[532,2822,2825],{"href":2823,"rel":2824},"https://pages.cloudflare.com",[536],"hosting"," agent bundle, and ",[532,2828,2831],{"href":2829,"rel":2830},"https://docs.github.com/en/actions/get-started/continuous-integration",[536],"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,2834,2835],{},"Web agent source code right inside the application codebase comes at a cost:",[22,2837,2838,2841,2844],{},[25,2839,2840],{},"Agent developers can manipulate the source code of the underlying application.",[25,2842,2843],{},"Agent functionality could introduce side effects on the underlying application.",[25,2845,2846],{},"Agent changes require deployment of the entire application.",[94,2848,2850],{"id":2849},"best-practices-of-agentic-ux","Best Practices of Agentic UX",[11,2852,2853],{},"When designing user experiences for agent-enhanced applications, there are a few things to consider:",[22,2855,2856,2857,2856,2866,2856,2874],{},"\n    ",[25,2858,2859,2860,2859,2863,2865],{},"\n        ",[28,2861,2862],{},"Stream input and output to reduce latency",[2060,2864],{},"\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,2867,2859,2868,2859,2871,2873],{},[28,2869,2870],{},"Provide fine-grained feedback to bridge high-latency",[2060,2872],{},"\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,2875,2859,2876,2859,2879,2881],{},[28,2877,2878],{},"Always prompt the human user for consent to perform critical actions",[2060,2880],{},"\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    ",[94,2883,2885],{"id":2884},"non-invasive-web-agents-with-webfuse","Non-Invasive Web Agents with Webfuse",[11,2887,2888,2893],{},[532,2889,2891],{"href":1878,"rel":2890},[536],[28,2892,243],{}," 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.",[209,2895],{":demoAction":2896,"heading":2897,"subtitle":2898},"{\"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.",[2134,2900,2901],{},"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 .scGhl, html code.shiki .scGhl{--shiki-default:#7C7F93;--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 .sbuKk, html code.shiki .sbuKk{--shiki-default:#40A02B;--shiki-dark:#D9F5DD}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}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 .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 .sCC8C, html code.shiki .sCC8C{--shiki-default:#40A02B;--shiki-dark:#C789D6}",{"title":460,"searchDepth":461,"depth":461,"links":2903},[2904,2909,2915],{"id":2210,"depth":461,"text":2174,"children":2905},[2906,2907,2908],{"id":2226,"depth":467,"text":2227},{"id":2248,"depth":467,"text":2249},{"id":2266,"depth":467,"text":2267},{"id":2287,"depth":461,"text":2288,"children":2910},[2911,2912,2913,2914],{"id":2299,"depth":467,"text":2300},{"id":2332,"depth":467,"text":2333},{"id":2354,"depth":467,"text":2355},{"id":2720,"depth":467,"text":2721},{"id":2732,"depth":461,"text":2733,"children":2916},[2917,2918,2919,2920],{"id":2739,"depth":467,"text":2740},{"id":2793,"depth":467,"text":2794},{"id":2849,"depth":467,"text":2850},{"id":2884,"depth":467,"text":2885},"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.",[2924,2927,2930,2933],{"question":2925,"answer":2926},"What is a web AI agent?","A web AI agent is an application that autonomously acts on behalf of a human by operating a website through its user interface rather than its API. It uses a large language model to interpret the page and decide what to click, type, or scroll to complete a task. This human-like interaction lets it work on websites built for people rather than machines.",{"question":2928,"answer":2929},"What is the difference between a generalist and a specialist web agent?","A generalist web agent is built to solve arbitrary tasks across any website, while a specialist agent is constrained to one task and application domain. Generalist agents remain early proofs of concept and often fail on uncommon or highly precise tasks. Specialist agents, such as on-page chat and voice assistants, carry most of the current commercial value.",{"question":2931,"answer":2932},"How does a web agent work?","A web agent sits between a web browser and an LLM backend and runs an iterative loop. It serialises the page's current runtime state into a snapshot, sends that snapshot to the LLM along with the task, receives a planned action such as a click or keystroke, and executes it. It then evaluates the new page state and repeats the cycle until the result matches the declared goal.",{"question":2934,"answer":2935},"How do you build a web agent?","There are three main paths: use a pre-compiled agent configured through an agent-as-a-service provider, adapt an open-source templated agent, or develop one from scratch. Templated agents are usually the best balance, because they shortcut integration with LLM and browser APIs while still allowing full customisation.",{"homepage":506,"relatedLinks":2937},[2938,2939,2943],{"text":2170,"href":2171,"description":2172},{"text":2940,"href":2941,"description":2942},"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":1874,"href":2944,"external":506,"description":2178},"https://dev.webfuse.com/automation-api/",{"title":2191,"description":2922},{"loc":1616},"blog/1011.a-gentle-introduction-to-ai-agents-for-the-web",[476,2184,2185,512,2187],"IB7gPedi1oLYTLac9mfXKYLmZAOXLkFuxGa9Y4zDIhs",1783434593711]