Tasks that can move into a tab are those that never need to reach beyond these four doors; the ones worth moving are fewer still.
Whether an Agent can live in a browser depends on whether what it needs to do reaches beyond four doors: model, file, process, network. Today the first three each have something ready to open them, with conditions attached. The fourth door is the network, and the browser opens it only a crack: most pages made for humans can't be read, and TCP can't be reached. So a "pure web Agent" is, in engineering terms, local compute plus a very thin exit; once a task needs something from beyond that exit (git, ssh, databases, ordinary web pages, unattended runs), it can't move in. Beyond whether it can, there is whether it's worth it: what holds up is "execution in the browser, model in the cloud"; moving the model into the tab as well still falls short on coverage and capability.
showDirectoryPicker is Chromium-only (Chrome 86+); Firefox and Safari lack it, leaving only OPFS—which is not your disk. My page only reads on import, capped at 300 files, 4 MB; changes stay in memory first.In both runtimes, the Agent first ran tests using the page's built-in sandbox, hit an error, and only then switched to the real shell; the task description never mentioned Bash. The limiting factor isn't whether it knows how to use tools—it's whether the page exposes the real tools.
What I worried about first wasn't speed. A pure-web Agent modifying your local project directory sounds like it should be blocked dead by the browser's security model: why should a webpage read your disk, run a shell, or fetch dependencies over the network?
From October 14 to 20, I built two pages to dismantle that suspicion. They share the same Claude Code–style Agent shell: read/write files, confirm before writing, run tests, self-verify after changes. The only difference is the runtime behind the Bash tool. The first page uses StackBlitz's WebContainers, the second uses the open-source Wasmer, each adding only ~100 lines of code. The model is BigModel's glm-5.3 (in those days its API could still be called directly from a web page; see § 02).
Conclusion first: the security model doesn't block it dead. The browser gives file a key, process a key—each with conditions. What truly blocks it is the fourth thing: network.
Answer first, then how I measured. "Evidence" column: tested means I or a session I dispatched ran it by hand; docs means from official documentation; inferred means untested, derived from the first two.
| Task | Can it run in a tab? | Evidence |
|---|---|---|
| Read your project directory, write changes back | Chromium yes; Firefox/Safari degrade to an in-memory blank workspace | Docs. I haven't automated the full authorize-read-write path (can't click system dialogs) |
| Fix a bug in a pure JS project, run unit tests | Yes | Tested, one glm-5.3 task per runtime; on October 28 I ran two more passes each with a local gemma4, and re-ran the tests in host Node: 5/5 |
| Install npm dependencies and run tests | WebContainers yes; Wasmer requires you to provide a relay, and only pnpm works | Tested |
| Call GitHub, npm, PyPI, Wikipedia APIs | Yes | Tested (CORS allows) |
| Read an ordinary news or documentation webpage | Mostly no | Tested, 19 of 31 URLs lack allow headers |
| git commit, push | No, neither runtime has git | Tested |
| ssh, connect to a database | No | Docs + inferred: browser has no TCP |
| Run a Python script | Wasmer yes (Python 3.13, ~22 s first time); WebContainers has only RustPython alpha | Tested; scientific computing libs not tested |
| Unattended, run overnight | No: close the tab and it stops; a background tab can also be frozen after 5 minutes | Docs (Chrome 133's freezing rules) plus inference; not tested |
| Thousands of files, project needing native compilation | No | Page import cap 300 files, 4 MB; neither runtime has gcc |
Every row ultimately lands on one of the four doors. Let's go through them one by one.
An Agent working in the browser thinks on a remote model. The first question is whether the page can call it directly.
I used curl to impersonate a page from roam.xiaopingfeng.com, sending one preflight request to each of 14 model interfaces, then a POST with a fake key, checking whether the error response includes an allow-origin header. The script and raw output are in this text file. On October 20 all 14 preflights passed; on October 28 I re-ran the same script and one thing had changed, and two other details are worth noting.
What changed is BigModel. The /chat/completions preflight at open.bigmodel.cn now returns 200 but carries no Access-Control-Allow-* header at all, even for a preflight that asks only for authorization or only for content-type; three runs in a row gave the same result, and in Chrome a POST with a JSON body fails straight away with "Failed to fetch". /models on the same site still passes, and both paths on the international site api.z.ai pass too. All my real-model tests with BigModel between October 15 and 20 worked, so this changed within the week; I did not contact them to ask whether it is temporary or permanent. The configuration examples in both my pages happen to use BigModel, so they most likely cannot connect now. The point is plain: for this door the switch is in the API provider's hands, one gateway config change on their side and a pure web Agent can no longer reach them, so a page where users bring their own key should support several providers.
Anthropic's interface won't return an allow-origin in the preflight unless you declare the anthropic-dangerous-direct-browser-access header; once declared, it returns a wildcard, and the 401 for the fake key also carries the header. The header name says it all: they allow it, but want you to explicitly acknowledge the risk. Volcengine's preflight passes, but the error response lacks CORS headers—when the page sends a bad key, the browser only reports an opaque network error, unable to read the 401. Debugging such interfaces is the hardest. The remaining eleven either echo my domain or return *.
Passing only answers whether you can call it. The page stores the API key in this domain's localStorage; requests go directly from the browser to the address you filled in, not through the site—meaning anything that can execute scripts under this domain (a poisoned dependency, an extension) can read it.
Local models are another story. WebLLM does inference in the browser; the page code limits it to 14 core tools with a 4–8k context. Ollama by default doesn't allow cross-origin calls; you must set OLLAMA_ORIGINS on the server. In my October 15 tests, qwen2.5:7b could follow the action format but would fabricate an "observation result" after the action, claiming completion without verification—couldn't build Snake. gemma4:31b produced a playable version in 44 s; glm-5.3 at its default deepest reasoning level took 246 s for the same Snake, dropping to 45 s at low.
So the condition for this door is: you're willing to send code snippets to some model API and the provider hasn't shut off direct browser access, or you have a ~30B-class model locally. I haven't run real inference on WebLLM.
The browser lets a webpage read/write your real disk via the File System Access API's showDirectoryPicker. The rules are specific: only available under HTTPS; must be triggered by a user gesture like a click; you pick which directory, and the page only gets that directory; directories the browser deems too sensitive are refused (Chrome's docs give Windows and macOS system library directories as examples); writes require another authorization prompt; once all same-site tabs close, the permission is lost.
So my initial suspicion was wrong on the file front. This mechanism was designed for exactly this use case.
The blocker is elsewhere: compat data shows showDirectoryPicker is Chrome 86+ only; Firefox and Safari don't support it. The latter two have OPFS (Firefox 111+, Safari 15.2+), but that's a private space the browser allocates per site—not a folder on your desktop. In other words, "working on your local project" holds only in Chromium; in other browsers it degrades to a from-scratch in-memory workspace.
My page adds two further restrictions. When opening a folder it only reads on import—max 300 files, 200 KB each, 4 MB total—skipping node_modules, .git, dist directories; the Agent's changes stay in memory first, and only when you type /save does it request write permission to flush to disk. Both runtimes' file systems are virtual anyway, so before and after each Bash command, the page syncs the workspace in and syncs changed text files back out.
One thing I haven't verified on this front: the full authorize-read-write path, because the picker is a system dialog I can't automate.
This door is the hardest, and the fastest-changing.
The threshold first. Running a proper runtime in the browser requires multithreading, which requires SharedArrayBuffer, which is only available to cross-origin-isolated pages: the response headers must include Cross-Origin-Opener-Policy: same-origin plus Cross-Origin-Embedder-Policy set to require-corp or credentialless (see MDN). For a static site, this means configuring headers for the specific page path: roam is deployed on Cloudflare Pages, and I enabled them in _headers for only two paths, leaving other pages untouched.
I chose credentialless, because require-corp blocks third-party images in previews that lack CORP headers (discovered in another session). The cost is in the compat data: credentialless is Chrome 96+, Firefox 119+; Safari doesn't support it. WebContainers' own docs say desktop Chromium works out of the box; Safari and Firefox are still beta. So this door, too, is effectively Chromium's.
The two runtimes side by side:
| WebContainers | Wasmer | |
|---|---|---|
| Where's the runtime | StackBlitz-hosted, loaded from their domain, closed-source | SDK served same-origin with the page (~5 MB); bash, Node, etc. downloaded from Wasmer's package repo on first use |
| What's inside | Node 22, npm | bash, Node 24 (Edge.js), pnpm, Python 3.13 loaded on demand |
| Cold start | 27.2 s (1 sample); other samples 7–8 s; online I measured 15.1 s | 27–38 s (~89 MB); Python another ~22 s |
| Warm start | 0.34–0.68 s | 0.66 s |
| Network install | Works out of the box | Requires your own WISP relay; only pnpm works |
| Real glm-5.3 fixing cart | 29 s | 61 s, incl. 34.4 s cold start |
These numbers have very small samples—WebContainers' cold start column has only one or two—so don't treat them as benchmarks. The cart is a small project with three bugs (reduce missing initial value, price not zero-padded, discount returning the discount amount); the WebContainers column comes from another Claude Code session's report.
More interesting than the numbers is the Agent's behavior. In both real tasks, it first called the page's built-in sandbox Test, got test is not a function, read the test file, then switched to Bash to run node --test. That error was a page bug: my sandbox returned an object without a default export for the standard import test from 'node:test'. The task description never mentioned Bash; the system prompt included the tool, but it only used it after hitting the error. It switched, fixed all three, re-ran, 5/5 passed. I exported the Wasmer session's workspace and ran the original tests in real Node—5/5, test file unchanged.
On the flip side, each runtime has a string of pitfalls, which ultimately become one line in the tool description and a guard. Wasmer pitfalls I hit:
node --test default mode reports "serializer payload is no longer available"; must use --test-isolation=none. The page now adds this automatically.node x.js | tail gives empty output, but echo hi | cat works fine. Tool description now says "don't pipe node's output."npm install fails with "https protocol not supported"; only pnpm works, and needs a .npmrc.timeout_ms can fail: the SDK's built-in timeout waits for a blocking guest call (e.g., sleep 30) to return before taking effect. A 3-second-limited command once took 30 s. The page now times independently and force-kills at the deadline—discovered while running the batch below, now fixed.The shared gaps in both runtimes are even more worth noting: no git, no grep, sed, awk, find. File search is covered by the page's Grep and Glob tools, but git commit has no substitute. In WebContainers, native modules install but fail at require with ERR_DLOPEN_DISABLED—installable doesn't mean usable.
I later wrote these "can it or can't it" checks as 11 tasks, running them via the same interface (boot / put / exec) against WebContainers, Wasmer, and a temporarily deployed Cloudflare Sandbox. The two browser columns ran the real Bash tool from the online page; the cloud column used the official minimal example's default lite instance, with the image swapped to a Debian with git, Python, and build tools, outbound network enabled—deleted the Worker, container app, and image after testing. Each column ran only once—not benchmarks; task scripts, adapters, and raw results are in this text file.
| Task | WebContainers | Wasmer | Cloud lite |
|---|---|---|---|
| node:test red→green (3 bugs) | ✓ | ✓ | ✓ |
| Install pure JS dep then require | ✓ npm | ✓ pnpm, needs relay | ✓ |
| git init / commit / log | ✗ no git | ✗ no git | ✓ |
| grep / sed / awk / find | ✗ all missing | ✗ all missing | ✓ |
| Install native module (better-sqlite3) and call it | ✗ installs, load disabled | ✗ no loadable binary | ✓ ~37 s |
| Python run script, import sqlite3 | ✗ has python3, missing _sqlite3 | ✓ Python 3.13 | ✓ Python 3.11 |
| Outbound HTTPS to non-CORS site | ✗ socket closed | ✓ via self-provided relay | ✓ |
| node as pipe upstream | ✓ | ✗ empty output | ✓ |
| Timeout force-kill: node spins 30 s, limit 3 s | ✓ 3.1 s | ✓ 3.8 s | ✓ 3.1 s |
Timeout force-kill: shell sleep 30 | ✗ no sleep in jsh | ✓ 3.0 s | ✓ 3.3 s |
| Iterations in 3 s spin loop | 120 M | 18 M | 1.6 M |
| Cold start | 7.5–7.7 s | 27–34 s | 9–13 s |
Warm command (echo) | ~105 ms | ~58 ms | 150–615 ms |
The two browser runtimes and the cloud are identical at the "run Node, run tests, install pure JS packages" layer: red-green tests are 4 fail 1 pass before, 5 pass after, across all three. The difference is tooling: git, grep, etc., and native modules work in the cloud but in neither browser runtime. This is the same story as the § 01 decision table rows—now every row has results from the same batch of tasks.
Two things surprised me. First, outbound network: fetch('https://example.com') fails directly in WebContainers, but Wasmer with my self-provided relay succeeds, and the cloud works natively—consistent with § 05: whoever controls the egress decides what you can read. Second, compute: same 3-second spin loop, WebContainers ran ~120 M iterations, Wasmer ~18 M, cloud lite ~1.6 M. Browser Node uses your machine's CPU, much faster than the cloud lite instance's default tier; Wasmer is ~7× slower than WebContainers—reason uninvestigated. Don't read the cloud column as "all cloud is this slow"—I didn't try larger instances. Cold start order flips: cloud 9–13 s, faster than Wasmer's 27–34 s, but each command adds a network round trip: warm command 150–615 ms vs. 58–105 ms in the browser.
"Computation is on your machine"—I measured this too, not just trusting docs: had both runtimes run a 16-second spin loop while sampling CPU every 2 s with top, summing processes whose names start with the browser app name (main process, renderer processes). Idle: 12–23%; during loop: 53–67%; after: 13–32%; one renderer process alone hit ~40–49% during the loop. If commands ran remotely, there'd be no such swing. This measurement is noisy: on the first try, WebContainers' idle baseline was over 100%, so I re-ran; what's written here is the re-run, one trial per runtime. It only shows the computation happened on this machine—I didn't packet-capture to prove there was no other traffic.
One more pitfall, visible only after disabling cross-origin isolation. My page hides the Bash tool when headers are absent, but using Wasmer's SDK directly, an unisolated page doesn't error either: run() returns success, exit code 0, empty stdout and stderr, 22 ms—command never ran; same code on an isolated page outputs hi. Anyone using it for integration tests would get an all-green empty result.
Network has two layers. The first is HTTP, governed by CORS: a page can only read sites that explicitly state "allow this origin" in their response headers.
Again using curl to impersonate a page, I tested 31 public URLs (raw output in the same text file), biased toward sites developers frequent—not a random sample.
| Result | Count | Examples |
|---|---|---|
| Allowed | 11 | GitHub raw, GitHub API, npm registry, PyPI JSON, jsDelivr, unpkg, Wikipedia REST, Hacker News API, Hugging Face API |
| Only allows own domain | 1 | Damai |
| No allow headers | 19 | github.com pages, Wikipedia pages, MDN, Python docs, arXiv, BBC, Zhihu, Juejin, 36Kr, Baidu, Douban; Reddit, Stack Overflow, New York Times return 403 directly |
The pattern is clear: machine-readable endpoints mostly allow; human-readable pages mostly don't. Broken down by nature: 10 of 12 machine-readable endpoints allow; only 1 of 19 human-readable pages does. Same Hugging Face: API allows, model page doesn't. Same Wikipedia: REST API allows, article page doesn't. Another session saw the same in WebContainers: curl and fetch inside the container fail for Damai and Xiudong, but npm registry works.
For an Agent, the consequence is it can call APIs, read doc repos, and pull packages—but most pages you'd ask it to "look up online" are unreadable. My page has a WebFetch tool that defaults to asking you per domain, only reading CORS-open sites; you can manually enable a reader proxy (r.jina.ai) to bypass this, at the cost of the proxy seeing which URLs you read.
The second layer is TCP, which the browser simply doesn't have. npm install, ssh, database connections all need TCP. The two runtimes handle it differently: WebContainers relies on StackBlitz's proxy service; Wasmer requires you to provide a WISP relay—a small service that converts WebSocket to TCP.
I spent considerable time on this. Without a relay, npm install just hung—60 s with no output and no error. With a local relay started, pnpm add still failed, showing only ECONNRESET in the guest. The clue was finally in the relay's log: refusing to create a stream. The reason: my machine's DNS returns fake IPs (198.18.x.x, common with proxy software), and the relay defaults to rejecting this range as private. After adding allow_private_ips, pnpm add is-odd took 4.4 s, pnpm add -D mocha@10 ~12 s; mocha went 2 pass 3 fail, then after code changes 5 pass. TLS is completed inside the guest; I verified the handshake with tls.connect, negotiating TLSv1.2—so the relay sees only the target host, port, and ciphertext.
Three things to lay out here. The relay is a server—so "pure webpage" is no longer pure at this step. A relay that allows private network ranges is essentially a jumpbox to your internal network on the local machine; I haven't verified whether it restricts by originating page, so I only enable it during testing and shut it down after. Also, the WISP client library @mercuryworkshop/wisp-js is licensed AGPL-3.0, so I didn't put it in the repo; the page only loads it from jsDelivr when you configure a relay. Whether this handling is sufficient, I haven't had anyone confirm.
Browser vendors have thought about it: Chrome has a Direct Sockets API letting pages open TCP and UDP, but only for Isolated Web Apps—installable apps with strict content security policies—not ordinary web pages. When an Intent to Ship was filed in 2024, Gecko took no position, WebKit sent no signal; I haven't checked the 2026 status.
People asking this usually want to know if there's a standard. At the browser layer, there isn't. What has standards are the pieces underneath: File API (not yet Baseline), cross-origin isolation, WebAssembly. Above that, every runtime is one company's product:
@webcontainer/api package is labeled MIT, only 35 KB—it's a client shell. boot() inserts a hidden iframe pointing to stackblitz.com; the real runtime loads from there. The webcontainer-core repo on GitHub has a README stating it's just an issue tracker. Production commercial use requires a license; prototypes and POCs don't; self-hosting is enterprise-only. I read all this because the MIT label easily makes you think the whole thing is open source.The most widely used Agent sandboxes in the industry aren't in the browser. A May 2026 Agent sandbox inventory divides solutions into hosted sandboxes (E2B and Vercel Sandbox use Firecracker micro-VMs; Cloudflare uses V8 isolates + containers), local OS-level sandboxes (macOS Seatbelt, Linux Landlock, bubblewrap), and sandboxes built into Agents: Codex CLI and Claude Code are this type. E2B is Apache-2.0, ~14 k stars. The browser route is a small slice in this picture, with only two selling points: zero install, and code never leaves your machine (model API calls excepted).
Another article of mine measured how open the server side is to Agents: Which service is truly Agent native. Read together, my takeaway is: how far an Agent can go depends on whether the other side has left a machine-usable path that doesn't require human intervention. The server side lacks this path; so does the browser.
The first six sections measured whether it can. Whether it can and whether it is worth it are two different questions: something can run and still nobody wants to pay for it. This section asks the second.
I looked in three directions: products and the market, on-device models and the browser platform, and standards and risks (including the counter-arguments). I went back to the source data for the key numbers: the npm and GitHub APIs, the BFCL data table, the two browser vendors' position issues, and the authors' own posts. Whatever I couldn't check is marked in the text as vendor claim or secondhand.
First, take it apart. "An Agent living in the browser" can mean four different things, and the evidence for each differs a lot:
Execution in the tab, model left in the cloud: the only one that has been validated, and it has clear limits. bolt.new is the textbook case. Its open-source repo says generated code runs in the browser on WebContainers; its CTO told PostHog that people assume they run a server farm when in fact "the server is your browser": most similar products start a cloud container per session and pay for cold starts, network round trips and per-user cost, and Bolt has none of that. The scale numbers are all secondhand: Sacra estimates it launched in October 2024, reached about $40 million in annualized revenue in March 2025, and had a gross margin of about 40% in May 2025; after March 2025 I found no new public number, so do not extrapolate. A 40% margin suggests the sandbox it saves is not the biggest cost; the bulk should be model tokens. That is my inference; Sacra does not break it down.
On cost, the hardest number I could find is old. StackBlitz's co-founder told TechCrunch in 2022 that 2 million developers a month were using it and the AWS bill was only a couple of hundred dollars, because the compute was offloaded to the browser. That was an IDE, not an Agent. What I measured is the other side of the same thing: the same 3-second busy loop from § 04 ran about 120 million iterations on WebContainers, against about 1.6 million on the cloud instance from the official minimal example. Compute in the browser uses your own CPU and costs the platform nothing.
The limits are written by the vendors themselves. Bolt's supported-technologies page says that on desktop Chrome and other Chromium browsers are the main target, Safari works but differs (the code view is read-only and the preview is built on a host); only JavaScript backends are supported, and Python and PHP are not compatible. WebContainers' browser support page says Safari and Firefox are still in beta, and its troubleshooting page says native extensions are disabled by default and opening several projects at once can exhaust browser memory. The steadiest foothold is not Agents at all but interactive sandboxes embedded in docs: the official Angular and Svelte tutorials both say they are powered by WebContainers (Angular v17 announcement, SvelteKit 1.0 announcement; these are claims from the announcements, which this article did not check against the original pages).
Counter-evidence is at this layer too. CodeSandbox's co-founder replied on GitHub in November 2025 to the question of whether running Node in the browser is a dead end: he thinks it is still a valid and interesting space, but all of CodeSandbox's revenue comes from its VM product, mainly the part serving AI agents and text-to-app builders, so the browser-side Sandpack has had less attention. In the same issue, a shutdown notice posted in March 2026 says Sandpack is no longer actively maintained (I could not find the original page). He did not say the browser route fails technically; he said the people paying are elsewhere. The npm numbers say the same:
Over the same window (2026-09-27 to 10-26), among cloud sandbox SDKs @vercel/sandbox had about 21.76 million, e2b about 7.66 million and @daytonaio/sdk about 2.58 million; among in-browser SDKs @webcontainer/api had about 540,000, @mlc-ai/web-llm about 450,000 and @wasmer/sdk about 28,000 (data from npm's download API, same path for the other packages). Read with care: downloads include CI and server-side use and do not equal end users, and @vercel/sandbox may be pulled in indirectly by templates. All you can read is that the scale differs by one to two orders of magnitude, and that both sides are growing: @webcontainer/api went from about 110,000 in January 2025 to about 470,000 in September 2026, and e2b from about 97,000 to about 7.31 million over the same period. On the other hand, I found no product that shut down because running in the browser proved infeasible; Bolt's own move was to fall back to a hosted preview in Safari and to add Bolt Cloud (hosting, database, edge functions) in 2025.
Put the Agent loop in the tab too: no backend, but no evidence of usage. My two pages are this kind: no backend, one link is one Agent, and the user brings the key. The closest public example is Leaning Technologies' BrowserCode, which uses BrowserPod to run unmodified Claude Code and Codex CLI in the browser; it is Apache-2.0 with 148 stars; its Show HN scored 6, and another Show HN about compiling Codex CLI to WASM scored 5. That shows it is feasible; it does not show anyone wants it. My own two pages are the same: no analytics, and I do not know how many people have used them.
The "zero cost" of this kind is more often achieved by passing the bill to the end user than by moving compute onto their device. Claude artifacts let an app in the page call Claude with the usage charged to the user's own subscription (official post); Puter.js lets the user's quota pay, with zero cost to the developer (Puter developer page). Cost shifting is a validated mechanism; what is shifted is just not necessarily compute.
This kind has two more bills. One is the key sitting in the page, from § 02. The other is the tab's lifecycle: since Chrome 133, with Energy Saver on, a tab group whose pages have all been hidden and silent for more than 5 minutes is frozen when a same-origin subgroup is judged CPU-intensive; the official advice is to move background work to a Service Worker, but an extension's Service Worker is reclaimed after 30 seconds idle (that page was last updated in 2023). An Agent loop that only waits on network replies is probably not CPU-intensive, while local inference is at risk, and there is no official threshold for the judgment. That is my inference; I did not test it. So it suits interactive sessions where you are present, not something you leave running for half an hour.
Put the model in too: the most imaginative layer, and the one with the weakest evidence.
Coverage is narrow to begin with. Chrome's built-in model interface, the Prompt API, reached web pages with Chrome 148 in May 2026, on desktop only; Chrome's documentation says Android and iOS are not supported and it requires more than 4 GB of VRAM or 16 GB of RAM and at least 22 GB of free disk. WebKit's position on it is oppose and Mozilla's is negative. Then the users: by page views, StatCounter puts phones at about 60% in September 2026.
The only public live-product data point I found is SendCheckIt, a small tool that suggests alternative email subject lines, using Chrome's built-in Gemini Nano and falling back to a hosted Gemma when it is unavailable. As of January 2026, of 836 users 340 met the conditions (Chrome 138 or later, desktop, English), 40.7%, and about a quarter of those already had the model ready; per generation, Gemini Nano locally took a median of 7.7 seconds and the hosted Gemma about 1.3 seconds. The author removed the built-in model in September 2026, reasoning that maintaining two inference paths for about 40% of users was not worth it. This is one site, one task, English only, and the author's own account, but it is the closest thing to a real adoption rate I could find.
On capability, a small model that can call a tool is not the same as one that can finish the job. On the BFCL V4 leaderboard (the page says updated 2026-04-12), Qwen3-8B scores 42.57% overall, 41.75% on multi-turn and 12.00% on web search; the top entry, Claude Opus 4.5, scores 77.47%, 68.38% and 84.50%. The newer small models of 2026 (Qwen3.5, Gemma 4) are not on that board and their numbers are all vendor self-reports; the two vendors' self-reported 4B-class scores on the same τ² benchmark differ by nearly a factor of two (79.9 versus 42.2), so they cannot be compared directly. Chrome itself still has no usable native tool calling: function calling is still "Proposed" on chromestatus.
On cost, what gets "moved to the user's device" is a very small sum. On Google's pricing page, Gemini 2.5 Flash-Lite costs $0.10 per million input tokens and $0.40 per million output tokens. With my assumed 4,000 input and 500 output tokens per step, a step costs about $0.0006 and a ten-step Agent task about 0.6 cents (no caching, and a longer context would cost more). That is the order of magnitude saved, not the price of a flagship model.
What the evidence actually supports is a hybrid. Chrome's documentation recommends "built-in model plus cloud fallback" (Firebase AI Logic); NVIDIA's 8B orchestrator scored high on τ²-bench by dispatching stronger models, and the result depends on those stronger models rather than the 8B alone (paper). Small models built for browser operation are also improving: Microsoft self-reports Fara1.5 at 4B and 9B scoring 57.3 and 63.4 on Online-Mind2Web, with MIT-licensed weights (paper); but that is self-reported, depends on screenshot input, and I found no one who has run it in a browser.
Two points often used to sell it hold in a narrower range than claimed.
Security: an Agent in the browser cannot reach ~/.ssh or environment variables, and that is real. Local CLI Agents have been borrowed that way: in the August 2025 Nx supply-chain attack, malicious scripts called the AI CLIs already installed on the victim's machine to enumerate wallet and key files, and several security vendors have written it up (The Hacker News, StepSecurity). But a sandbox protects the host, not the data the Agent handles: when Google's Paul Kinlan wrote "The Browser Is the Sandbox" he himself said file contents are still sent to a third-party model and the model can still be induced to leak them. Prompt injection is not the sandbox's job either; Chrome's security guidance leaves input and output validation, origin restrictions and user confirmation to the Agent and the site. On which is safer, an Agent in the browser or a local CLI Agent, I found no head-to-head empirical data, only reasoning about mechanisms.
Privacy: "data never leaves the device" holds only for local inference. With local orchestration and a cloud API, file contents are still sent to a third party; and local inference is exactly the weakest layer above. I found no verified institution using local inference in a tab as its compliance approach. Cisco's 2026 privacy benchmark study (more than 5,200 respondents) says 81% report that generative and agentic AI has raised localization demands, but what it quantifies is country- and region-level data residency; it did not ask about on-device inference.
The other direction, where the page hands its tools to an Agent: still only a preview. WebMCP is not an Agent living in the page; it is the page declaring to an Agent what it can do, and I wrote up its background in another article. As of now: the spec is a W3C community group draft, not on the standards track; Chrome 149 and Edge 150 are running an origin trial; WebKit clearly opposed it on June 11, 2026, with reasons that include there being no consent and undo model for operations with side effects; Mozilla set its position to neutral on August 5. If it lands, the page becomes the server and uses your already-logged-in session, and an Agent no longer has to operate pages by screenshot; but today it is not a stable feature, and it does not by itself let an Agent live in a tab.
My judgment.
On the quality of evidence in this section: the scale numbers almost all come from vendor claims or aggregator sites, with no independent third party; the counter-arguments almost all come from vendors selling alternatives, and I found no clearly attributed non-vendor piece; I found no public measurement of the power and heat of in-browser inference; and there is no reliable statistic for the share of devices that meet Gemini Nano's threshold.
My own practice: browser-based Agents are good for demos, zero-install trials, small front-end projects, and teaching; for real work repos, I still run Claude Code locally.
Unverified:
cart.test.js was not changed; the Agent took about 38 and 40 seconds on WebContainers and about 27 and 56 seconds on Wasmer.Things that would rewrite this article's conclusions:
showDirectoryPicker, or Direct Sockets ships beyond Isolated Web Apps. Then the conditions on the file and network doors would change.Next step I want to take: fix that batch of tasks so every runtime version upgrade triggers a re-run—more reliable than me hand-writing "tested" each time; the table above is the first run's results. Also want to add two things: verification in Safari (requires manually opening the page), and larger cloud instances.