[{"data":1,"prerenderedAt":5081},["ShallowReactive",2],{"/blog/what-is-webmcp-the-practical-guide-to-the-web-model-context-protocol":3,"related-/blog/what-is-webmcp-the-practical-guide-to-the-web-model-context-protocol":2645},{"id":4,"title":5,"authorId":6,"body":7,"category":2598,"created":2599,"description":2600,"extension":2601,"faqs":2602,"featurePriority":2624,"head":2625,"landingPath":2625,"meta":2626,"navigation":945,"ogImage":2625,"path":2634,"robots":2625,"schemaOrg":2625,"seo":2635,"sitemap":2636,"stem":2637,"tags":2638,"__hash__":2644},"blog/blog/1039.what-is-webmcp-the-practical-guide-to-the-web-model-context-protocol.md","What Is WebMCP? A Practical Guide to the Web Model Context Protocol","salome-koshadze",{"type":8,"value":9,"toc":2564},"minimark",[10,20,23,26,29,34,43,46,51,62,150,153,157,160,176,180,183,186,202,205,209,213,216,219,264,268,274,425,428,432,443,447,451,461,468,474,481,740,746,749,885,894,903,973,977,984,987,990,1026,1029,1344,1347,1634,1638,1653,1863,1866,1870,1873,1877,1990,1994,2014,2017,2021,2028,2032,2038,2146,2149,2153,2173,2179,2183,2187,2190,2221,2224,2228,2231,2235,2238,2241,2255,2259,2262,2284,2288,2292,2299,2302,2328,2332,2338,2346,2349,2372,2486,2495,2499,2502,2529,2547,2551,2554,2557,2560],[11,12,13,14,19],"p",{},"WebMCP is a proposed browser standard that lets websites expose structured tools directly to AI agents. Instead of forcing an agent to interpret a page visually and click through the interface like a human, WebMCP gives it a machine-readable way to discover actions and pass structured inputs. If you are new to the broader category, see ",[15,16,18],"a",{"href":17},"/blog/a-gentle-introduction-to-ai-agents-for-the-web","A Gentle Introduction to AI Agents for the Web",".",[11,21,22],{},"In short: WebMCP is meant to replace brittle screen-scraping with direct tool use inside the browser. As of 2026, it is still experimental and mainly available through Chrome early preview tooling.",[24,25],"article-cheatsheet-card",{},[11,27,28],{},"Websites are primarily built for human interaction, with visual layouts, buttons, and forms designed for manual input. As AI agents become more capable of performing tasks on our behalf, they face a major challenge: they must interpret these human-centric interfaces, often leading to slow and unreliable performance. WebMCP is designed to solve this problem by creating a direct, structured communication channel between websites and AI agents.",[30,31,33],"h2",{"id":32},"what-is-webmcp-and-how-does-it-work","What Is WebMCP and How Does It Work?",[35,36],"nuxt-picture",{":width":37,"alt":38,"loading":39,"provider":40,"src":41,"format":42},"900","Illustration of WebMCP enabling a more programmable and intelligent web","lazy","none","/blog/what-is-webmcp-the-practical-guide-to-the-web-model-context-protocol/6.svg","webp",[11,44,45],{},"At a high level, WebMCP gives a live webpage a structured way to expose actions to an AI agent. Instead of forcing the agent to infer meaning from the DOM and visual layout, the page can expose machine-readable tools, inputs, and current state.",[47,48,50],"h3",{"id":49},"webmcp-vs-mcp-vs-openapi-the-fastest-way-to-understand-the-difference","WebMCP vs. MCP vs. OpenAPI: The Fastest Way to Understand the Difference",[11,52,53,54,58,59,19],{},"One reason WebMCP can be confusing is that it sits next to other AI integration approaches rather than replacing them. The shortest explanation is this: ",[55,56,57],"strong",{},"WebMCP is for live, in-browser interaction with a webpage",", while ",[55,60,61],{},"MCP and OpenAPI are typically used for backend or service-level integrations",[63,64,65,84],"table",{},[66,67,68],"thead",{},[69,70,71,75,78,81],"tr",{},[72,73,74],"th",{},"Approach",[72,76,77],{},"Where it runs",[72,79,80],{},"Browser required?",[72,82,83],{},"Best for",[85,86,87,104,120,135],"tbody",{},[69,88,89,95,98,101],{},[90,91,92],"td",{},[55,93,94],{},"WebMCP",[90,96,97],{},"In the user's browser on a live webpage",[90,99,100],{},"Yes",[90,102,103],{},"User-in-the-loop tasks on websites",[69,105,106,111,114,117],{},[90,107,108],{},[55,109,110],{},"MCP",[90,112,113],{},"Between an AI system and external tools/services",[90,115,116],{},"No",[90,118,119],{},"Structured tool access across backend systems",[69,121,122,127,130,132],{},[90,123,124],{},[55,125,126],{},"OpenAPI",[90,128,129],{},"Between clients and HTTP APIs",[90,131,116],{},[90,133,134],{},"Stable API integrations and service endpoints",[69,136,137,142,145,147],{},[90,138,139],{},[55,140,141],{},"Screen-scraping",[90,143,144],{},"Through the DOM and rendered UI",[90,146,100],{},[90,148,149],{},"Sites with no structured interface",[11,151,152],{},"In practice, many products may eventually use more than one approach. A company might offer an MCP server or OpenAPI endpoint for backend automation while also using WebMCP to help an AI agent assist a user on the live website.",[30,154,156],{"id":155},"the-bridge-between-websites-and-ai-agents","The Bridge Between Websites and AI Agents",[11,158,159],{},"At its core, WebMCP provides a standardized \"contract\" that allows a website to explicitly declare its functionality to a browser's AI agent. Instead of forcing an agent to guess the purpose of a form field or the action of a button by analyzing the page's visual structure, a website can publish a set of defined \"tools\" that the agent can use directly.",[11,161,162,163,166,167,171,172,19],{},"This approach marks a major shift away from the current common practice of ",[55,164,165],{},"screen-scraping",", where an agent programmatically \"looks\" at a webpage to simulate human actions. That problem is closely related to the challenges discussed in ",[15,168,170],{"href":169},"/blog/how-voice-agents-see-and-act-a-guide-to-dom-tools","How Voice Agents See and Act: A Guide to DOM Tools"," and ",[15,173,175],{"href":174},"/blog/dom-downsampling-for-llm-based-web-agents","DOM Downsampling for LLM-Based Web Agents",[47,177,179],{"id":178},"life-without-webmcp-the-limits-of-screen-scraping","Life Without WebMCP: The Limits of Screen-Scraping",[11,181,182],{},"Today, an AI agent trying to complete a task on a website operates with limited information. It must analyze the Document Object Model (DOM) and visual layout to infer meaning.",[11,184,185],{},"Consider an agent tasked with booking a flight. It would have to:",[187,188,189,193,196,199],"ol",{},[190,191,192],"li",{},"Identify input fields for \"Origin\" and \"Destination\" based on nearby text labels.",[190,194,195],{},"Locate a calendar widget and programmatically click through months and days to select dates.",[190,197,198],{},"Find a dropdown or stepper for the number of passengers.",[190,200,201],{},"Locate and trigger the \"Search Flights\" button.",[11,203,204],{},"This process is not only inefficient but also highly fragile. A small change in the website's design, like renaming a button or restructuring a form, could easily break the agent's workflow, requiring a complete reprogramming of its logic for that specific site.",[35,206],{":width":37,"alt":207,"loading":39,"provider":40,"src":208,"format":42},"Diagram showing the fragility of screen-scraping for AI agents on websites","/blog/what-is-webmcp-the-practical-guide-to-the-web-model-context-protocol/1.svg",[47,210,212],{"id":211},"the-webmcp-solution-a-contract-for-interaction","The WebMCP Solution: A Contract for Interaction",[11,214,215],{},"WebMCP replaces this guesswork with a clear, machine-readable interface. A website can use JavaScript to register tools and their specific parameters, providing a stable API for agents. This contract defines three main areas for interaction.",[11,217,218],{},"It establishes a shared understanding through these key components:",[220,221,222,236,254],"ul",{},[190,223,224,227,228,232,233,19],{},[55,225,226],{},"Discovery:"," A standard way for an agent to query a webpage and ask, \"What can you do?\" The site responds with a list of available tools, such as ",[229,230,231],"code",{},"searchFlights"," or ",[229,234,235],{},"submitApplication",[190,237,238,241,242,245,246,249,250,253],{},[55,239,240],{},"JSON Schemas:"," Each tool comes with an explicit definition of its required inputs and expected outputs. For a flight search, the schema would clearly state it needs parameters like ",[229,243,244],{},"origin",", ",[229,247,248],{},"destination",", and ",[229,251,252],{},"outboundDate",", preventing the agent from providing incorrect or incomplete data.",[190,255,256,259,260,263],{},[55,257,258],{},"State:"," The protocol creates a shared context, allowing the agent to know which tools are available in real-time as the user navigates the application. For example, a ",[229,261,262],{},"checkout"," tool would only become available after items have been added to a shopping cart.",[35,265],{":width":37,"alt":266,"loading":39,"provider":40,"src":267,"format":42},"Diagram showing WebMCP shared context and real-time tool availability for AI agents","/blog/what-is-webmcp-the-practical-guide-to-the-web-model-context-protocol/2.svg",[11,269,270,271,273],{},"With WebMCP, the same flight booking task becomes a single, direct action. The website exposes a ",[229,272,231],{}," tool. The agent can then call this tool with a structured data object, like the one below, to execute the search instantly and reliably.",[275,276,281],"pre",{"className":277,"code":278,"language":279,"meta":280,"style":280},"language-json shiki shiki-themes catppuccin-latte night-owl","{\n  \"origin\": \"LON\",\n  \"destination\": \"NYC\",\n  \"tripType\": \"round-trip\",\n  \"outboundDate\": \"2026-06-10\",\n  \"inboundDate\": \"2026-06-17\",\n  \"passengers\": 2\n}\n","json","",[229,282,283,292,321,341,362,382,403,419],{"__ignoreMap":280},[284,285,288],"span",{"class":286,"line":287},"line",1,[284,289,291],{"class":290},"scGhl","{\n",[284,293,295,299,302,305,308,312,316,318],{"class":286,"line":294},2,[284,296,298],{"class":297},"srFR9","  \"",[284,300,244],{"class":301},"s30W1",[284,303,304],{"class":297},"\"",[284,306,307],{"class":290},":",[284,309,311],{"class":310},"sbuKk"," \"",[284,313,315],{"class":314},"sCC8C","LON",[284,317,304],{"class":310},[284,319,320],{"class":290},",\n",[284,322,324,326,328,330,332,334,337,339],{"class":286,"line":323},3,[284,325,298],{"class":297},[284,327,248],{"class":301},[284,329,304],{"class":297},[284,331,307],{"class":290},[284,333,311],{"class":310},[284,335,336],{"class":314},"NYC",[284,338,304],{"class":310},[284,340,320],{"class":290},[284,342,344,346,349,351,353,355,358,360],{"class":286,"line":343},4,[284,345,298],{"class":297},[284,347,348],{"class":301},"tripType",[284,350,304],{"class":297},[284,352,307],{"class":290},[284,354,311],{"class":310},[284,356,357],{"class":314},"round-trip",[284,359,304],{"class":310},[284,361,320],{"class":290},[284,363,365,367,369,371,373,375,378,380],{"class":286,"line":364},5,[284,366,298],{"class":297},[284,368,252],{"class":301},[284,370,304],{"class":297},[284,372,307],{"class":290},[284,374,311],{"class":310},[284,376,377],{"class":314},"2026-06-10",[284,379,304],{"class":310},[284,381,320],{"class":290},[284,383,385,387,390,392,394,396,399,401],{"class":286,"line":384},6,[284,386,298],{"class":297},[284,388,389],{"class":301},"inboundDate",[284,391,304],{"class":297},[284,393,307],{"class":290},[284,395,311],{"class":310},[284,397,398],{"class":314},"2026-06-17",[284,400,304],{"class":310},[284,402,320],{"class":290},[284,404,406,408,411,413,415],{"class":286,"line":405},7,[284,407,298],{"class":297},[284,409,410],{"class":301},"passengers",[284,412,304],{"class":297},[284,414,307],{"class":290},[284,416,418],{"class":417},"sZ_Zo"," 2\n",[284,420,422],{"class":286,"line":421},8,[284,423,424],{"class":290},"}\n",[11,426,427],{},"This method is faster, more resilient to UI changes, and opens the door for more complex, collaborative workflows between humans and AI agents on the web.",[30,429,431],{"id":430},"how-webmcp-works-the-imperative-and-declarative-apis","How WebMCP Works: The Imperative and Declarative APIs",[11,433,434,435,438,439,442],{},"WebMCP offers developers two distinct methods for exposing tools to AI agents. The choice between them depends on the complexity of the website's architecture and the nature of the tasks being automated. The ",[55,436,437],{},"Imperative API"," provides fine-grained control using JavaScript, suitable for dynamic single-page applications (SPAs). The ",[55,440,441],{},"Declarative API"," offers a simpler approach by adding special attributes to standard HTML forms, making it ideal for converting existing forms into agent-accessible tools with minimal code changes.",[35,444],{":width":37,"alt":445,"loading":39,"provider":40,"src":446,"format":42},"Diagram comparing the WebMCP Imperative API and Declarative API approaches","/blog/what-is-webmcp-the-practical-guide-to-the-web-model-context-protocol/3.svg",[30,448,450],{"id":449},"the-imperative-api-defining-tools-with-javascript","The Imperative API: Defining Tools with JavaScript",[11,452,453,454,232,457,460],{},"The Imperative API allows developers to programmatically manage the lifecycle of tools available to an agent. This method is highly flexible and works well in applications where the available actions change frequently based on the user's context or application state. For example, in a document editor, tools like ",[229,455,456],{},"formatText",[229,458,459],{},"insertImage"," can be registered or unregistered as the user selects different elements on the page.",[11,462,463,464,467],{},"Four main functions form the core of the Imperative API. They are accessed through the ",[229,465,466],{},"window.navigator.modelContext"," object.",[47,469,471],{"id":470},"registertool",[229,472,473],{},"registerTool",[11,475,476,477,480],{},"This function adds a single tool to the current set of available tools without affecting others. It is useful for incrementally adding functionality as new UI components are loaded or become active. Each tool definition includes a name, a natural language description for the agent, a JSON schema for its inputs, and an ",[229,478,479],{},"execute"," function that contains the logic to be run.",[275,482,486],{"className":483,"code":484,"language":485,"meta":280,"style":280},"language-javascript shiki shiki-themes catppuccin-latte night-owl","window.navigator.modelContext.registerTool({\n  name: \"addTodo\",\n  description: \"Add a new item to the todo list\",\n  inputSchema: {\n    type: \"object\",\n    properties: {\n      text: { type: \"string\" },\n    },\n  },\n  execute: ({ text }) => {\n    // Application logic to add the todo item\n    return { content: [{ type: \"text\", text: `Added todo: ${text}` }] };\n  },\n});\n","javascript",[229,487,488,517,535,551,561,577,586,611,616,622,653,660,725,730],{"__ignoreMap":280},[284,489,490,494,497,501,503,506,508,511,515],{"class":286,"line":287},[284,491,493],{"class":492},"sP4PM","window",[284,495,19],{"class":496},"s5FwJ",[284,498,500],{"class":499},"sHY1S","navigator",[284,502,19],{"class":496},[284,504,505],{"class":499},"modelContext",[284,507,19],{"class":496},[284,509,473],{"class":510},"sNstc",[284,512,514],{"class":513},"s2kId","(",[284,516,291],{"class":290},[284,518,519,522,525,527,531,533],{"class":286,"line":294},[284,520,521],{"class":513},"  name",[284,523,307],{"class":524},"sVS64",[284,526,311],{"class":310},[284,528,530],{"class":529},"sfrMT","addTodo",[284,532,304],{"class":310},[284,534,320],{"class":290},[284,536,537,540,542,544,547,549],{"class":286,"line":323},[284,538,539],{"class":513},"  description",[284,541,307],{"class":524},[284,543,311],{"class":310},[284,545,546],{"class":529},"Add a new item to the todo list",[284,548,304],{"class":310},[284,550,320],{"class":290},[284,552,553,556,558],{"class":286,"line":343},[284,554,555],{"class":513},"  inputSchema",[284,557,307],{"class":524},[284,559,560],{"class":290}," {\n",[284,562,563,566,568,570,573,575],{"class":286,"line":364},[284,564,565],{"class":513},"    type",[284,567,307],{"class":524},[284,569,311],{"class":310},[284,571,572],{"class":529},"object",[284,574,304],{"class":310},[284,576,320],{"class":290},[284,578,579,582,584],{"class":286,"line":384},[284,580,581],{"class":513},"    properties",[284,583,307],{"class":524},[284,585,560],{"class":290},[284,587,588,591,593,596,599,601,603,606,608],{"class":286,"line":405},[284,589,590],{"class":513},"      text",[284,592,307],{"class":524},[284,594,595],{"class":290}," {",[284,597,598],{"class":513}," type",[284,600,307],{"class":524},[284,602,311],{"class":310},[284,604,605],{"class":529},"string",[284,607,304],{"class":310},[284,609,610],{"class":290}," },\n",[284,612,613],{"class":286,"line":421},[284,614,615],{"class":290},"    },\n",[284,617,619],{"class":286,"line":618},9,[284,620,621],{"class":290},"  },\n",[284,623,625,628,630,634,637,641,644,647,651],{"class":286,"line":624},10,[284,626,627],{"class":510},"  execute",[284,629,307],{"class":524},[284,631,633],{"class":632},"sMtgK"," (",[284,635,636],{"class":290},"{",[284,638,640],{"class":639},"sIhCM"," text",[284,642,643],{"class":290}," }",[284,645,646],{"class":632},")",[284,648,650],{"class":649},"s76yb"," =>",[284,652,560],{"class":290},[284,654,656],{"class":286,"line":655},11,[284,657,659],{"class":658},"sDmS1","    // Application logic to add the todo item\n",[284,661,663,667,669,672,674,677,679,681,683,685,688,690,693,695,697,701,704,708,711,714,717,719,722],{"class":286,"line":662},12,[284,664,666],{"class":665},"srhcd","    return",[284,668,595],{"class":290},[284,670,671],{"class":513}," content",[284,673,307],{"class":524},[284,675,676],{"class":513}," [",[284,678,636],{"class":290},[284,680,598],{"class":513},[284,682,307],{"class":524},[284,684,311],{"class":310},[284,686,687],{"class":529},"text",[284,689,304],{"class":310},[284,691,692],{"class":290},",",[284,694,640],{"class":513},[284,696,307],{"class":524},[284,698,700],{"class":699},"sizNf"," `",[284,702,703],{"class":529},"Added todo: ",[284,705,707],{"class":706},"sDF9U","${",[284,709,687],{"class":710},"soAP-",[284,712,713],{"class":706},"}",[284,715,716],{"class":699},"`",[284,718,643],{"class":290},[284,720,721],{"class":513},"] ",[284,723,724],{"class":290},"};\n",[284,726,728],{"class":286,"line":727},13,[284,729,621],{"class":290},[284,731,733,735,737],{"class":286,"line":732},14,[284,734,713],{"class":290},[284,736,646],{"class":513},[284,738,739],{"class":290},";\n",[47,741,743],{"id":742},"providecontext",[229,744,745],{},"provideContext",[11,747,748],{},"This function is a convenience wrapper that replaces the entire set of registered tools at once. It is suitable for major state transitions in an application, such as navigating to a completely different section of a site. It ensures that the agent only has access to the tools relevant to the current view.",[275,750,752],{"className":483,"code":751,"language":485,"meta":280,"style":280},"window.navigator.modelContext.provideContext({\n  tools: [\n    {\n      name: \"addTodo\",\n      description: \"Add a new item to the todo list\",\n      // ... schema and execute function\n    },\n    {\n      name: \"markComplete\",\n      description: \"Mark a todo item as complete\",\n      // ... schema and execute function\n    },\n  ],\n});\n",[229,753,754,774,784,789,804,819,824,828,832,847,862,866,870,877],{"__ignoreMap":280},[284,755,756,758,760,762,764,766,768,770,772],{"class":286,"line":287},[284,757,493],{"class":492},[284,759,19],{"class":496},[284,761,500],{"class":499},[284,763,19],{"class":496},[284,765,505],{"class":499},[284,767,19],{"class":496},[284,769,745],{"class":510},[284,771,514],{"class":513},[284,773,291],{"class":290},[284,775,776,779,781],{"class":286,"line":294},[284,777,778],{"class":513},"  tools",[284,780,307],{"class":524},[284,782,783],{"class":513}," [\n",[284,785,786],{"class":286,"line":323},[284,787,788],{"class":290},"    {\n",[284,790,791,794,796,798,800,802],{"class":286,"line":343},[284,792,793],{"class":513},"      name",[284,795,307],{"class":524},[284,797,311],{"class":310},[284,799,530],{"class":529},[284,801,304],{"class":310},[284,803,320],{"class":290},[284,805,806,809,811,813,815,817],{"class":286,"line":364},[284,807,808],{"class":513},"      description",[284,810,307],{"class":524},[284,812,311],{"class":310},[284,814,546],{"class":529},[284,816,304],{"class":310},[284,818,320],{"class":290},[284,820,821],{"class":286,"line":384},[284,822,823],{"class":658},"      // ... schema and execute function\n",[284,825,826],{"class":286,"line":405},[284,827,615],{"class":290},[284,829,830],{"class":286,"line":421},[284,831,788],{"class":290},[284,833,834,836,838,840,843,845],{"class":286,"line":618},[284,835,793],{"class":513},[284,837,307],{"class":524},[284,839,311],{"class":310},[284,841,842],{"class":529},"markComplete",[284,844,304],{"class":310},[284,846,320],{"class":290},[284,848,849,851,853,855,858,860],{"class":286,"line":624},[284,850,808],{"class":513},[284,852,307],{"class":524},[284,854,311],{"class":310},[284,856,857],{"class":529},"Mark a todo item as complete",[284,859,304],{"class":310},[284,861,320],{"class":290},[284,863,864],{"class":286,"line":655},[284,865,823],{"class":658},[284,867,868],{"class":286,"line":662},[284,869,615],{"class":290},[284,871,872,875],{"class":286,"line":727},[284,873,874],{"class":513},"  ]",[284,876,320],{"class":290},[284,878,879,881,883],{"class":286,"line":732},[284,880,713],{"class":290},[284,882,646],{"class":513},[284,884,739],{"class":290},[47,886,888,171,891],{"id":887},"unregistertool-and-clearcontext",[229,889,890],{},"unregisterTool",[229,892,893],{},"clearContext",[11,895,896,897,899,900,902],{},"To manage the available tools, WebMCP provides functions for removal. ",[229,898,890],{}," removes a specific tool by its name, while ",[229,901,893],{}," removes all currently registered tools at once.",[275,904,906],{"className":483,"code":905,"language":485,"meta":280,"style":280},"// Remove a single tool\nwindow.navigator.modelContext.unregisterTool(\"addTodo\");\n\n// Remove all tools\nwindow.navigator.modelContext.clearContext();\n",[229,907,908,913,941,947,952],{"__ignoreMap":280},[284,909,910],{"class":286,"line":287},[284,911,912],{"class":658},"// Remove a single tool\n",[284,914,915,917,919,921,923,925,927,929,931,933,935,937,939],{"class":286,"line":294},[284,916,493],{"class":492},[284,918,19],{"class":496},[284,920,500],{"class":499},[284,922,19],{"class":496},[284,924,505],{"class":499},[284,926,19],{"class":496},[284,928,890],{"class":510},[284,930,514],{"class":513},[284,932,304],{"class":310},[284,934,530],{"class":529},[284,936,304],{"class":310},[284,938,646],{"class":513},[284,940,739],{"class":290},[284,942,943],{"class":286,"line":323},[284,944,946],{"emptyLinePlaceholder":945},true,"\n",[284,948,949],{"class":286,"line":343},[284,950,951],{"class":658},"// Remove all tools\n",[284,953,954,956,958,960,962,964,966,968,971],{"class":286,"line":364},[284,955,493],{"class":492},[284,957,19],{"class":496},[284,959,500],{"class":499},[284,961,19],{"class":496},[284,963,505],{"class":499},[284,965,19],{"class":496},[284,967,893],{"class":510},[284,969,970],{"class":513},"()",[284,972,739],{"class":290},[30,974,976],{"id":975},"the-declarative-api-enhancing-standard-html-forms","The Declarative API: Enhancing Standard HTML Forms",[11,978,979,980,983],{},"The Declarative API is designed to be a low-friction way to make existing websites agent-friendly. Instead of writing JavaScript, developers can annotate standard ",[229,981,982],{},"\u003Cform>"," elements with special HTML attributes. In current preview materials, the browser then translates these annotated forms into structured WebMCP tools that an agent can discover and use.",[11,985,986],{},"This approach is particularly effective for common web interactions like search forms, login pages, or data submission forms. The browser handles the creation of the JSON schema based on the form's input fields, labels, and attributes.",[11,988,989],{},"Key attributes for the Declarative API include:",[220,991,992,1002,1008,1014,1020],{},[190,993,994,997,998,1001],{},[229,995,996],{},"toolname",": Defines the name of the tool (e.g., ",[229,999,1000],{},"search_products",").",[190,1003,1004,1007],{},[229,1005,1006],{},"tooldescription",": Provides a natural language description for the agent.",[190,1009,1010,1013],{},[229,1011,1012],{},"toolautosubmit",": An optional attribute that allows the form to be submitted automatically by the agent without requiring manual user confirmation.",[190,1015,1016,1019],{},[229,1017,1018],{},"toolparamtitle",": Overrides the default title for a form field in the JSON schema.",[190,1021,1022,1025],{},[229,1023,1024],{},"toolparamdescription",": Overrides the default description for a form field.",[11,1027,1028],{},"Here is an example of an HTML form enhanced with declarative WebMCP attributes.",[275,1030,1034],{"className":1031,"code":1032,"language":1033,"meta":280,"style":280},"language-html shiki shiki-themes catppuccin-latte night-owl","\u003Cform\n  toolname=\"my_tool\"\n  tooldescription=\"A simple declarative tool\"\n  toolautosubmit\n  action=\"/submit\"\n>\n  \u003Clabel for=\"text\">text label\u003C/label>\n  \u003Cinput type=\"text\" name=\"text\" />\n\n  \u003Cselect\n    name=\"select\"\n    required\n    toolparamtitle=\"Possible Options\"\n    toolparamdescription=\"A nice description\"\n  >\n    \u003Coption value=\"Option 1\">This is option 1\u003C/option>\n    \u003Coption value=\"Option 2\">This is option 2\u003C/option>\n  \u003C/select>\n\n  \u003Cbutton type=\"submit\">Submit\u003C/button>\n\u003C/form>\n","html",[229,1035,1036,1046,1063,1077,1082,1096,1101,1133,1164,1168,1175,1189,1194,1208,1222,1228,1260,1289,1299,1304,1334],{"__ignoreMap":280},[284,1037,1038,1042],{"class":286,"line":287},[284,1039,1041],{"class":1040},"s9rnR","\u003C",[284,1043,1045],{"class":1044},"sY2RG","form\n",[284,1047,1048,1052,1055,1057,1060],{"class":286,"line":294},[284,1049,1051],{"class":1050},"swkLt","  toolname",[284,1053,1054],{"class":1040},"=",[284,1056,304],{"class":310},[284,1058,1059],{"class":529},"my_tool",[284,1061,1062],{"class":310},"\"\n",[284,1064,1065,1068,1070,1072,1075],{"class":286,"line":323},[284,1066,1067],{"class":1050},"  tooldescription",[284,1069,1054],{"class":1040},[284,1071,304],{"class":310},[284,1073,1074],{"class":529},"A simple declarative tool",[284,1076,1062],{"class":310},[284,1078,1079],{"class":286,"line":343},[284,1080,1081],{"class":1050},"  toolautosubmit\n",[284,1083,1084,1087,1089,1091,1094],{"class":286,"line":364},[284,1085,1086],{"class":1050},"  action",[284,1088,1054],{"class":1040},[284,1090,304],{"class":310},[284,1092,1093],{"class":529},"/submit",[284,1095,1062],{"class":310},[284,1097,1098],{"class":286,"line":384},[284,1099,1100],{"class":1040},">\n",[284,1102,1103,1106,1109,1112,1114,1116,1118,1120,1123,1126,1129,1131],{"class":286,"line":405},[284,1104,1105],{"class":1040},"  \u003C",[284,1107,1108],{"class":1044},"label",[284,1110,1111],{"class":1050}," for",[284,1113,1054],{"class":1040},[284,1115,304],{"class":310},[284,1117,687],{"class":529},[284,1119,304],{"class":310},[284,1121,1122],{"class":1040},">",[284,1124,1125],{"class":513},"text label",[284,1127,1128],{"class":1040},"\u003C/",[284,1130,1108],{"class":1044},[284,1132,1100],{"class":1040},[284,1134,1135,1137,1140,1142,1144,1146,1148,1150,1153,1155,1157,1159,1161],{"class":286,"line":421},[284,1136,1105],{"class":1040},[284,1138,1139],{"class":1044},"input",[284,1141,598],{"class":1050},[284,1143,1054],{"class":1040},[284,1145,304],{"class":310},[284,1147,687],{"class":529},[284,1149,304],{"class":310},[284,1151,1152],{"class":1050}," name",[284,1154,1054],{"class":1040},[284,1156,304],{"class":310},[284,1158,687],{"class":529},[284,1160,304],{"class":310},[284,1162,1163],{"class":1040}," />\n",[284,1165,1166],{"class":286,"line":618},[284,1167,946],{"emptyLinePlaceholder":945},[284,1169,1170,1172],{"class":286,"line":624},[284,1171,1105],{"class":1040},[284,1173,1174],{"class":1044},"select\n",[284,1176,1177,1180,1182,1184,1187],{"class":286,"line":655},[284,1178,1179],{"class":1050},"    name",[284,1181,1054],{"class":1040},[284,1183,304],{"class":310},[284,1185,1186],{"class":529},"select",[284,1188,1062],{"class":310},[284,1190,1191],{"class":286,"line":662},[284,1192,1193],{"class":1050},"    required\n",[284,1195,1196,1199,1201,1203,1206],{"class":286,"line":727},[284,1197,1198],{"class":1050},"    toolparamtitle",[284,1200,1054],{"class":1040},[284,1202,304],{"class":310},[284,1204,1205],{"class":529},"Possible Options",[284,1207,1062],{"class":310},[284,1209,1210,1213,1215,1217,1220],{"class":286,"line":732},[284,1211,1212],{"class":1050},"    toolparamdescription",[284,1214,1054],{"class":1040},[284,1216,304],{"class":310},[284,1218,1219],{"class":529},"A nice description",[284,1221,1062],{"class":310},[284,1223,1225],{"class":286,"line":1224},15,[284,1226,1227],{"class":1040},"  >\n",[284,1229,1231,1234,1237,1240,1242,1244,1247,1249,1251,1254,1256,1258],{"class":286,"line":1230},16,[284,1232,1233],{"class":1040},"    \u003C",[284,1235,1236],{"class":1044},"option",[284,1238,1239],{"class":1050}," value",[284,1241,1054],{"class":1040},[284,1243,304],{"class":310},[284,1245,1246],{"class":529},"Option 1",[284,1248,304],{"class":310},[284,1250,1122],{"class":1040},[284,1252,1253],{"class":513},"This is option 1",[284,1255,1128],{"class":1040},[284,1257,1236],{"class":1044},[284,1259,1100],{"class":1040},[284,1261,1263,1265,1267,1269,1271,1273,1276,1278,1280,1283,1285,1287],{"class":286,"line":1262},17,[284,1264,1233],{"class":1040},[284,1266,1236],{"class":1044},[284,1268,1239],{"class":1050},[284,1270,1054],{"class":1040},[284,1272,304],{"class":310},[284,1274,1275],{"class":529},"Option 2",[284,1277,304],{"class":310},[284,1279,1122],{"class":1040},[284,1281,1282],{"class":513},"This is option 2",[284,1284,1128],{"class":1040},[284,1286,1236],{"class":1044},[284,1288,1100],{"class":1040},[284,1290,1292,1295,1297],{"class":286,"line":1291},18,[284,1293,1294],{"class":1040},"  \u003C/",[284,1296,1186],{"class":1044},[284,1298,1100],{"class":1040},[284,1300,1302],{"class":286,"line":1301},19,[284,1303,946],{"emptyLinePlaceholder":945},[284,1305,1307,1309,1312,1314,1316,1318,1321,1323,1325,1328,1330,1332],{"class":286,"line":1306},20,[284,1308,1105],{"class":1040},[284,1310,1311],{"class":1044},"button",[284,1313,598],{"class":1050},[284,1315,1054],{"class":1040},[284,1317,304],{"class":310},[284,1319,1320],{"class":529},"submit",[284,1322,304],{"class":310},[284,1324,1122],{"class":1040},[284,1326,1327],{"class":513},"Submit",[284,1329,1128],{"class":1040},[284,1331,1311],{"class":1044},[284,1333,1100],{"class":1040},[284,1335,1337,1339,1342],{"class":286,"line":1336},21,[284,1338,1128],{"class":1040},[284,1340,1341],{"class":1044},"form",[284,1343,1100],{"class":1040},[11,1345,1346],{},"In current preview examples, the browser generates a tool definition like the following from this HTML and makes it available to an AI agent.",[275,1348,1350],{"className":277,"code":1349,"language":279,"meta":280,"style":280},"[\n  {\n    \"name\": \"my_tool\",\n    \"description\": \"A simple declarative tool\",\n    \"inputSchema\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"text\": { \"type\": \"string\", \"description\": \"text label\" },\n        \"select\": {\n          \"type\": \"string\",\n          \"enum\": [\"Option 1\", \"Option 2\"],\n          \"title\": \"Possible Options\",\n          \"description\": \"A nice description\"\n        }\n      },\n      \"required\": [\"select\"]\n    }\n  }\n]\n",[229,1351,1352,1357,1362,1382,1401,1414,1434,1447,1492,1504,1523,1553,1572,1588,1593,1598,1620,1625,1630],{"__ignoreMap":280},[284,1353,1354],{"class":286,"line":287},[284,1355,1356],{"class":290},"[\n",[284,1358,1359],{"class":286,"line":294},[284,1360,1361],{"class":290},"  {\n",[284,1363,1364,1367,1370,1372,1374,1376,1378,1380],{"class":286,"line":323},[284,1365,1366],{"class":297},"    \"",[284,1368,1369],{"class":301},"name",[284,1371,304],{"class":297},[284,1373,307],{"class":290},[284,1375,311],{"class":310},[284,1377,1059],{"class":314},[284,1379,304],{"class":310},[284,1381,320],{"class":290},[284,1383,1384,1386,1389,1391,1393,1395,1397,1399],{"class":286,"line":343},[284,1385,1366],{"class":297},[284,1387,1388],{"class":301},"description",[284,1390,304],{"class":297},[284,1392,307],{"class":290},[284,1394,311],{"class":310},[284,1396,1074],{"class":314},[284,1398,304],{"class":310},[284,1400,320],{"class":290},[284,1402,1403,1405,1408,1410,1412],{"class":286,"line":364},[284,1404,1366],{"class":297},[284,1406,1407],{"class":301},"inputSchema",[284,1409,304],{"class":297},[284,1411,307],{"class":290},[284,1413,560],{"class":290},[284,1415,1416,1419,1422,1424,1426,1428,1430,1432],{"class":286,"line":384},[284,1417,1418],{"class":297},"      \"",[284,1420,1421],{"class":301},"type",[284,1423,304],{"class":297},[284,1425,307],{"class":290},[284,1427,311],{"class":310},[284,1429,572],{"class":314},[284,1431,304],{"class":310},[284,1433,320],{"class":290},[284,1435,1436,1438,1441,1443,1445],{"class":286,"line":405},[284,1437,1418],{"class":297},[284,1439,1440],{"class":301},"properties",[284,1442,304],{"class":297},[284,1444,307],{"class":290},[284,1446,560],{"class":290},[284,1448,1449,1452,1454,1456,1458,1460,1462,1464,1466,1468,1470,1472,1474,1476,1478,1480,1482,1484,1486,1488,1490],{"class":286,"line":421},[284,1450,1451],{"class":297},"        \"",[284,1453,687],{"class":301},[284,1455,304],{"class":297},[284,1457,307],{"class":290},[284,1459,595],{"class":290},[284,1461,311],{"class":297},[284,1463,1421],{"class":301},[284,1465,304],{"class":297},[284,1467,307],{"class":290},[284,1469,311],{"class":310},[284,1471,605],{"class":314},[284,1473,304],{"class":310},[284,1475,692],{"class":290},[284,1477,311],{"class":297},[284,1479,1388],{"class":301},[284,1481,304],{"class":297},[284,1483,307],{"class":290},[284,1485,311],{"class":310},[284,1487,1125],{"class":314},[284,1489,304],{"class":310},[284,1491,610],{"class":290},[284,1493,1494,1496,1498,1500,1502],{"class":286,"line":618},[284,1495,1451],{"class":297},[284,1497,1186],{"class":301},[284,1499,304],{"class":297},[284,1501,307],{"class":290},[284,1503,560],{"class":290},[284,1505,1506,1509,1511,1513,1515,1517,1519,1521],{"class":286,"line":624},[284,1507,1508],{"class":297},"          \"",[284,1510,1421],{"class":301},[284,1512,304],{"class":297},[284,1514,307],{"class":290},[284,1516,311],{"class":310},[284,1518,605],{"class":314},[284,1520,304],{"class":310},[284,1522,320],{"class":290},[284,1524,1525,1527,1530,1532,1534,1536,1538,1540,1542,1544,1546,1548,1550],{"class":286,"line":655},[284,1526,1508],{"class":297},[284,1528,1529],{"class":301},"enum",[284,1531,304],{"class":297},[284,1533,307],{"class":290},[284,1535,676],{"class":290},[284,1537,304],{"class":310},[284,1539,1246],{"class":314},[284,1541,304],{"class":310},[284,1543,692],{"class":290},[284,1545,311],{"class":310},[284,1547,1275],{"class":314},[284,1549,304],{"class":310},[284,1551,1552],{"class":290},"],\n",[284,1554,1555,1557,1560,1562,1564,1566,1568,1570],{"class":286,"line":662},[284,1556,1508],{"class":297},[284,1558,1559],{"class":301},"title",[284,1561,304],{"class":297},[284,1563,307],{"class":290},[284,1565,311],{"class":310},[284,1567,1205],{"class":314},[284,1569,304],{"class":310},[284,1571,320],{"class":290},[284,1573,1574,1576,1578,1580,1582,1584,1586],{"class":286,"line":727},[284,1575,1508],{"class":297},[284,1577,1388],{"class":301},[284,1579,304],{"class":297},[284,1581,307],{"class":290},[284,1583,311],{"class":310},[284,1585,1219],{"class":314},[284,1587,1062],{"class":310},[284,1589,1590],{"class":286,"line":732},[284,1591,1592],{"class":290},"        }\n",[284,1594,1595],{"class":286,"line":1224},[284,1596,1597],{"class":290},"      },\n",[284,1599,1600,1602,1605,1607,1609,1611,1613,1615,1617],{"class":286,"line":1230},[284,1601,1418],{"class":297},[284,1603,1604],{"class":301},"required",[284,1606,304],{"class":297},[284,1608,307],{"class":290},[284,1610,676],{"class":290},[284,1612,304],{"class":310},[284,1614,1186],{"class":314},[284,1616,304],{"class":310},[284,1618,1619],{"class":290},"]\n",[284,1621,1622],{"class":286,"line":1262},[284,1623,1624],{"class":290},"    }\n",[284,1626,1627],{"class":286,"line":1291},[284,1628,1629],{"class":290},"  }\n",[284,1631,1632],{"class":286,"line":1301},[284,1633,1619],{"class":290},[47,1635,1637],{"id":1636},"handling-agent-initiated-submissions","Handling Agent-Initiated Submissions",[11,1639,1640,1641,1644,1645,1648,1649,1652],{},"In current preview documentation and examples, developer control over agent-initiated actions is shown through an extended ",[229,1642,1643],{},"SubmitEvent"," flow. In that model, an ",[229,1646,1647],{},"agentInvoked"," flag indicates that the form submission came from an agent, and ",[229,1650,1651],{},"respondWith(Promise\u003Cany>)"," can be used to return a custom result instead of performing the standard form submission.",[275,1654,1656],{"className":483,"code":1655,"language":485,"meta":280,"style":280},"document.querySelector(\"form\").addEventListener(\"submit\", (e) => {\n  if (e.agentInvoked) {\n    e.preventDefault();\n    const formData = new FormData(e.target);\n    const query = formData.get(\"query\");\n\n    // Custom logic to handle the search\n    const searchResultPromise = myCustomSearchFunction(query);\n\n    e.respondWith(searchResultPromise);\n  }\n});\n",[229,1657,1658,1704,1723,1737,1771,1800,1804,1809,1829,1833,1851,1855],{"__ignoreMap":280},[284,1659,1660,1663,1665,1668,1670,1672,1674,1676,1678,1680,1683,1685,1687,1689,1691,1693,1695,1698,1700,1702],{"class":286,"line":287},[284,1661,1662],{"class":492},"document",[284,1664,19],{"class":496},[284,1666,1667],{"class":510},"querySelector",[284,1669,514],{"class":513},[284,1671,304],{"class":310},[284,1673,1341],{"class":529},[284,1675,304],{"class":310},[284,1677,646],{"class":513},[284,1679,19],{"class":496},[284,1681,1682],{"class":510},"addEventListener",[284,1684,514],{"class":513},[284,1686,304],{"class":310},[284,1688,1320],{"class":529},[284,1690,304],{"class":310},[284,1692,692],{"class":290},[284,1694,633],{"class":632},[284,1696,1697],{"class":639},"e",[284,1699,646],{"class":632},[284,1701,650],{"class":649},[284,1703,560],{"class":290},[284,1705,1706,1709,1711,1713,1715,1718,1721],{"class":286,"line":294},[284,1707,1708],{"class":649},"  if",[284,1710,633],{"class":513},[284,1712,1697],{"class":492},[284,1714,19],{"class":496},[284,1716,1647],{"class":1717},"sL4Ga",[284,1719,1720],{"class":513},") ",[284,1722,291],{"class":290},[284,1724,1725,1728,1730,1733,1735],{"class":286,"line":323},[284,1726,1727],{"class":492},"    e",[284,1729,19],{"class":496},[284,1731,1732],{"class":510},"preventDefault",[284,1734,970],{"class":513},[284,1736,739],{"class":290},[284,1738,1739,1742,1746,1750,1754,1757,1759,1761,1763,1767,1769],{"class":286,"line":343},[284,1740,1741],{"class":649},"    const",[284,1743,1745],{"class":1744},"scsc5"," formData",[284,1747,1749],{"class":1748},"s-_ek"," =",[284,1751,1753],{"class":1752},"szhwX"," new",[284,1755,1756],{"class":510}," FormData",[284,1758,514],{"class":513},[284,1760,1697],{"class":492},[284,1762,19],{"class":496},[284,1764,1766],{"class":1765},"s8apv","target",[284,1768,646],{"class":513},[284,1770,739],{"class":290},[284,1772,1773,1775,1778,1780,1782,1784,1787,1789,1791,1794,1796,1798],{"class":286,"line":364},[284,1774,1741],{"class":649},[284,1776,1777],{"class":1744}," query",[284,1779,1749],{"class":1748},[284,1781,1745],{"class":492},[284,1783,19],{"class":496},[284,1785,1786],{"class":510},"get",[284,1788,514],{"class":513},[284,1790,304],{"class":310},[284,1792,1793],{"class":529},"query",[284,1795,304],{"class":310},[284,1797,646],{"class":513},[284,1799,739],{"class":290},[284,1801,1802],{"class":286,"line":384},[284,1803,946],{"emptyLinePlaceholder":945},[284,1805,1806],{"class":286,"line":405},[284,1807,1808],{"class":658},"    // Custom logic to handle the search\n",[284,1810,1811,1813,1816,1818,1821,1823,1825,1827],{"class":286,"line":421},[284,1812,1741],{"class":649},[284,1814,1815],{"class":1744}," searchResultPromise",[284,1817,1749],{"class":1748},[284,1819,1820],{"class":510}," myCustomSearchFunction",[284,1822,514],{"class":513},[284,1824,1793],{"class":710},[284,1826,646],{"class":513},[284,1828,739],{"class":290},[284,1830,1831],{"class":286,"line":618},[284,1832,946],{"emptyLinePlaceholder":945},[284,1834,1835,1837,1839,1842,1844,1847,1849],{"class":286,"line":624},[284,1836,1727],{"class":492},[284,1838,19],{"class":496},[284,1840,1841],{"class":510},"respondWith",[284,1843,514],{"class":513},[284,1845,1846],{"class":710},"searchResultPromise",[284,1848,646],{"class":513},[284,1850,739],{"class":290},[284,1852,1853],{"class":286,"line":655},[284,1854,1629],{"class":290},[284,1856,1857,1859,1861],{"class":286,"line":662},[284,1858,713],{"class":290},[284,1860,646],{"class":513},[284,1862,739],{"class":290},[11,1864,1865],{},"Current preview materials also describe visual feedback and events around agent interaction, including CSS states and page events that developers can use to react to agent-filled forms.",[30,1867,1869],{"id":1868},"webmcp-tool-design-checklist","WebMCP Tool Design Checklist",[11,1871,1872],{},"The exact API surface may evolve while WebMCP remains experimental, but the design principles behind good browser-exposed tools are already clear. If you want an AI agent to use your website reliably, optimize for clarity, predictable state changes, and easy recovery when something goes wrong.",[47,1874,1876],{"id":1875},"what-good-webmcp-tools-should-do","What good WebMCP tools should do",[63,1878,1879,1892],{},[66,1880,1881],{},[69,1882,1883,1886,1889],{},[72,1884,1885],{},"Area",[72,1887,1888],{},"What to do",[72,1890,1891],{},"Why it matters",[85,1893,1894,1912,1925,1938,1951,1964,1977],{},[69,1895,1896,1901,1909],{},[90,1897,1898],{},[55,1899,1900],{},"Name clearly",[90,1902,1903,1904,245,1906],{},"Describe the real outcome - ",[229,1905,231],{},[229,1907,1908],{},"addSuggestedEdit",[90,1910,1911],{},"Agent picks the right tool first try",[69,1913,1914,1919,1922],{},[90,1915,1916],{},[55,1917,1918],{},"Describe when to use it",[90,1920,1921],{},"Explain purpose in plain language",[90,1923,1924],{},"Reduces wrong tool selection",[69,1926,1927,1932,1935],{},[90,1928,1929],{},[55,1930,1931],{},"Accept natural inputs",[90,1933,1934],{},"Use dates, times, and labels as users would enter them",[90,1936,1937],{},"Less reasoning overhead for the model",[69,1939,1940,1945,1948],{},[90,1941,1942],{},[55,1943,1944],{},"Validate in code",[90,1946,1947],{},"Validate arguments even with a schema defined",[90,1949,1950],{},"Prevents silent failures from bad inputs",[69,1952,1953,1958,1961],{},[90,1954,1955],{},[55,1956,1957],{},"Return useful errors",[90,1959,1960],{},"State what was invalid and how to fix it",[90,1962,1963],{},"Makes retries more likely to succeed",[69,1965,1966,1971,1974],{},[90,1967,1968],{},[55,1969,1970],{},"Update the UI before resolving",[90,1972,1973],{},"Only resolve after visible state matches the result",[90,1975,1976],{},"Keeps agent and user in sync",[69,1978,1979,1984,1987],{},[90,1980,1981],{},[55,1982,1983],{},"Keep tools atomic",[90,1985,1986],{},"One clear action per tool, no overlapping variants",[90,1988,1989],{},"Easier to compose",[47,1991,1993],{"id":1992},"three-practical-rules-for-developers","Three practical rules for developers",[187,1995,1996,2002,2008],{},[190,1997,1998,2001],{},[55,1999,2000],{},"Separate page logic from presentation."," WebMCP works best when your core business logic already exists outside click handlers and UI-only code.",[190,2003,2004,2007],{},[55,2005,2006],{},"Expose only the actions that make sense in the current page state."," Tools should match what the user can actually do on the page right now.",[190,2009,2010,2013],{},[55,2011,2012],{},"Design for user-visible collaboration, not hidden automation."," WebMCP is strongest when the agent helps inside a live webpage that the user can still inspect and control.",[11,2015,2016],{},"In other words, the best WebMCP implementations do not just expose functionality. They expose it in a way that is understandable to both the model and the human watching the interaction.",[30,2018,2020],{"id":2019},"practical-use-cases-of-webmcp","Practical Use Cases of WebMCP",[11,2022,2023,2024,2027],{},"The clearest use case for WebMCP is ",[55,2025,2026],{},"user-visible assistance inside a live webpage",". That is also how the current Chrome early-preview materials position it: as a way for websites to expose structured browser-side capabilities to an agent without forcing the agent to reverse-engineer the interface.",[47,2029,2031],{"id":2030},"a-concrete-example-flight-search-on-a-live-webpage","A concrete example: flight search on a live webpage",[11,2033,2034,2035,2037],{},"The most grounded public example today is the Chrome Labs flight-search demo. A page exposes a ",[229,2036,231],{}," capability, and the agent passes structured inputs instead of clicking through form fields one by one.",[275,2039,2041],{"className":483,"code":2040,"language":485,"meta":280,"style":280},"searchFlights({\n  origin: \"LON\",\n  destination: \"NYC\",\n  tripType: \"round-trip\",\n  outboundDate: \"2026-06-10\",\n  inboundDate: \"2026-06-17\",\n  passengers: 2,\n});\n",[229,2042,2043,2051,2066,2081,2096,2111,2126,2138],{"__ignoreMap":280},[284,2044,2045,2047,2049],{"class":286,"line":287},[284,2046,231],{"class":510},[284,2048,514],{"class":513},[284,2050,291],{"class":290},[284,2052,2053,2056,2058,2060,2062,2064],{"class":286,"line":294},[284,2054,2055],{"class":513},"  origin",[284,2057,307],{"class":524},[284,2059,311],{"class":310},[284,2061,315],{"class":529},[284,2063,304],{"class":310},[284,2065,320],{"class":290},[284,2067,2068,2071,2073,2075,2077,2079],{"class":286,"line":323},[284,2069,2070],{"class":513},"  destination",[284,2072,307],{"class":524},[284,2074,311],{"class":310},[284,2076,336],{"class":529},[284,2078,304],{"class":310},[284,2080,320],{"class":290},[284,2082,2083,2086,2088,2090,2092,2094],{"class":286,"line":343},[284,2084,2085],{"class":513},"  tripType",[284,2087,307],{"class":524},[284,2089,311],{"class":310},[284,2091,357],{"class":529},[284,2093,304],{"class":310},[284,2095,320],{"class":290},[284,2097,2098,2101,2103,2105,2107,2109],{"class":286,"line":364},[284,2099,2100],{"class":513},"  outboundDate",[284,2102,307],{"class":524},[284,2104,311],{"class":310},[284,2106,377],{"class":529},[284,2108,304],{"class":310},[284,2110,320],{"class":290},[284,2112,2113,2116,2118,2120,2122,2124],{"class":286,"line":384},[284,2114,2115],{"class":513},"  inboundDate",[284,2117,307],{"class":524},[284,2119,311],{"class":310},[284,2121,398],{"class":529},[284,2123,304],{"class":310},[284,2125,320],{"class":290},[284,2127,2128,2131,2133,2136],{"class":286,"line":405},[284,2129,2130],{"class":513},"  passengers",[284,2132,307],{"class":524},[284,2134,2135],{"class":417}," 2",[284,2137,320],{"class":290},[284,2139,2140,2142,2144],{"class":286,"line":421},[284,2141,713],{"class":290},[284,2143,646],{"class":513},[284,2145,739],{"class":290},[11,2147,2148],{},"That is a good illustration of where WebMCP fits best: the user stays on the page, the UI updates visibly, and the agent works through a structured contract instead of brittle DOM guessing.",[47,2150,2152],{"id":2151},"other-strong-fits-for-webmcp","Other strong fits for WebMCP",[220,2154,2155,2161,2167],{},[190,2156,2157,2160],{},[55,2158,2159],{},"Design and editing tools:"," expose actions such as filtering templates, applying edits, or inserting structured content while the user watches the page update.",[190,2162,2163,2166],{},[55,2164,2165],{},"Commerce and search experiences:"," expose structured product retrieval or filtering tools so an agent can narrow results without scraping listings.",[190,2168,2169,2172],{},[55,2170,2171],{},"Developer and power-user apps:"," expose page-local actions such as log inspection, search, or suggested edits in tools that are hard to discover from the UI alone.",[11,2174,2175,2176],{},"The key pattern across all of these is the same: ",[55,2177,2178],{},"WebMCP is most useful when the website already has meaningful client-side actions and wants to make them easier for an agent to call safely and predictably.",[35,2180],{":width":37,"alt":2181,"loading":39,"provider":40,"src":2182,"format":42},"Diagram showing a WebMCP cross-application workflow between a design tool and email service","/blog/what-is-webmcp-the-practical-guide-to-the-web-model-context-protocol/4.svg",[30,2184,2186],{"id":2185},"limitations-and-the-road-ahead","Limitations and The Road Ahead",[11,2188,2189],{},"WebMCP is a proposal for a new web standard, and as an early preview, it comes with a set of limitations and open questions that are actively being explored. Understanding these constraints is important for developers considering its adoption.",[220,2191,2192,2198,2209,2215],{},[190,2193,2194,2197],{},[55,2195,2196],{},"Browsing Context is Required:"," WebMCP tools are executed in JavaScript within a webpage. This means a browser tab (or a webview) must be open and active for an agent to interact with the site. It does not currently support \"headless\" scenarios where an agent could call tools without a visible browser UI.",[190,2199,2200,2203,2204,2208],{},[55,2201,2202],{},"Developer Responsibility for UI Synchronization:"," The protocol facilitates the ",[2205,2206,2207],"em",{},"execution"," of actions, but it is up to the web developer to ensure the user interface accurately reflects any state changes made by an agent. For example, if an agent adds an item to a shopping cart via a tool, the site's JavaScript must update the cart icon and item list accordingly.",[190,2210,2211,2214],{},[55,2212,2213],{},"Potential for Refactoring:"," On websites with highly complex or tightly-coupled user interfaces, simply adding tool definitions may not be enough. Developers may need to refactor existing JavaScript to separate business logic from its presentation, making it easier to expose clean, reusable functions as tools.",[190,2216,2217,2220],{},[55,2218,2219],{},"Tool Discoverability:"," There is no built-in, centralized mechanism for an AI agent to discover which websites support WebMCP without first navigating to them. Search engines or dedicated directories may eventually fill this gap, but for now, tool discovery is limited to the context of a visited page.",[11,2222,2223],{},"As of 2026, WebMCP should be treated as an experimental Chrome early-preview capability rather than a broadly supported browser standard. The longer-term goal is wider standardization, but cross-browser support is still part of the future roadmap.",[35,2225],{":width":37,"alt":2226,"loading":39,"provider":40,"src":2227,"format":42},"Comparison diagram of WebMCP client-side approach versus server-side MCP and OpenAPI integrations","/blog/what-is-webmcp-the-practical-guide-to-the-web-model-context-protocol/5.svg",[11,2229,2230],{},"WebMCP is not intended to replace backend integrations. Instead, it complements them by providing a solution specifically designed for the interactive, UI-driven nature of the web. A business might offer a server-side MCP API for autonomous booking while also implementing a client-side WebMCP layer to assist users who are actively browsing and refining their travel plans on the website.",[30,2232,2234],{"id":2233},"getting-started-trying-webmcp-today","Getting Started: Trying WebMCP Today",[11,2236,2237],{},"If you want to experiment with WebMCP now, approach it as an early preview workflow rather than a stable production feature. At the time of writing, testing is centered on recent Chrome 146+ builds with the relevant flag enabled, plus Chrome's debugging tooling and demo pages.",[11,2239,2240],{},"To begin, you will need two prerequisites:",[220,2242,2243,2249],{},[190,2244,2245,2248],{},[55,2246,2247],{},"Chrome Version:"," Use a recent Chrome 146+ build or the current Chrome early-preview build that supports WebMCP testing.",[190,2250,2251,2254],{},[55,2252,2253],{},"Feature Flag:"," The \"WebMCP for testing\" flag must be enabled.",[47,2256,2258],{"id":2257},"enabling-the-webmcp-flag","Enabling the WebMCP Flag",[11,2260,2261],{},"First, you need to activate the feature within Chrome. This process exposes the WebMCP APIs to websites.",[187,2263,2264,2271,2277],{},[190,2265,2266,2267,2270],{},"Open a new tab in Chrome and navigate to the flags page by typing ",[229,2268,2269],{},"chrome://flags/#enable-webmcp-testing"," into the address bar.",[190,2272,2273,2274,19],{},"Locate the \"WebMCP for testing\" flag and change its setting from \"Default\" to ",[55,2275,2276],{},"Enabled",[190,2278,2279,2280,2283],{},"A prompt will appear at the bottom of the screen to relaunch the browser. Click ",[55,2281,2282],{},"Relaunch"," to apply the changes.",[35,2285],{":width":37,"alt":2286,"loading":39,"provider":40,"src":2287},"Chrome flags page showing the WebMCP for testing flag enabled at chrome://flags/#enable-webmcp-testing","/blog/what-is-webmcp-the-practical-guide-to-the-web-model-context-protocol/chrome-flag-enable.png",[47,2289,2291],{"id":2290},"using-the-model-context-tool-inspector-extension","Using the Model Context Tool Inspector Extension",[11,2293,2294,2295,2298],{},"To help developers debug and test their WebMCP implementations, the Chrome team has released a browser extension. The ",[55,2296,2297],{},"Model Context Tool Inspector"," lets you see which tools are registered on a page, execute them manually, and even test them with a real AI agent.",[11,2300,2301],{},"The extension offers three main capabilities for developers:",[220,2303,2304,2313,2322],{},[190,2305,2306,2309,2310,2312],{},[55,2307,2308],{},"List Registered Tools:"," The extension automatically detects and lists all tools registered on the active tab, whether through the Imperative API (",[229,2311,473],{},") or the Declarative API (HTML form annotations). For each tool, it displays its name, description, and the complete JSON input schema, which is useful for debugging.",[190,2314,2315,2318,2319,2321],{},[55,2316,2317],{},"Call Tools Manually:"," This feature allows you to bypass the non-deterministic nature of an AI model for initial testing. You can select a tool from the list, fill in its parameters using a JSON editor directly in the extension's UI, and execute it. The extension shows the returned result or any error messages, helping to quickly identify schema mismatches or runtime bugs in your ",[229,2320,479],{}," function.",[190,2323,2324,2327],{},[55,2325,2326],{},"Test with an Agent:"," The extension includes support for the Gemini API. By providing your own API key, you can enter natural language prompts and observe if the agent correctly identifies and calls the appropriate tool with the right parameters. This is a major help for optimizing tool descriptions and schemas for better model comprehension.",[47,2329,2331],{"id":2330},"hands-on-with-the-live-demo","Hands-On with the Live Demo",[11,2333,2334,2335,2337],{},"The best way to see WebMCP in action is with a hosted travel demo that exposes a ",[229,2336,231],{}," tool triggerable through the inspector extension.",[2339,2340,2342,2343,2345],"h4",{"id":2341},"manually-executing-the-searchflights-tool","Manually Executing the ",[229,2344,231],{}," Tool",[11,2347,2348],{},"This exercise demonstrates how to call a tool directly with structured data, without needing an AI model.",[187,2350,2351,2360,2366,2369],{},[190,2352,2353,2354,19],{},"With the extension installed and the flag enabled, navigate to the ",[15,2355,2359],{"href":2356,"rel":2357},"https://googlechromelabs.github.io/webmcp-tools/demos/react-flightsearch/",[2358],"nofollow","React Flight Search demo",[190,2361,2362,2363,2365],{},"Click the Model Context Tool Inspector extension icon in your toolbar to open its panel. You should see the ",[229,2364,231],{}," tool listed.",[190,2367,2368],{},"In the panel, ensure the \"Tool\" dropdown is set to \"searchFlights\".",[190,2370,2371],{},"In the \"Input Arguments\" field, paste the following JSON object:",[275,2373,2374],{"className":277,"code":278,"language":279,"meta":280,"style":280},[229,2375,2376,2380,2398,2416,2434,2452,2470,2482],{"__ignoreMap":280},[284,2377,2378],{"class":286,"line":287},[284,2379,291],{"class":290},[284,2381,2382,2384,2386,2388,2390,2392,2394,2396],{"class":286,"line":294},[284,2383,298],{"class":297},[284,2385,244],{"class":301},[284,2387,304],{"class":297},[284,2389,307],{"class":290},[284,2391,311],{"class":310},[284,2393,315],{"class":314},[284,2395,304],{"class":310},[284,2397,320],{"class":290},[284,2399,2400,2402,2404,2406,2408,2410,2412,2414],{"class":286,"line":323},[284,2401,298],{"class":297},[284,2403,248],{"class":301},[284,2405,304],{"class":297},[284,2407,307],{"class":290},[284,2409,311],{"class":310},[284,2411,336],{"class":314},[284,2413,304],{"class":310},[284,2415,320],{"class":290},[284,2417,2418,2420,2422,2424,2426,2428,2430,2432],{"class":286,"line":343},[284,2419,298],{"class":297},[284,2421,348],{"class":301},[284,2423,304],{"class":297},[284,2425,307],{"class":290},[284,2427,311],{"class":310},[284,2429,357],{"class":314},[284,2431,304],{"class":310},[284,2433,320],{"class":290},[284,2435,2436,2438,2440,2442,2444,2446,2448,2450],{"class":286,"line":364},[284,2437,298],{"class":297},[284,2439,252],{"class":301},[284,2441,304],{"class":297},[284,2443,307],{"class":290},[284,2445,311],{"class":310},[284,2447,377],{"class":314},[284,2449,304],{"class":310},[284,2451,320],{"class":290},[284,2453,2454,2456,2458,2460,2462,2464,2466,2468],{"class":286,"line":384},[284,2455,298],{"class":297},[284,2457,389],{"class":301},[284,2459,304],{"class":297},[284,2461,307],{"class":290},[284,2463,311],{"class":310},[284,2465,398],{"class":314},[284,2467,304],{"class":310},[284,2469,320],{"class":290},[284,2471,2472,2474,2476,2478,2480],{"class":286,"line":405},[284,2473,298],{"class":297},[284,2475,410],{"class":301},[284,2477,304],{"class":297},[284,2479,307],{"class":290},[284,2481,418],{"class":417},[284,2483,2484],{"class":286,"line":421},[284,2485,424],{"class":290},[187,2487,2488],{"start":364},[190,2489,2490,2491,2494],{},"Click the ",[55,2492,2493],{},"Execute Tool"," button. The page will update to show the flight search results.",[2339,2496,2498],{"id":2497},"invoking-the-tool-with-natural-language","Invoking the Tool with Natural Language",[11,2500,2501],{},"This next step simulates a real user interaction by translating a natural language request into a tool call. Note that this requires a Gemini API key.",[187,2503,2504,2507,2514,2520],{},[190,2505,2506],{},"Open the extension on the same demo page.",[190,2508,2509,2510,2513],{},"Click ",[55,2511,2512],{},"Set a Gemini API key"," and enter your key.",[190,2515,2516,2517],{},"In the \"User Prompt\" field, type: ",[229,2518,2519],{},"Search flights from LON to NYC leaving next Monday and returning after a week for 2 passengers.",[190,2521,2509,2522,2525,2526,2528],{},[55,2523,2524],{},"Send",". The extension will send your prompt and the tool's definition to the Gemini model. The model will determine that the ",[229,2527,231],{}," tool should be called and generate the necessary JSON arguments. The extension will then execute the tool with these arguments, and the page will update with the results.",[11,2530,2531,2532,2537,2538,2542,2543,19],{},"The demos and source code are open source and available for review on the ",[15,2533,2536],{"href":2534,"rel":2535},"https://github.com/GoogleChromeLabs/webmcp-tools",[2358],"Google Chrome Labs GitHub repository",". If you want more context on server-side alternatives, see ",[15,2539,2541],{"href":2540},"/blog/the-top-5-best-mcp-servers-for-ai-agent-browser-automation","Top 5 Best MCP Servers for AI Agent Browser Automation",". If you are comparing browser-native structured tooling with existing automation approaches, see ",[15,2544,2546],{"href":2545},"/blog/agent-browser-vs-puppeteer-and-playwright","Agent Browser vs. Puppeteer & Playwright",[30,2548,2550],{"id":2549},"conclusion","Conclusion",[11,2552,2553],{},"The conventional design of the web, centered on human visual interaction, creates inherent difficulties for automated AI agents that must rely on brittle screen-scraping techniques. WebMCP addresses this gap by establishing a direct and structured communication layer between web applications and the agents that interact with them. It provides a clear contract, replacing guesswork with a defined set of tools that a website can offer.",[11,2555,2556],{},"Through its dual-API approach-a flexible Imperative API for dynamic applications and a straightforward Declarative API for standard HTML forms-WebMCP offers a path for developers to make their sites agent-accessible with a suitable level of effort. This does more than just improve the speed and reliability of automation. The protocol's design supports a future where human-in-the-loop workflows become common, allowing users to delegate complex or repetitive tasks to an AI agent while remaining in full control within a familiar web interface.",[11,2558,2559],{},"As a proposed standard in an early preview stage, WebMCP's direction will be shaped by the web development community. Experimenting with the APIs and providing feedback on use cases, API design, and tooling is an important part of maturing this technology. By giving websites a native language to express their capabilities to machines, WebMCP represents a major step toward a more programmable, accessible, and intelligent web.",[2561,2562,2563],"style",{},"html pre.shiki code .scGhl, html code.shiki .scGhl{--shiki-default:#7C7F93;--shiki-dark:#D6DEEB}html pre.shiki code .srFR9, html code.shiki .srFR9{--shiki-default:#7C7F93;--shiki-dark:#7FDBCA}html pre.shiki code .s30W1, html code.shiki .s30W1{--shiki-default:#1E66F5;--shiki-dark:#7FDBCA}html pre.shiki code .sbuKk, html code.shiki .sbuKk{--shiki-default:#40A02B;--shiki-dark:#D9F5DD}html pre.shiki code .sCC8C, html code.shiki .sCC8C{--shiki-default:#40A02B;--shiki-dark:#C789D6}html pre.shiki code .sZ_Zo, html code.shiki .sZ_Zo{--shiki-default:#FE640B;--shiki-dark:#F78C6C}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 .sP4PM, html code.shiki .sP4PM{--shiki-default:#4C4F69;--shiki-default-font-style:inherit;--shiki-dark:#7FDBCA;--shiki-dark-font-style:italic}html pre.shiki code .s5FwJ, html code.shiki .s5FwJ{--shiki-default:#179299;--shiki-default-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic}html pre.shiki code .sHY1S, html code.shiki .sHY1S{--shiki-default:#4C4F69;--shiki-default-font-style:inherit;--shiki-dark:#FAF39F;--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 .s2kId, html code.shiki .s2kId{--shiki-default:#4C4F69;--shiki-dark:#D6DEEB}html pre.shiki code .sVS64, html code.shiki .sVS64{--shiki-default:#179299;--shiki-dark:#D6DEEB}html pre.shiki code .sfrMT, html code.shiki .sfrMT{--shiki-default:#40A02B;--shiki-dark:#ECC48D}html pre.shiki code .sMtgK, html code.shiki .sMtgK{--shiki-default:#7C7F93;--shiki-dark:#D9F5DD}html pre.shiki code .sIhCM, html code.shiki .sIhCM{--shiki-default:#E64553;--shiki-default-font-style:italic;--shiki-dark:#D7DBE0;--shiki-dark-font-style:inherit}html pre.shiki code .s76yb, html code.shiki .s76yb{--shiki-default:#8839EF;--shiki-dark:#C792EA}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 .srhcd, html code.shiki .srhcd{--shiki-default:#8839EF;--shiki-default-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic}html pre.shiki code .sizNf, html code.shiki .sizNf{--shiki-default:#40A02B;--shiki-dark:#D6DEEB}html pre.shiki code .sDF9U, html code.shiki .sDF9U{--shiki-default:#7C7F93;--shiki-dark:#D3423E}html pre.shiki code .soAP-, html code.shiki .soAP-{--shiki-default:#4C4F69;--shiki-dark:#D7DBE0}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 .sL4Ga, html code.shiki .sL4Ga{--shiki-default:#4C4F69;--shiki-dark:#BAEBE2}html pre.shiki code .scsc5, html code.shiki .scsc5{--shiki-default:#4C4F69;--shiki-default-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic}html pre.shiki code .s-_ek, html code.shiki .s-_ek{--shiki-default:#179299;--shiki-dark:#C792EA}html pre.shiki code .szhwX, html code.shiki .szhwX{--shiki-default:#8839EF;--shiki-default-font-weight:bold;--shiki-dark:#7FDBCA;--shiki-dark-font-weight:inherit}html pre.shiki code .s8apv, html code.shiki .s8apv{--shiki-default:#4C4F69;--shiki-default-font-style:inherit;--shiki-dark:#BAEBE2;--shiki-dark-font-style:italic}",{"title":280,"searchDepth":294,"depth":294,"links":2565},[2566,2569,2573,2574,2580,2583,2587,2591,2592,2597],{"id":32,"depth":294,"text":33,"children":2567},[2568],{"id":49,"depth":323,"text":50},{"id":155,"depth":294,"text":156,"children":2570},[2571,2572],{"id":178,"depth":323,"text":179},{"id":211,"depth":323,"text":212},{"id":430,"depth":294,"text":431},{"id":449,"depth":294,"text":450,"children":2575},[2576,2577,2578],{"id":470,"depth":323,"text":473},{"id":742,"depth":323,"text":745},{"id":887,"depth":323,"text":2579},"unregisterTool and clearContext",{"id":975,"depth":294,"text":976,"children":2581},[2582],{"id":1636,"depth":323,"text":1637},{"id":1868,"depth":294,"text":1869,"children":2584},[2585,2586],{"id":1875,"depth":323,"text":1876},{"id":1992,"depth":323,"text":1993},{"id":2019,"depth":294,"text":2020,"children":2588},[2589,2590],{"id":2030,"depth":323,"text":2031},{"id":2151,"depth":323,"text":2152},{"id":2185,"depth":294,"text":2186},{"id":2233,"depth":294,"text":2234,"children":2593},[2594,2595,2596],{"id":2257,"depth":323,"text":2258},{"id":2290,"depth":323,"text":2291},{"id":2330,"depth":323,"text":2331},{"id":2549,"depth":294,"text":2550},"ai-agents","2026-04-10","What is WebMCP? Learn how the experimental browser protocol lets websites expose structured tools to AI agents, how it differs from MCP and OpenAPI, and how to test it in Chrome.","md",[2603,2606,2609,2612,2615,2618,2621],{"question":2604,"answer":2605},"What is WebMCP?","WebMCP (Web Model Context Protocol) is a proposed browser standard that lets websites expose structured tools to AI agents running in the browser. Instead of relying on brittle screen-scraping, agents can discover and call clearly defined tools with structured inputs. This makes web interactions faster, more reliable, and easier for developers to maintain.",{"question":2607,"answer":2608},"What is the difference between the WebMCP Imperative and Declarative APIs?","The Imperative API uses JavaScript functions (registerTool, provideContext, unregisterTool, clearContext) accessed via window.navigator.modelContext to programmatically manage tools at runtime. It is best for dynamic single-page applications where available actions change based on state. The Declarative API adds special HTML attributes (toolname, tooldescription, toolparamtitle) to standard form elements. The browser automatically converts these annotated forms into structured tool definitions, making it a low-friction way to make existing forms agent-accessible with minimal code changes.",{"question":2610,"answer":2611},"How does WebMCP differ from MCP and OpenAPI?","MCP (Model Context Protocol) and OpenAPI are server-side integration approaches where an AI platform communicates directly with a backend server without involving a browser. WebMCP is entirely client-side: tools are JavaScript functions that execute within the user's browser on a loaded webpage. This client-side architecture enables human-in-the-loop workflows where users remain in control of a familiar web interface while an agent handles specific tasks.",{"question":2613,"answer":2614},"What are the current limitations of WebMCP?","WebMCP requires an active browser tab to function-it does not support headless scenarios without a visible UI. Developers are responsible for ensuring the UI reflects any state changes the agent makes. Complex applications may need refactoring to separate business logic from presentation. There is no centralized discovery mechanism for agents to find WebMCP-enabled sites. As of 2026, it is only available as an experimental feature behind a flag in Google Chrome version 146+.",{"question":2616,"answer":2617},"How do I try WebMCP today?","WebMCP is currently available in Chrome's early preview environment for testing. In practice, that means using a recent Chrome 146+ build with the 'WebMCP for testing' flag enabled at chrome://flags/#enable-webmcp-testing. After relaunching Chrome, you can use the Model Context Tool Inspector extension to inspect and test tools on supported demo pages such as the Google Chrome Labs React flight-search demo.",{"question":2619,"answer":2620},"Is WebMCP available today?","Yes, but only as an experimental Chrome early preview. It is not yet a widely supported cross-browser web standard, so developers should treat it as an emerging technology for testing and feedback rather than a production baseline.",{"question":2622,"answer":2623},"Does WebMCP replace MCP or OpenAPI?","No. WebMCP is designed for browser-based, user-in-the-loop interactions on a live webpage. MCP and OpenAPI remain better fits for server-side integrations and fully automated backend workflows. In practice, many products may eventually use both: server-side protocols for backend automation and WebMCP for interactive browser experiences.",0,null,{"shortTitle":2604,"relatedLinks":2627},[2628,2630,2632],{"text":2541,"href":2540,"description":2629},"Compare the five best MCP servers for connecting AI agents to live browsers.",{"text":2546,"href":2545,"description":2631},"Compare Vercel agent-browser, Puppeteer, and Playwright for web automation and AI agents in 2026.",{"text":18,"href":17,"description":2633},"A beginner-friendly overview of how AI agents interact with and control websites.","/blog/what-is-webmcp-the-practical-guide-to-the-web-model-context-protocol",{"title":5,"description":2600},{"loc":2634},"blog/1039.what-is-webmcp-the-practical-guide-to-the-web-model-context-protocol",[2639,2640,2598,2641,2642,2643],"webmcp","mcp","browser-automation","web-agents","web-standard","ILg2UK9OFU2Klo9QFRrN4pbv4qz9tV1_WhroqgPGt1k",[2646,4349],{"id":2647,"title":175,"authorId":2648,"body":2649,"category":2598,"created":4326,"description":4327,"extension":2601,"faqs":2625,"featurePriority":2625,"head":2625,"landingPath":2625,"meta":4328,"navigation":945,"ogImage":2625,"path":174,"robots":2625,"schemaOrg":2625,"seo":4340,"sitemap":4341,"stem":4342,"tags":4343,"__hash__":4348},"blog/blog/1012.dom-downsampling-for-llm-based-web-agents.md","thassilo-schiepanski",{"type":8,"value":2650,"toc":4311},[2651,2655,2677,2681,2688,2692,2707,2711,2717,2721,2739,2763,2766,2770,2773,2784,2790,2821,2825,2843,2855,2859,2874,2888,2891,2895,2915,2919,2927,2939,2943,2946,3297,3303,3310,3474,3481,3572,3579,3651,3660,3666,3675,3679,3685,3694,3706,3924,3942,4008,4014,4126,4130,4142,4151,4156,4161,4164,4168,4174,4179,4217,4221,4227,4231,4241,4245,4248,4308],[35,2652],{":width":37,"alt":2653,"format":42,"loading":39,"src":2654},"Downsampling visualised for digital images and HTML","/blog/dom-downsampling-for-web-agents/1.png",[11,2656,2657,245,2662,245,2667,2672,2673,2676],{},[15,2658,2661],{"href":2659,"rel":2660},"https://operator.chatgpt.com",[2358],"Operator (OpenAI)",[15,2663,2666],{"href":2664,"rel":2665},"https://www.director.ai",[2358],"Director (Browserbase)",[15,2668,2671],{"href":2669,"rel":2670},"https://browser-use.com",[2358],"Browser Use"," – we are currently witnessing the rise of ",[55,2674,2675],{},"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.",[30,2678,2680],{"id":2679},"what-is-a-snapshot","What is a Snapshot?",[11,2682,2683,2684,2687],{},"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 ",[55,2685,2686],{},"snapshot",". And the snapshot technique primarily decides the quality of LLM interaction suggestions.",[47,2689,2691],{"id":2690},"gui-snapshots","GUI Snapshots",[11,2693,2694,2695,2698,2699,2702,2703,2706],{},"Screenshots – for consistency reasons referred to as ",[55,2696,2697],{},"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 ",[2205,2700,2701],{},"“click at 100, 735”",". As a workaround, early web agents used ",[2205,2704,2705],{},"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.",[35,2708],{":width":37,"alt":2709,"format":42,"loading":39,"src":2710},"Grounded GUI snapshot as implemented by Browser Use","/blog/dom-downsampling-for-web-agents/2.png",[11,2712,2713],{},[2714,2715,2716],"small",{},"Grounded GUI snapshot as implemented by Browser Use.",[47,2718,2720],{"id":2719},"dom-snapshots","DOM Snapshots",[11,2722,2723,2724,2734,2735,2738],{},"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",[2725,2726,2727],"sup",{},[15,2728,2733],{"href":2729,"ariaDescribedBy":2730,"dataFootnoteRef":280,"id":2732},"#user-content-fn-1",[2731],"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, ",[55,2736,2737],{},"DOM snapshots"," offer a compelling alternative to GUI snapshots. DOM snapshots offer a handful of key advantages:",[187,2740,2741,2744,2747,2750,2753],{},[190,2742,2743],{},"DOM snapshots connect with LLM code (HTML) interpretation abilities.",[190,2745,2746],{},"DOM snapshots can be compiled from deep clones, hidden from supervision (unlike GUI grounding).",[190,2748,2749],{},"DOM snapshots render text input that on average consume less bandwidth than screnshots.",[190,2751,2752],{},"DOM snapshots allow for exact programmatic targeting of elements (e.g., via CSS selectors).",[190,2754,2755,2756,2759,2760,1001],{},"DOM snapshots are available with the ",[229,2757,2758],{},"DOMContentLoaded"," event (whereas the GUI completes initial rendering with ",[229,2761,2762],{},"load",[11,2764,2765],{},"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?).",[30,2767,2769],{"id":2768},"dom-downsampling-a-novel-approach","DOM Downsampling: A Novel Approach",[11,2771,2772],{},"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,2774,2775,2776,2779,2780,2783],{},"We transfer the concept of ",[55,2777,2778],{},"downsampling"," to ",[55,2781,2782],{},"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.",[30,2785,2787],{"id":2786},"d2snap",[2205,2788,2789],{},"D2Snap",[11,2791,2792,2793,2801,2809,2817,2818,2820],{},"We recently proposed ",[15,2794,2797],{"href":2795,"rel":2796},"https://arxiv.org/abs/2508.04412",[2358],[55,2798,2799],{},[2205,2800,2789],{},[2725,2802,2803],{},[15,2804,2808],{"href":2805,"ariaDescribedBy":2806,"dataFootnoteRef":280,"id":2807},"#user-content-fn-2",[2731],"user-content-fnref-2","2",[2725,2810,2811],{},[15,2812,2816],{"href":2813,"ariaDescribedBy":2814,"dataFootnoteRef":280,"id":2815},"#user-content-fn-3",[2731],"user-content-fnref-3","3"," – a first-of-its-kind downsampling algorithm for DOMs. Herein, we'll briefly explain how the ",[2205,2819,2789],{}," algorithm works, and how it can be utilised to build efficient and performant web agents.",[47,2822,2824],{"id":2823},"how-it-works","How it works",[11,2826,2827,2828,2830,2831,245,2834,249,2837,633,2840,1001],{},"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. ",[2205,2829,2789],{}," downsamples at a variable ratio, configured through procedure-specific parameters  ",[229,2832,2833],{},"k",[229,2835,2836],{},"l",[229,2838,2839],{},"m",[229,2841,2842],{},"∈ [0, 1]",[2844,2845,2846],"blockquote",{},[11,2847,2848,2849,2854],{},"We used ",[15,2850,2853],{"href":2851,"rel":2852},"https://openai.com/index/hello-gpt-4o/",[2358],"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.",[2339,2856,2858],{"id":2857},"procedure-elements","Procedure: Elements",[11,2860,2861,2863,2864,171,2867,2870,2871,2873],{},[2205,2862,2789],{}," downsamples (simplifies) elements by merging container elements like ",[229,2865,2866],{},"section",[229,2868,2869],{},"div"," together. A parameter ",[229,2872,2833],{}," 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,2875,2876,2877,245,2879,2881,2882,2887],{},"Elements in content elements (",[229,2878,11],{},[229,2880,2844],{},", ...) are translated to a more comprehensive ",[15,2883,2886],{"href":2884,"rel":2885},"https://www.markdownguide.org/basic-syntax/",[2358],"Markdown"," representation.",[11,2889,2890],{},"Interactive elements, definite interaction target candidates, are kept as is.",[2339,2892,2894],{"id":2893},"procedure-text","Procedure: Text",[11,2896,2897,2899,2900,2903,2911,2912,2914],{},[2205,2898,2789],{}," downsamples text by dropping a fraction. Natural units of text are space-separated words, or punctuation-separated sentences. We reuse the ",[2205,2901,2902],{},"TextRank",[2725,2904,2905],{},[15,2906,2910],{"href":2907,"ariaDescribedBy":2908,"dataFootnoteRef":280,"id":2909},"#user-content-fn-4",[2731],"user-content-fnref-4","4"," algorithm to rank sentences in text nodes. The lowest-ranking fraction of sentences, denoted by parameter ",[229,2913,2836],{},", is dropped.",[2339,2916,2918],{"id":2917},"procedure-attributes","Procedure: Attributes",[11,2920,2921,2923,2924,2926],{},[2205,2922,2789],{}," downsamples attributes by dropping those with a name that, according to ground truth, holds a UI feature degree below a threshold. Parameter ",[229,2925,2839],{}," denotes this threshold.",[2844,2928,2929],{},[11,2930,2931,2932,2938],{},"Check out the ",[15,2933,2935,2937],{"href":2795,"rel":2934},[2358],[2205,2936,2789],{}," paper"," to learn about the algorithm in-depth.",[47,2940,2942],{"id":2941},"example-of-a-downsampled-dom","Example of a Downsampled DOM",[11,2944,2945],{},"Consider a partial DOM state, serialised as HTML:",[275,2947,2949],{"className":1031,"code":2948,"language":1033,"meta":280,"style":280},"\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",[229,2950,2951,3005,3047,3065,3073,3093,3111,3119,3124,3129,3138,3165,3174,3192,3209,3217,3222,3227,3236,3262,3270,3279,3288],{"__ignoreMap":280},[284,2952,2953,2955,2957,2960,2962,2964,2967,2969,2972,2974,2976,2978,2980,2983,2985,2987,2990,2992,2994,2996,2998,3001,3003],{"class":286,"line":287},[284,2954,1041],{"class":1040},[284,2956,2866],{"class":1044},[284,2958,2959],{"class":1050}," class",[284,2961,1054],{"class":1040},[284,2963,304],{"class":310},[284,2965,2966],{"class":529},"container",[284,2968,304],{"class":310},[284,2970,2971],{"class":1050}," tabindex",[284,2973,1054],{"class":1040},[284,2975,304],{"class":310},[284,2977,2816],{"class":529},[284,2979,304],{"class":310},[284,2981,2982],{"class":1050}," required",[284,2984,1054],{"class":1040},[284,2986,304],{"class":310},[284,2988,2989],{"class":529},"true",[284,2991,304],{"class":310},[284,2993,598],{"class":1050},[284,2995,1054],{"class":1040},[284,2997,304],{"class":310},[284,2999,3000],{"class":529},"example",[284,3002,304],{"class":310},[284,3004,1100],{"class":1040},[284,3006,3007,3009,3011,3013,3015,3017,3020,3022,3025,3027,3029,3032,3034,3036,3038,3040,3043,3045],{"class":286,"line":294},[284,3008,1105],{"class":1040},[284,3010,2869],{"class":1044},[284,3012,2959],{"class":1050},[284,3014,1054],{"class":1040},[284,3016,304],{"class":310},[284,3018,3019],{"class":529},"mx-auto",[284,3021,304],{"class":310},[284,3023,3024],{"class":1050}," data-topic",[284,3026,1054],{"class":1040},[284,3028,304],{"class":310},[284,3030,3031],{"class":529},"products",[284,3033,304],{"class":310},[284,3035,2982],{"class":1050},[284,3037,1054],{"class":1040},[284,3039,304],{"class":310},[284,3041,3042],{"class":529},"false",[284,3044,304],{"class":310},[284,3046,1100],{"class":1040},[284,3048,3049,3051,3054,3056,3059,3061,3063],{"class":286,"line":323},[284,3050,1233],{"class":1040},[284,3052,3053],{"class":1044},"h1",[284,3055,1122],{"class":1040},[284,3057,3058],{"class":513},"Our Pizza",[284,3060,1128],{"class":1040},[284,3062,3053],{"class":1044},[284,3064,1100],{"class":1040},[284,3066,3067,3069,3071],{"class":286,"line":343},[284,3068,1233],{"class":1040},[284,3070,2869],{"class":1044},[284,3072,1100],{"class":1040},[284,3074,3075,3078,3080,3082,3084,3086,3089,3091],{"class":286,"line":364},[284,3076,3077],{"class":1040},"      \u003C",[284,3079,2869],{"class":1044},[284,3081,2959],{"class":1050},[284,3083,1054],{"class":1040},[284,3085,304],{"class":310},[284,3087,3088],{"class":529},"shadow-lg",[284,3090,304],{"class":310},[284,3092,1100],{"class":1040},[284,3094,3095,3098,3100,3102,3105,3107,3109],{"class":286,"line":384},[284,3096,3097],{"class":1040},"        \u003C",[284,3099,30],{"class":1044},[284,3101,1122],{"class":1040},[284,3103,3104],{"class":513},"Margherita",[284,3106,1128],{"class":1040},[284,3108,30],{"class":1044},[284,3110,1100],{"class":1040},[284,3112,3113,3115,3117],{"class":286,"line":405},[284,3114,3097],{"class":1040},[284,3116,11],{"class":1044},[284,3118,1100],{"class":1040},[284,3120,3121],{"class":286,"line":421},[284,3122,3123],{"class":513},"          A simple classic: mozzarela, tomatoes and basil.\n",[284,3125,3126],{"class":286,"line":618},[284,3127,3128],{"class":513},"          An everyday choice!\n",[284,3130,3131,3134,3136],{"class":286,"line":624},[284,3132,3133],{"class":1040},"        \u003C/",[284,3135,11],{"class":1044},[284,3137,1100],{"class":1040},[284,3139,3140,3142,3144,3146,3148,3150,3152,3154,3156,3159,3161,3163],{"class":286,"line":655},[284,3141,3097],{"class":1040},[284,3143,1311],{"class":1044},[284,3145,598],{"class":1050},[284,3147,1054],{"class":1040},[284,3149,304],{"class":310},[284,3151,1311],{"class":529},[284,3153,304],{"class":310},[284,3155,1122],{"class":1040},[284,3157,3158],{"class":513},"Add",[284,3160,1128],{"class":1040},[284,3162,1311],{"class":1044},[284,3164,1100],{"class":1040},[284,3166,3167,3170,3172],{"class":286,"line":662},[284,3168,3169],{"class":1040},"      \u003C/",[284,3171,2869],{"class":1044},[284,3173,1100],{"class":1040},[284,3175,3176,3178,3180,3182,3184,3186,3188,3190],{"class":286,"line":727},[284,3177,3077],{"class":1040},[284,3179,2869],{"class":1044},[284,3181,2959],{"class":1050},[284,3183,1054],{"class":1040},[284,3185,304],{"class":310},[284,3187,3088],{"class":529},[284,3189,304],{"class":310},[284,3191,1100],{"class":1040},[284,3193,3194,3196,3198,3200,3203,3205,3207],{"class":286,"line":732},[284,3195,3097],{"class":1040},[284,3197,30],{"class":1044},[284,3199,1122],{"class":1040},[284,3201,3202],{"class":513},"Capricciosa",[284,3204,1128],{"class":1040},[284,3206,30],{"class":1044},[284,3208,1100],{"class":1040},[284,3210,3211,3213,3215],{"class":286,"line":1224},[284,3212,3097],{"class":1040},[284,3214,11],{"class":1044},[284,3216,1100],{"class":1040},[284,3218,3219],{"class":286,"line":1230},[284,3220,3221],{"class":513},"          A rich taste: mozzarella, ham, mushrooms, artichokes, and olives.\n",[284,3223,3224],{"class":286,"line":1262},[284,3225,3226],{"class":513},"          A true favourite!\n",[284,3228,3229,3232,3234],{"class":286,"line":1291},[284,3230,3231],{"class":1040},"          \u003C/",[284,3233,11],{"class":1044},[284,3235,1100],{"class":1040},[284,3237,3238,3240,3242,3244,3246,3248,3250,3252,3254,3256,3258,3260],{"class":286,"line":1301},[284,3239,3097],{"class":1040},[284,3241,1311],{"class":1044},[284,3243,598],{"class":1050},[284,3245,1054],{"class":1040},[284,3247,304],{"class":310},[284,3249,1311],{"class":529},[284,3251,304],{"class":310},[284,3253,1122],{"class":1040},[284,3255,3158],{"class":513},[284,3257,1128],{"class":1040},[284,3259,1311],{"class":1044},[284,3261,1100],{"class":1040},[284,3263,3264,3266,3268],{"class":286,"line":1306},[284,3265,3169],{"class":1040},[284,3267,2869],{"class":1044},[284,3269,1100],{"class":1040},[284,3271,3272,3275,3277],{"class":286,"line":1336},[284,3273,3274],{"class":1040},"    \u003C/",[284,3276,2869],{"class":1044},[284,3278,1100],{"class":1040},[284,3280,3282,3284,3286],{"class":286,"line":3281},22,[284,3283,1294],{"class":1040},[284,3285,2869],{"class":1044},[284,3287,1100],{"class":1040},[284,3289,3291,3293,3295],{"class":286,"line":3290},23,[284,3292,1128],{"class":1040},[284,3294,2866],{"class":1044},[284,3296,1100],{"class":1040},[11,3298,3299,3300,3302],{},"Here are some ",[2205,3301,2789],{}," downsampling results, which are based on different parametric configurations. A percentage denotes the reduced size.",[2339,3304,3306,3309],{"id":3305},"k3-l3-m3-55",[229,3307,3308],{},"k=.3, l=.3, m=.3"," (55%)",[275,3311,3313],{"className":1031,"code":3312,"language":1033,"meta":280,"style":280},"\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",[229,3314,3315,3363,3368,3386,3391,3396,3422,3427,3432,3458,3466],{"__ignoreMap":280},[284,3316,3317,3319,3321,3323,3325,3327,3329,3331,3333,3335,3337,3339,3341,3343,3345,3347,3349,3351,3353,3355,3357,3359,3361],{"class":286,"line":287},[284,3318,1041],{"class":1040},[284,3320,2866],{"class":1044},[284,3322,2971],{"class":1050},[284,3324,1054],{"class":1040},[284,3326,304],{"class":310},[284,3328,2816],{"class":529},[284,3330,304],{"class":310},[284,3332,598],{"class":1050},[284,3334,1054],{"class":1040},[284,3336,304],{"class":310},[284,3338,3000],{"class":529},[284,3340,304],{"class":310},[284,3342,2959],{"class":1050},[284,3344,1054],{"class":1040},[284,3346,304],{"class":310},[284,3348,2966],{"class":529},[284,3350,304],{"class":310},[284,3352,2982],{"class":1050},[284,3354,1054],{"class":1040},[284,3356,304],{"class":310},[284,3358,2989],{"class":529},[284,3360,304],{"class":310},[284,3362,1100],{"class":1040},[284,3364,3365],{"class":286,"line":294},[284,3366,3367],{"class":513},"  # Our Pizza\n",[284,3369,3370,3372,3374,3376,3378,3380,3382,3384],{"class":286,"line":323},[284,3371,1105],{"class":1040},[284,3373,2869],{"class":1044},[284,3375,2959],{"class":1050},[284,3377,1054],{"class":1040},[284,3379,304],{"class":310},[284,3381,3088],{"class":529},[284,3383,304],{"class":310},[284,3385,1100],{"class":1040},[284,3387,3388],{"class":286,"line":343},[284,3389,3390],{"class":513},"    ## Margherita\n",[284,3392,3393],{"class":286,"line":364},[284,3394,3395],{"class":513},"    A simple classic: mozzarela, tomatoes, and basil.\n",[284,3397,3398,3400,3402,3404,3406,3408,3410,3412,3414,3416,3418,3420],{"class":286,"line":384},[284,3399,1233],{"class":1040},[284,3401,1311],{"class":1044},[284,3403,598],{"class":1050},[284,3405,1054],{"class":1040},[284,3407,304],{"class":310},[284,3409,1311],{"class":529},[284,3411,304],{"class":310},[284,3413,1122],{"class":1040},[284,3415,3158],{"class":513},[284,3417,1128],{"class":1040},[284,3419,1311],{"class":1044},[284,3421,1100],{"class":1040},[284,3423,3424],{"class":286,"line":405},[284,3425,3426],{"class":513},"    ## Capricciosa\n",[284,3428,3429],{"class":286,"line":421},[284,3430,3431],{"class":513},"    A rich taste: mozzarella, ham, mushrooms, artichokes, and olives.\n",[284,3433,3434,3436,3438,3440,3442,3444,3446,3448,3450,3452,3454,3456],{"class":286,"line":618},[284,3435,1233],{"class":1040},[284,3437,1311],{"class":1044},[284,3439,598],{"class":1050},[284,3441,1054],{"class":1040},[284,3443,304],{"class":310},[284,3445,1311],{"class":529},[284,3447,304],{"class":310},[284,3449,1122],{"class":1040},[284,3451,3158],{"class":513},[284,3453,1128],{"class":1040},[284,3455,1311],{"class":1044},[284,3457,1100],{"class":1040},[284,3459,3460,3462,3464],{"class":286,"line":624},[284,3461,1294],{"class":1040},[284,3463,2869],{"class":1044},[284,3465,1100],{"class":1040},[284,3467,3468,3470,3472],{"class":286,"line":655},[284,3469,1128],{"class":1040},[284,3471,2866],{"class":1044},[284,3473,1100],{"class":1040},[2339,3475,3477,3480],{"id":3476},"k4-l6-m8-27",[229,3478,3479],{},"k=.4, l=.6, m=.8"," (27%)",[275,3482,3484],{"className":1031,"code":3483,"language":1033,"meta":280,"style":280},"\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",[229,3485,3486,3494,3498,3506,3510,3515,3531,3535,3540,3556,3564],{"__ignoreMap":280},[284,3487,3488,3490,3492],{"class":286,"line":287},[284,3489,1041],{"class":1040},[284,3491,2866],{"class":1044},[284,3493,1100],{"class":1040},[284,3495,3496],{"class":286,"line":294},[284,3497,3367],{"class":513},[284,3499,3500,3502,3504],{"class":286,"line":323},[284,3501,1105],{"class":1040},[284,3503,2869],{"class":1044},[284,3505,1100],{"class":1040},[284,3507,3508],{"class":286,"line":343},[284,3509,3390],{"class":513},[284,3511,3512],{"class":286,"line":364},[284,3513,3514],{"class":513},"    A simple classic:\n",[284,3516,3517,3519,3521,3523,3525,3527,3529],{"class":286,"line":384},[284,3518,1233],{"class":1040},[284,3520,1311],{"class":1044},[284,3522,1122],{"class":1040},[284,3524,3158],{"class":513},[284,3526,1128],{"class":1040},[284,3528,1311],{"class":1044},[284,3530,1100],{"class":1040},[284,3532,3533],{"class":286,"line":405},[284,3534,3426],{"class":513},[284,3536,3537],{"class":286,"line":421},[284,3538,3539],{"class":513},"    A rich taste:\n",[284,3541,3542,3544,3546,3548,3550,3552,3554],{"class":286,"line":618},[284,3543,1233],{"class":1040},[284,3545,1311],{"class":1044},[284,3547,1122],{"class":1040},[284,3549,3158],{"class":513},[284,3551,1128],{"class":1040},[284,3553,1311],{"class":1044},[284,3555,1100],{"class":1040},[284,3557,3558,3560,3562],{"class":286,"line":624},[284,3559,1294],{"class":1040},[284,3561,2869],{"class":1044},[284,3563,1100],{"class":1040},[284,3565,3566,3568,3570],{"class":286,"line":655},[284,3567,1128],{"class":1040},[284,3569,2866],{"class":1044},[284,3571,1100],{"class":1040},[2339,3573,3575,3578],{"id":3574},"k-l0-m-35",[229,3576,3577],{},"k→∞, l=0, ∀m"," (35%)",[275,3580,3582],{"className":1031,"code":3581,"language":1033,"meta":280,"style":280},"# 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",[229,3583,3584,3589,3594,3599,3604,3620,3625,3630,3635],{"__ignoreMap":280},[284,3585,3586],{"class":286,"line":287},[284,3587,3588],{"class":513},"# Our Pizza\n",[284,3590,3591],{"class":286,"line":294},[284,3592,3593],{"class":513},"## Margherita\n",[284,3595,3596],{"class":286,"line":323},[284,3597,3598],{"class":513},"A simple classic: mozzarela, tomatoes, and basil.\n",[284,3600,3601],{"class":286,"line":343},[284,3602,3603],{"class":513},"An everyday choice!\n",[284,3605,3606,3608,3610,3612,3614,3616,3618],{"class":286,"line":364},[284,3607,1041],{"class":1040},[284,3609,1311],{"class":1044},[284,3611,1122],{"class":1040},[284,3613,3158],{"class":513},[284,3615,1128],{"class":1040},[284,3617,1311],{"class":1044},[284,3619,1100],{"class":1040},[284,3621,3622],{"class":286,"line":384},[284,3623,3624],{"class":513},"## Capricciosa\n",[284,3626,3627],{"class":286,"line":405},[284,3628,3629],{"class":513},"A rich taste: mozzarella, ham, mushrooms, artichokes, and olives.\n",[284,3631,3632],{"class":286,"line":421},[284,3633,3634],{"class":513},"A true favourite!\n",[284,3636,3637,3639,3641,3643,3645,3647,3649],{"class":286,"line":618},[284,3638,1041],{"class":1040},[284,3640,1311],{"class":1044},[284,3642,1122],{"class":1040},[284,3644,3158],{"class":513},[284,3646,1128],{"class":1040},[284,3648,1311],{"class":1044},[284,3650,1100],{"class":1040},[11,3652,3653,3654,3656,3657,3659],{},"Asymptotic ",[229,3655,2833],{}," (kind of 'infinite' ",[229,3658,2833],{},") 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.",[47,3661,3663],{"id":3662},"adaptived2snap",[2205,3664,3665],{},"AdaptiveD2Snap",[11,3667,3668,3669,3671,3672,3674],{},"Fixed parameters might not be ideal for arbitrary DOMs – sourced from a landscape of web applications. We created ",[2205,3670,3665],{}," – a wrapper for ",[2205,3673,2789],{}," that infers suitable parameters from a given DOM in order to hit a certain token budget.",[47,3676,3678],{"id":3677},"implementation-integration","Implementation & Integration",[11,3680,3681,3682,3684],{},"Picture an LLM-based weg agent that is premised on DOM snapshots. Implementing ",[2205,3683,2789],{}," is simple: Deep clone the DOM, and feed it to the algorithm. Now, take the snapshot; this is, serialise the resulting DOM. Done.",[2844,3686,3687],{},[11,3688,3689,3690,3693],{},"Read our ",[15,3691,3692],{"href":17},"gentle introduction to AI agents for the web"," to get started with high-level web agent concepts.",[11,3695,3696,3697,3699,3700,3705],{},"The open source ",[2205,3698,2789],{}," API, provided as a ",[15,3701,3704],{"href":3702,"rel":3703},"https://github.com/webfuse-com/D2Snap",[2358],"package on GitHub"," provides the following signature:",[275,3707,3711],{"className":3708,"code":3709,"language":3710,"meta":280,"style":280},"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",[229,3712,3713,3741,3752,3770,3784,3788,3792,3804,3815,3832,3842,3857,3861,3872,3880,3892,3904,3912],{"__ignoreMap":280},[284,3714,3715,3717,3721,3723,3727,3730,3733,3735,3739],{"class":286,"line":287},[284,3716,1421],{"class":649},[284,3718,3720],{"class":3719},"sXbZB"," DOM ",[284,3722,1054],{"class":1748},[284,3724,3726],{"class":3725},"s-DR7"," Document",[284,3728,3729],{"class":1040}," |",[284,3731,3732],{"class":3725}," Element",[284,3734,3729],{"class":1040},[284,3736,3738],{"class":3737},"scrte"," string",[284,3740,739],{"class":290},[284,3742,3743,3745,3748,3750],{"class":286,"line":294},[284,3744,1421],{"class":649},[284,3746,3747],{"class":3719}," Options ",[284,3749,1054],{"class":1748},[284,3751,560],{"class":290},[284,3753,3754,3758,3761,3764,3767],{"class":286,"line":323},[284,3755,3757],{"class":3756},"swl0y","  assignUniqueIDs",[284,3759,3760],{"class":1040},"?:",[284,3762,3763],{"class":3737}," boolean",[284,3765,3766],{"class":290},";",[284,3768,3769],{"class":658}," // false\n",[284,3771,3772,3775,3777,3779,3781],{"class":286,"line":343},[284,3773,3774],{"class":3756},"  debug",[284,3776,3760],{"class":1040},[284,3778,3763],{"class":3737},[284,3780,3766],{"class":290},[284,3782,3783],{"class":658},"           // true\n",[284,3785,3786],{"class":286,"line":364},[284,3787,724],{"class":290},[284,3789,3790],{"class":286,"line":384},[284,3791,946],{"emptyLinePlaceholder":945},[284,3793,3794,3796,3798,3801],{"class":286,"line":405},[284,3795,2789],{"class":513},[284,3797,19],{"class":496},[284,3799,3800],{"class":510},"d2Snap",[284,3802,3803],{"class":513},"(\n",[284,3805,3806,3809,3813],{"class":286,"line":421},[284,3807,3808],{"class":513},"  dom: ",[284,3810,3812],{"class":3811},"sqxXB","DOM",[284,3814,320],{"class":290},[284,3816,3817,3820,3822,3825,3827,3830],{"class":286,"line":618},[284,3818,3819],{"class":513},"  k: number",[284,3821,692],{"class":290},[284,3823,3824],{"class":513}," l: number",[284,3826,692],{"class":290},[284,3828,3829],{"class":513}," m: number",[284,3831,320],{"class":290},[284,3833,3834,3837,3839],{"class":286,"line":624},[284,3835,3836],{"class":513},"  options",[284,3838,3760],{"class":1748},[284,3840,3841],{"class":513}," Options\n",[284,3843,3844,3847,3851,3853,3855],{"class":286,"line":655},[284,3845,3846],{"class":513},"): ",[284,3848,3850],{"class":3849},"s8Irk","Promise",[284,3852,1041],{"class":1748},[284,3854,605],{"class":513},[284,3856,1100],{"class":1748},[284,3858,3859],{"class":286,"line":662},[284,3860,946],{"emptyLinePlaceholder":945},[284,3862,3863,3865,3867,3870],{"class":286,"line":727},[284,3864,2789],{"class":513},[284,3866,19],{"class":496},[284,3868,3869],{"class":510},"adaptiveD2Snap",[284,3871,3803],{"class":513},[284,3873,3874,3876,3878],{"class":286,"line":732},[284,3875,3808],{"class":513},[284,3877,3812],{"class":3811},[284,3879,320],{"class":290},[284,3881,3882,3885,3887,3890],{"class":286,"line":1224},[284,3883,3884],{"class":513},"  maxTokens: number ",[284,3886,1054],{"class":1748},[284,3888,3889],{"class":417}," 4096",[284,3891,320],{"class":290},[284,3893,3894,3897,3899,3902],{"class":286,"line":1230},[284,3895,3896],{"class":513},"  maxIterations: number ",[284,3898,1054],{"class":1748},[284,3900,3901],{"class":417}," 5",[284,3903,320],{"class":290},[284,3905,3906,3908,3910],{"class":286,"line":1262},[284,3907,3836],{"class":513},[284,3909,3760],{"class":1748},[284,3911,3841],{"class":513},[284,3913,3914,3916,3918,3920,3922],{"class":286,"line":1291},[284,3915,3846],{"class":513},[284,3917,3850],{"class":3849},[284,3919,1041],{"class":1748},[284,3921,605],{"class":513},[284,3923,1100],{"class":1748},[11,3925,3926,3927,3929,3930,3935,3936,3941],{},"Moreover, ",[2205,3928,2789],{}," it is available on the ",[15,3931,3934],{"href":3932,"rel":3933},"https://dev.webfuse.com/automation-api",[2358],"Webfuse Automation API",". ",[15,3937,3940],{"href":3938,"rel":3939},"https://www.webfuse.com",[2358],"Webfuse"," essentially is a proxy to seamlessly serve any existing web application with custom augmentations, such as a web agent widget.",[275,3943,3947],{"className":3944,"code":3945,"language":3946,"meta":280,"style":280},"language-js shiki shiki-themes catppuccin-latte night-owl","const domSnapshot = await browser.webfuseSession\n    .automation\n    .take_dom_snapshot({ modifier: 'downsample' })\n","js",[229,3948,3949,3970,3978],{"__ignoreMap":280},[284,3950,3951,3954,3957,3959,3962,3965,3967],{"class":286,"line":287},[284,3952,3953],{"class":649},"const",[284,3955,3956],{"class":1744}," domSnapshot",[284,3958,1749],{"class":1748},[284,3960,3961],{"class":665}," await",[284,3963,3964],{"class":492}," browser",[284,3966,19],{"class":496},[284,3968,3969],{"class":1765},"webfuseSession\n",[284,3971,3972,3975],{"class":286,"line":294},[284,3973,3974],{"class":496},"    .",[284,3976,3977],{"class":1717},"automation\n",[284,3979,3980,3982,3985,3987,3989,3992,3994,3997,4000,4003,4005],{"class":286,"line":323},[284,3981,3974],{"class":496},[284,3983,3984],{"class":510},"take_dom_snapshot",[284,3986,514],{"class":513},[284,3988,636],{"class":290},[284,3990,3991],{"class":513}," modifier",[284,3993,307],{"class":524},[284,3995,3996],{"class":310}," '",[284,3998,3999],{"class":529},"downsample",[284,4001,4002],{"class":310},"'",[284,4004,643],{"class":290},[284,4006,4007],{"class":513},")\n",[11,4009,4010,4011,4013],{},"Need precise control over the underlying ",[2205,4012,2789],{}," invocation? Configure it exactly how you want:",[275,4015,4017],{"className":3944,"code":4016,"language":3946,"meta":280,"style":280},"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",[229,4018,4019,4035,4041,4051,4060,4075,4115,4119],{"__ignoreMap":280},[284,4020,4021,4023,4025,4027,4029,4031,4033],{"class":286,"line":287},[284,4022,3953],{"class":649},[284,4024,3956],{"class":1744},[284,4026,1749],{"class":1748},[284,4028,3961],{"class":665},[284,4030,3964],{"class":492},[284,4032,19],{"class":496},[284,4034,3969],{"class":1765},[284,4036,4037,4039],{"class":286,"line":294},[284,4038,3974],{"class":496},[284,4040,3977],{"class":1717},[284,4042,4043,4045,4047,4049],{"class":286,"line":323},[284,4044,3974],{"class":496},[284,4046,3984],{"class":510},[284,4048,514],{"class":513},[284,4050,291],{"class":290},[284,4052,4053,4056,4058],{"class":286,"line":343},[284,4054,4055],{"class":513},"        modifier",[284,4057,307],{"class":524},[284,4059,560],{"class":290},[284,4061,4062,4065,4067,4069,4071,4073],{"class":286,"line":364},[284,4063,4064],{"class":513},"            name",[284,4066,307],{"class":524},[284,4068,3996],{"class":310},[284,4070,2789],{"class":529},[284,4072,4002],{"class":310},[284,4074,320],{"class":290},[284,4076,4077,4080,4082,4084,4087,4089,4092,4094,4097,4099,4102,4104,4107,4109,4112],{"class":286,"line":384},[284,4078,4079],{"class":513},"            params",[284,4081,307],{"class":524},[284,4083,595],{"class":290},[284,4085,4086],{"class":513}," hierarchyRatio",[284,4088,307],{"class":524},[284,4090,4091],{"class":417}," 0.6",[284,4093,692],{"class":290},[284,4095,4096],{"class":513}," textRatio",[284,4098,307],{"class":524},[284,4100,4101],{"class":417}," 0.2",[284,4103,692],{"class":290},[284,4105,4106],{"class":513}," attributeRatio",[284,4108,307],{"class":524},[284,4110,4111],{"class":417}," 0.8",[284,4113,4114],{"class":290}," }\n",[284,4116,4117],{"class":286,"line":405},[284,4118,1592],{"class":290},[284,4120,4121,4124],{"class":286,"line":421},[284,4122,4123],{"class":290},"    }",[284,4125,4007],{"class":513},[47,4127,4129],{"id":4128},"performance-evaluation","Performance Evaluation",[11,4131,4132,4133,4135,4136,4138,4139,4141],{},"Now for the moment of truth: How does ",[2205,4134,2789],{}," stack up against the industry standard? We evaluated ",[2205,4137,2789],{}," in comparison to a grounded GUI snapshot baseline close to those used by ",[2205,4140,2671],{}," – coloured bounding boxes around visible interactive elements.",[11,4143,4144,4145,4150],{},"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 ",[15,4146,4149],{"href":4147,"rel":4148},"https://github.com/OSU-NLP-Group/Online-Mind2Web",[2358],"Online-Mind2Web"," dataset.",[35,4152],{":width":4153,"alt":4154,"format":42,"loading":39,"src":4155},"800","Exemplary solution UI state trajectory of a defined web-based task","/blog/dom-downsampling-for-web-agents/3.png",[11,4157,4158],{},[2714,4159,4160],{},"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,4162,4163],{},"These are our key findings...",[2339,4165,4167],{"id":4166},"substantial-success-rates","Substantial Success Rates",[11,4169,4170,4171,4173],{},"The results exceeded our expectations. Not only did ",[2205,4172,2789],{}," 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.",[35,4175],{":width":4176,"alt":4177,"format":42,"loading":39,"src":4178},"550","Success rate per web agent snapshot subject evaluated across the dataset","/blog/dom-downsampling-for-web-agents/4.png",[2714,4180,4181,4182,4189,4190,4192,4193,4196,4197,4200,4201,4204,4205,4208,4209,4212,4213,4216],{},"\n  Success rate per web agent snapshot subject evaluated across the dataset.\n  Labels: ",[229,4183,4184,4185],{},"GUI",[4186,4187,4188],"sub",{}," gr.",": Baseline, ",[229,4191,3812],{},": Raw DOM (cut-off at ~8K tokens), ",[229,4194,4195],{},"k( l m)",": Parameter values; e.g., ",[229,4198,4199],{},".9 .3 .6",", or ",[229,4202,4203],{},".4"," if equal). ",[229,4206,4207],{},"∞",": Linearisation,  ",[229,4210,4211],{},"8192 / 32768",": via token-limited (resp.) ",[4214,4215,3665],"i",{},".\n",[2339,4218,4220],{"id":4219},"containable-token-and-byte-size","Containable Token and Byte Size",[11,4222,4223,4224,4226],{},"Even light downsampling delivers dramatic size reductions. Most ",[2205,4225,2789],{}," 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.",[35,4228],{":width":4153,"alt":4229,"format":42,"loading":39,"src":4230},"Comparison of mean input size across and per subject","/blog/dom-downsampling-for-web-agents/5.png",[2714,4232,4233,4234,4237,4238,4240],{},"\n  Left: Comparison of mean input size (tokens vs bytes) across and per subject.",[4235,4236],"br",{},"\n  Right: Estimated input token size across the dataset created by a single ",[4214,4239,2789],{}," evaluation subject.\n",[2339,4242,4244],{"id":4243},"hierarchy-actually-matters","Hierarchy Actually Matters",[11,4246,4247],{},"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.",[2866,4249,4252,4257],{"className":4250,"dataFootnotes":280},[4251],"footnotes",[30,4253,4256],{"className":4254,"id":2731},[4255],"sr-only","Footnotes",[187,4258,4259,4274,4285,4296],{},[190,4260,4262,4266,4267],{"id":4261},"user-content-fn-1",[15,4263,4264],{"href":4264,"rel":4265},"https://arxiv.org/abs/2210.03945",[2358]," ",[15,4268,4273],{"href":4269,"ariaLabel":4270,"className":4271,"dataFootnoteBackref":280},"#user-content-fnref-1","Back to reference 1",[4272],"data-footnote-backref","↩",[190,4275,4277,4266,4280],{"id":4276},"user-content-fn-2",[15,4278,2795],{"href":2795,"rel":4279},[2358],[15,4281,4273],{"href":4282,"ariaLabel":4283,"className":4284,"dataFootnoteBackref":280},"#user-content-fnref-2","Back to reference 2",[4272],[190,4286,4288,4266,4291],{"id":4287},"user-content-fn-3",[15,4289,3702],{"href":3702,"rel":4290},[2358],[15,4292,4273],{"href":4293,"ariaLabel":4294,"className":4295,"dataFootnoteBackref":280},"#user-content-fnref-3","Back to reference 3",[4272],[190,4297,4299,4266,4303],{"id":4298},"user-content-fn-4",[15,4300,4301],{"href":4301,"rel":4302},"https://aclanthology.org/W04-3252",[2358],[15,4304,4273],{"href":4305,"ariaLabel":4306,"className":4307,"dataFootnoteBackref":280},"#user-content-fnref-4","Back to reference 4",[4272],[2561,4309,4310],{},"html pre.shiki code .s9rnR, html code.shiki .s9rnR{--shiki-default:#179299;--shiki-dark:#7FDBCA}html pre.shiki code .sY2RG, html code.shiki .sY2RG{--shiki-default:#1E66F5;--shiki-dark:#CAECE6}html pre.shiki code .swkLt, html code.shiki .swkLt{--shiki-default:#DF8E1D;--shiki-default-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic}html pre.shiki code .sbuKk, html code.shiki .sbuKk{--shiki-default:#40A02B;--shiki-dark:#D9F5DD}html pre.shiki code .sfrMT, html code.shiki .sfrMT{--shiki-default:#40A02B;--shiki-dark:#ECC48D}html pre.shiki code .s2kId, html code.shiki .s2kId{--shiki-default:#4C4F69;--shiki-dark:#D6DEEB}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s76yb, html code.shiki .s76yb{--shiki-default:#8839EF;--shiki-dark:#C792EA}html pre.shiki code .sXbZB, html code.shiki .sXbZB{--shiki-default:#DF8E1D;--shiki-default-font-style:italic;--shiki-dark:#D6DEEB;--shiki-dark-font-style:inherit}html pre.shiki code .s-_ek, html code.shiki .s-_ek{--shiki-default:#179299;--shiki-dark:#C792EA}html pre.shiki code .s-DR7, html code.shiki .s-DR7{--shiki-default:#DF8E1D;--shiki-default-font-style:italic;--shiki-dark:#FFCB8B;--shiki-dark-font-style:inherit}html pre.shiki code .scrte, html code.shiki .scrte{--shiki-default:#8839EF;--shiki-dark:#C5E478}html pre.shiki code .scGhl, html code.shiki .scGhl{--shiki-default:#7C7F93;--shiki-dark:#D6DEEB}html pre.shiki code .swl0y, html code.shiki .swl0y{--shiki-default:#4C4F69;--shiki-default-font-style:italic;--shiki-dark:#D6DEEB;--shiki-dark-font-style:inherit}html pre.shiki code .sDmS1, html code.shiki .sDmS1{--shiki-default:#7C7F93;--shiki-default-font-style:italic;--shiki-dark:#637777;--shiki-dark-font-style:italic}html pre.shiki code .s5FwJ, html code.shiki .s5FwJ{--shiki-default:#179299;--shiki-default-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic}html pre.shiki code .sNstc, html code.shiki .sNstc{--shiki-default:#1E66F5;--shiki-default-font-style:italic;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic}html pre.shiki code .sqxXB, html code.shiki .sqxXB{--shiki-default:#4C4F69;--shiki-dark:#82AAFF}html pre.shiki code .s8Irk, html code.shiki .s8Irk{--shiki-default:#DF8E1D;--shiki-default-font-style:italic;--shiki-dark:#C5E478;--shiki-dark-font-style:inherit}html pre.shiki code .sZ_Zo, html code.shiki .sZ_Zo{--shiki-default:#FE640B;--shiki-dark:#F78C6C}html pre.shiki code .scsc5, html code.shiki .scsc5{--shiki-default:#4C4F69;--shiki-default-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic}html pre.shiki code .srhcd, html code.shiki .srhcd{--shiki-default:#8839EF;--shiki-default-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic}html pre.shiki code .sP4PM, html code.shiki .sP4PM{--shiki-default:#4C4F69;--shiki-default-font-style:inherit;--shiki-dark:#7FDBCA;--shiki-dark-font-style:italic}html pre.shiki code .s8apv, html code.shiki .s8apv{--shiki-default:#4C4F69;--shiki-default-font-style:inherit;--shiki-dark:#BAEBE2;--shiki-dark-font-style:italic}html pre.shiki code .sL4Ga, html code.shiki .sL4Ga{--shiki-default:#4C4F69;--shiki-dark:#BAEBE2}html pre.shiki code .sVS64, html code.shiki .sVS64{--shiki-default:#179299;--shiki-dark:#D6DEEB}",{"title":280,"searchDepth":294,"depth":294,"links":4312},[4313,4317,4318,4325],{"id":2679,"depth":294,"text":2680,"children":4314},[4315,4316],{"id":2690,"depth":323,"text":2691},{"id":2719,"depth":323,"text":2720},{"id":2768,"depth":294,"text":2769},{"id":2786,"depth":294,"text":2789,"children":4319},[4320,4321,4322,4323,4324],{"id":2823,"depth":323,"text":2824},{"id":2941,"depth":323,"text":2942},{"id":3662,"depth":323,"text":3665},{"id":3677,"depth":323,"text":3678},{"id":4128,"depth":323,"text":4129},{"id":2731,"depth":294,"text":4256},"2025-08-18","We propose D2Snap – a first-of-its-kind downsampling algorithm for DOMs. D2Snap can be used as a pre-processing technique for DOM snapshots to optimise web agency context quality and token costs.",{"homepage":945,"relatedLinks":4329},[4330,4334,4337],{"text":4331,"href":4332,"description":4333},"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":4335,"href":17,"description":4336},"What is a Web Agent?","Learn the basics of web agents",{"text":3934,"href":4338,"external":945,"description":4339},"https://dev.webfuse.com/automation-api#take_dom_snapshot","Check out the Webfuse Automation API",{"title":175,"description":4327},{"loc":174},"blog/1012.dom-downsampling-for-llm-based-web-agents",[2598,4344,4345,4346,2642,4347],"browser-agents","llms","llm-context","web-automation","lDh50lEtos4T_tIdGCLKDox16i6ixbPnRxPJoFpKjnE",{"id":4350,"title":18,"authorId":2648,"body":4351,"category":2598,"created":5065,"description":5066,"extension":2601,"faqs":2625,"featurePriority":294,"head":2625,"landingPath":2625,"meta":5067,"navigation":945,"ogImage":2625,"path":17,"robots":2625,"schemaOrg":2625,"seo":5076,"sitemap":5077,"stem":5078,"tags":5079,"__hash__":5080},"blog/blog/1011.a-gentle-introduction-to-ai-agents-for-the-web.md",{"type":8,"value":4352,"toc":5046},[4353,4367,4370,4377,4383,4387,4390,4405,4409,4419,4423,4427,4440,4444,4448,4451,4456,4460,4469,4473,4484,4489,4493,4511,4515,4521,4620,4623,4845,4861,4865,4868,4873,4877,4880,4884,4902,4927,4934,4938,4976,4979,4990,4994,4997,5025,5029,5037,5043],[11,4354,4355,4356,245,4360,249,4363,4366],{},"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 ",[15,4357,2661],{"href":4358,"rel":4359},"https://openai.com/index/introducing-operator/",[2358],[15,4361,2666],{"href":2664,"rel":4362},[2358],[15,4364,2671],{"href":2669,"rel":4365},[2358],". By now, it is within reach to automate arbitrary web-based tasks, such as booking the cheapest flight from Berlin to Amsterdam.",[30,4368,4335],{"id":4369},"what-is-a-web-agent",[11,4371,4372,4373,4376],{},"For starters, let us break down the term ",[55,4374,4375],{},"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.",[35,4378],{":width":4379,"alt":4380,"format":4381,"loading":39,"src":4382},"610","High-level agent description comparing human and computer agents","svg","/blog/a-gentle-introduction-to-ai-agents-for-the-web/1.svg",[47,4384,4386],{"id":4385},"the-role-of-frontier-llms","The Role of Frontier LLMs",[11,4388,4389],{},"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,4391,4392,4393,4400,4401,4404],{},"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 (",[2205,4394,4395,4396,4399],{},"“",[284,4397,4398],{},"..."," e4 e5 2. Nc3 f5”","), and the respective task (",[2205,4402,4403],{},"“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.",[47,4406,4408],{"id":4407},"generalist-web-agents","Generalist Web Agents",[11,4410,4411,4412,249,4415,4418],{},"Generalist web agents are supposed to solve arbitrary tasks through a web browser. Web-based tasks can be as diverse as ",[2205,4413,4414],{},"“Find a picture of a cat.”",[2205,4416,4417],{},"“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.",[35,4420],{":width":37,"alt":4421,"format":42,"loading":39,"src":4422},"Screenshot of a generalist web agent UI (Director)","/blog/a-gentle-introduction-to-ai-agents-for-the-web/2.png",[47,4424,4426],{"id":4425},"specialist-web-agents","Specialist Web Agents",[11,4428,4429,4430,4433,4434,4439],{},"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 ",[2205,4431,4432],{},"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 ",[15,4435,4438],{"href":4436,"rel":4437},"https://docs.claude.com/en/docs/build-with-claude/prompt-engineering/system-prompts",[2358],"system prompt"," can, moreover, be leveraged to drive specialist agent quality for the respective problem domain.",[35,4441],{":width":37,"alt":4442,"format":42,"loading":39,"src":4443},"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",[30,4445,4447],{"id":4446},"how-does-a-web-agent-work","How Does a Web Agent Work?",[11,4449,4450],{},"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).",[35,4452],{":width":4453,"alt":4454,"format":4381,"loading":39,"src":4455},"480","High-level web agent architecture component view","/blog/a-gentle-introduction-to-ai-agents-for-the-web/4.svg",[47,4457,4459],{"id":4458},"the-agent-lifecycle","The Agent Lifecycle",[11,4461,4462,4463,4468],{},"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 ",[15,4464,4467],{"href":4465,"rel":4466},"https://www.redfin.com",[2358],"redfin.com",": In the first step, you specify a location. Only subsequently are you provided with a grid of available apartments for that location.",[35,4470],{":width":37,"alt":4471,"format":42,"loading":39,"src":4472},"Example of separated UI states in a rental home search application","/blog/a-gentle-introduction-to-ai-agents-for-the-web/5.png",[11,4474,4475,4476,4483],{},"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 ",[15,4477,4480],{"href":4478,"rel":4479},"https://mitpress.mit.edu/9780262640374/the-design-of-everyday-things/",[2358],[2205,4481,4482],{},"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.",[35,4485],{":width":4486,"alt":4487,"format":4381,"loading":39,"src":4488},"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",[47,4490,4492],{"id":4491},"web-context-for-llms","Web Context for LLMs",[11,4494,4495,4496,4498,4499,4502,4503,4506,4507,4510],{},"The gap from an agent towards the environment, according to ",[2205,4497,4482],{},", is known as the ",[2205,4500,4501],{},"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 ",[2205,4504,4505],{},"gulf of intention"," towards the action planning stage: how to serialise a currently browsed web page's runtime state for LLMs? ",[2205,4508,4509],{},"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?",[47,4512,4514],{"id":4513},"agentic-ui-interaction","Agentic UI Interaction",[11,4516,4517,4518,4520],{},"With a qualified set of well-defined actuation methods, web agents are able to close the ",[2205,4519,4501],{}," 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:",[275,4522,4524],{"className":3708,"code":4523,"language":3710,"meta":280,"style":280},"interface ActuationSchema = {\n    thought: string;\n    action: \"click\"\n        | \"scroll\"\n        | \"type\";\n    cssSelector: string;\n    data?: string;\n}[];\n",[229,4525,4526,4539,4550,4565,4577,4589,4600,4611],{"__ignoreMap":280},[284,4527,4528,4531,4534,4537],{"class":286,"line":287},[284,4529,4530],{"class":649},"interface",[284,4532,4533],{"class":3719}," ActuationSchema",[284,4535,4536],{"class":513}," = ",[284,4538,291],{"class":290},[284,4540,4541,4544,4546,4548],{"class":286,"line":294},[284,4542,4543],{"class":513},"    thought",[284,4545,307],{"class":1040},[284,4547,3738],{"class":3737},[284,4549,739],{"class":290},[284,4551,4552,4555,4557,4559,4563],{"class":286,"line":323},[284,4553,4554],{"class":513},"    action",[284,4556,307],{"class":1040},[284,4558,311],{"class":310},[284,4560,4562],{"class":4561},"sgAC-","click",[284,4564,1062],{"class":310},[284,4566,4567,4570,4572,4575],{"class":286,"line":343},[284,4568,4569],{"class":1040},"        |",[284,4571,311],{"class":310},[284,4573,4574],{"class":4561},"scroll",[284,4576,1062],{"class":310},[284,4578,4579,4581,4583,4585,4587],{"class":286,"line":364},[284,4580,4569],{"class":1040},[284,4582,311],{"class":310},[284,4584,1421],{"class":4561},[284,4586,304],{"class":310},[284,4588,739],{"class":290},[284,4590,4591,4594,4596,4598],{"class":286,"line":384},[284,4592,4593],{"class":513},"    cssSelector",[284,4595,307],{"class":1040},[284,4597,3738],{"class":3737},[284,4599,739],{"class":290},[284,4601,4602,4605,4607,4609],{"class":286,"line":405},[284,4603,4604],{"class":513},"    data",[284,4606,3760],{"class":1040},[284,4608,3738],{"class":3737},[284,4610,739],{"class":290},[284,4612,4613,4615,4618],{"class":286,"line":421},[284,4614,713],{"class":290},[284,4616,4617],{"class":513},"[]",[284,4619,739],{"class":290},[11,4621,4622],{},"And a suggested actions response could, in turn, look as follows:",[275,4624,4626],{"className":277,"code":4625,"language":279,"meta":280,"style":280},"[\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",[229,4627,4628,4632,4636,4656,4675,4693,4697,4701,4720,4738,4757,4775,4779,4783,4802,4820,4837,4841],{"__ignoreMap":280},[284,4629,4630],{"class":286,"line":287},[284,4631,1356],{"class":290},[284,4633,4634],{"class":286,"line":294},[284,4635,788],{"class":290},[284,4637,4638,4640,4643,4645,4647,4649,4652,4654],{"class":286,"line":323},[284,4639,1451],{"class":297},[284,4641,4642],{"class":301},"thought",[284,4644,304],{"class":297},[284,4646,307],{"class":290},[284,4648,311],{"class":310},[284,4650,4651],{"class":314},"Scroll newsletter cta into view",[284,4653,304],{"class":310},[284,4655,320],{"class":290},[284,4657,4658,4660,4663,4665,4667,4669,4671,4673],{"class":286,"line":343},[284,4659,1451],{"class":297},[284,4661,4662],{"class":301},"action",[284,4664,304],{"class":297},[284,4666,307],{"class":290},[284,4668,311],{"class":310},[284,4670,4574],{"class":314},[284,4672,304],{"class":310},[284,4674,320],{"class":290},[284,4676,4677,4679,4682,4684,4686,4688,4691],{"class":286,"line":364},[284,4678,1451],{"class":297},[284,4680,4681],{"class":301},"cssSelector",[284,4683,304],{"class":297},[284,4685,307],{"class":290},[284,4687,311],{"class":310},[284,4689,4690],{"class":314},"section#newsletter",[284,4692,1062],{"class":310},[284,4694,4695],{"class":286,"line":384},[284,4696,615],{"class":290},[284,4698,4699],{"class":286,"line":405},[284,4700,788],{"class":290},[284,4702,4703,4705,4707,4709,4711,4713,4716,4718],{"class":286,"line":421},[284,4704,1451],{"class":297},[284,4706,4642],{"class":301},[284,4708,304],{"class":297},[284,4710,307],{"class":290},[284,4712,311],{"class":310},[284,4714,4715],{"class":314},"Type email address to newsletter cta",[284,4717,304],{"class":310},[284,4719,320],{"class":290},[284,4721,4722,4724,4726,4728,4730,4732,4734,4736],{"class":286,"line":618},[284,4723,1451],{"class":297},[284,4725,4662],{"class":301},[284,4727,304],{"class":297},[284,4729,307],{"class":290},[284,4731,311],{"class":310},[284,4733,1421],{"class":314},[284,4735,304],{"class":310},[284,4737,320],{"class":290},[284,4739,4740,4742,4744,4746,4748,4750,4753,4755],{"class":286,"line":624},[284,4741,1451],{"class":297},[284,4743,4681],{"class":301},[284,4745,304],{"class":297},[284,4747,307],{"class":290},[284,4749,311],{"class":310},[284,4751,4752],{"class":314},"section#newsletter > input",[284,4754,304],{"class":310},[284,4756,320],{"class":290},[284,4758,4759,4761,4764,4766,4768,4770,4773],{"class":286,"line":655},[284,4760,1451],{"class":297},[284,4762,4763],{"class":301},"data",[284,4765,304],{"class":297},[284,4767,307],{"class":290},[284,4769,311],{"class":310},[284,4771,4772],{"class":314},"user@example.org",[284,4774,1062],{"class":310},[284,4776,4777],{"class":286,"line":662},[284,4778,615],{"class":290},[284,4780,4781],{"class":286,"line":727},[284,4782,788],{"class":290},[284,4784,4785,4787,4789,4791,4793,4795,4798,4800],{"class":286,"line":732},[284,4786,1451],{"class":297},[284,4788,4642],{"class":301},[284,4790,304],{"class":297},[284,4792,307],{"class":290},[284,4794,311],{"class":310},[284,4796,4797],{"class":314},"Submit newsletter sign up",[284,4799,304],{"class":310},[284,4801,320],{"class":290},[284,4803,4804,4806,4808,4810,4812,4814,4816,4818],{"class":286,"line":1224},[284,4805,1451],{"class":297},[284,4807,4662],{"class":301},[284,4809,304],{"class":297},[284,4811,307],{"class":290},[284,4813,311],{"class":310},[284,4815,4562],{"class":314},[284,4817,304],{"class":310},[284,4819,320],{"class":290},[284,4821,4822,4824,4826,4828,4830,4832,4835],{"class":286,"line":1230},[284,4823,1451],{"class":297},[284,4825,4681],{"class":301},[284,4827,304],{"class":297},[284,4829,307],{"class":290},[284,4831,311],{"class":310},[284,4833,4834],{"class":314},"section#newsletter > button",[284,4836,1062],{"class":310},[284,4838,4839],{"class":286,"line":1262},[284,4840,1624],{"class":290},[284,4842,4843],{"class":286,"line":1291},[284,4844,1619],{"class":290},[2844,4846,4847],{},[11,4848,4849,4854,4855,4860],{},[15,4850,4853],{"href":4851,"rel":4852},"https://platform.openai.com/docs/guides/function-calling",[2358],"Function Calling"," and the ",[15,4856,4859],{"href":4857,"rel":4858},"https://modelcontextprotocol.io",[2358],"Model Context Protocol"," represent two ends to outsource an explicit actuation model – server- and client-side, respectively.",[47,4862,4864],{"id":4863},"agentic-ui-augmentation","Agentic UI Augmentation",[11,4866,4867],{},"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.",[35,4869],{":width":4870,"alt":4871,"format":4381,"loading":39,"src":4872},"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",[30,4874,4876],{"id":4875},"how-to-build-a-web-agent","How to Build a Web Agent?",[11,4878,4879],{},"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.",[47,4881,4883],{"id":4882},"develop-a-web-agent","Develop a Web Agent",[11,4885,4886,4887,4890,4891,249,4896,4901],{},"Opting for a ",[55,4888,4889],{},"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., ",[15,4892,4895],{"href":4893,"rel":4894},"https://elevenlabs.io/conversational-ai",[2358],"ElevenLabs",[15,4897,4900],{"href":4898,"rel":4899},"https://www.intercom.com/drlp/ai-agent",[2358],"Intercom",". Serviced agents hide LLM communication and potentially interaction with a web browser behind the configuration interface.",[11,4903,4904,4905,4908,4909,4914,4915,4920,4921,4926],{},"Using a ",[55,4906,4907],{},"templated agent"," resembles the agent-as-a-service approach on a lower level. Openly sourced from a ",[15,4910,4913],{"href":4911,"rel":4912},"https://github.com/webfuse-com/agent-extension-blueprint",[2358],"code repository",", templated agents allow for any kind of development tweaks. Favourably, agent templates shortcut integration with ",[15,4916,4919],{"href":4917,"rel":4918},"https://openai.com/api/",[2358],"LLM APIs"," and web ",[15,4922,4925],{"href":4923,"rel":4924},"https://developer.mozilla.org/en-US/docs/Web/API",[2358],"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,4928,4929,4930,4933],{},"Of course, developing an ",[55,4931,4932],{},"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.",[47,4935,4937],{"id":4936},"deploy-a-web-agent","Deploy a Web Agent",[11,4939,4940,4941,171,4946,4951,4952,4957,4958,4963,4964,4969,4970,4975],{},"When web agent code lives side-by-side with the augmented application's code, agent deployment is covered by a generic pipeline. Something like: ",[15,4942,4945],{"href":4943,"rel":4944},"https://eslint.org",[2358],"linting",[15,4947,4950],{"href":4948,"rel":4949},"https://prettier.io",[2358],"formatting"," agent code, ",[15,4953,4956],{"href":4954,"rel":4955},"https://esbuild.github.io",[2358],"transpiling and bundling"," agent modules, ",[15,4959,4962],{"href":4960,"rel":4961},"https://www.cypress.io",[2358],"testing"," agent, ",[15,4965,4968],{"href":4966,"rel":4967},"https://pages.cloudflare.com",[2358],"hosting"," agent bundle, and ",[15,4971,4974],{"href":4972,"rel":4973},"https://docs.github.com/en/actions/get-started/continuous-integration",[2358],"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,4977,4978],{},"Web agent source code right inside the application codebase comes at a cost:",[220,4980,4981,4984,4987],{},[190,4982,4983],{},"Agent developers can manipulate the source code of the underlying application.",[190,4985,4986],{},"Agent functionality could introduce side effects on the underlying application.",[190,4988,4989],{},"Agent changes require deployment of the entire application.",[47,4991,4993],{"id":4992},"best-practices-of-agentic-ux","Best Practices of Agentic UX",[11,4995,4996],{},"When designing user experiences for agent-enhanced applications, there are a few things to consider:",[220,4998,4999,5000,4999,5009,4999,5017],{},"\n    ",[190,5001,5002,5003,5002,5006,5008],{},"\n        ",[55,5004,5005],{},"Stream input and output to reduce latency",[4235,5007],{},"\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    ",[190,5010,5002,5011,5002,5014,5016],{},[55,5012,5013],{},"Provide fine-grained feedback to bridge high-latency",[4235,5015],{},"\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    ",[190,5018,5002,5019,5002,5022,5024],{},[55,5020,5021],{},"Always prompt the human user for consent to perform critical actions",[4235,5023],{},"\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    ",[47,5026,5028],{"id":5027},"non-invasive-web-agents-with-webfuse","Non-Invasive Web Agents with Webfuse",[11,5030,5031,5036],{},[15,5032,5034],{"href":3938,"rel":5033},[2358],[55,5035,3940],{}," 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.",[5038,5039],"article-signup-cta",{":demoAction":5040,"heading":5041,"subtitle":5042},"{\"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.",[2561,5044,5045],{},"html pre.shiki code .scGhl, html code.shiki .scGhl{--shiki-default:#7C7F93;--shiki-dark:#D6DEEB}html pre.shiki code .srFR9, html code.shiki .srFR9{--shiki-default:#7C7F93;--shiki-dark:#7FDBCA}html pre.shiki code .s30W1, html code.shiki .s30W1{--shiki-default:#1E66F5;--shiki-dark:#7FDBCA}html pre.shiki code .sbuKk, html code.shiki .sbuKk{--shiki-default:#40A02B;--shiki-dark:#D9F5DD}html pre.shiki code .sCC8C, html code.shiki .sCC8C{--shiki-default:#40A02B;--shiki-dark:#C789D6}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s76yb, html code.shiki .s76yb{--shiki-default:#8839EF;--shiki-dark:#C792EA}html pre.shiki code .sXbZB, html code.shiki .sXbZB{--shiki-default:#DF8E1D;--shiki-default-font-style:italic;--shiki-dark:#D6DEEB;--shiki-dark-font-style:inherit}html pre.shiki code .s2kId, html code.shiki .s2kId{--shiki-default:#4C4F69;--shiki-dark:#D6DEEB}html pre.shiki code .s9rnR, html code.shiki .s9rnR{--shiki-default:#179299;--shiki-dark:#7FDBCA}html pre.shiki code .scrte, html code.shiki .scrte{--shiki-default:#8839EF;--shiki-dark:#C5E478}html pre.shiki code .sgAC-, html code.shiki .sgAC-{--shiki-default:#40A02B;--shiki-default-font-style:italic;--shiki-dark:#ECC48D;--shiki-dark-font-style:inherit}",{"title":280,"searchDepth":294,"depth":294,"links":5047},[5048,5053,5059],{"id":4369,"depth":294,"text":4335,"children":5049},[5050,5051,5052],{"id":4385,"depth":323,"text":4386},{"id":4407,"depth":323,"text":4408},{"id":4425,"depth":323,"text":4426},{"id":4446,"depth":294,"text":4447,"children":5054},[5055,5056,5057,5058],{"id":4458,"depth":323,"text":4459},{"id":4491,"depth":323,"text":4492},{"id":4513,"depth":323,"text":4514},{"id":4863,"depth":323,"text":4864},{"id":4875,"depth":294,"text":4876,"children":5060},[5061,5062,5063,5064],{"id":4882,"depth":323,"text":4883},{"id":4936,"depth":323,"text":4937},{"id":4992,"depth":323,"text":4993},{"id":5027,"depth":323,"text":5028},"2025-06-15","LLMs only recently enabled serviceable web agents: autonomous systems that browse web on behalf of a human. Get started with fundamental methodology, key design challenges, and technological opportunities.",{"homepage":945,"relatedLinks":5068},[5069,5070,5074],{"text":4331,"href":4332,"description":4333},{"text":5071,"href":5072,"description":5073},"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":3934,"href":5075,"external":945,"description":4339},"https://dev.webfuse.com/automation-api/",{"title":18,"description":5066},{"loc":17},"blog/1011.a-gentle-introduction-to-ai-agents-for-the-web",[2598,4344,4345,2642,4347],"NE1cc8w1586RjefKyr028dgV7yBmf460jhZy91LninA",1775834759567]