Skip to main content
← DeepDive Agents & Models · v3 Updated 2026-10-29 中文
DEEPDIVE / [Agent Engineering] · When Can an Agent Live in the Browser · Hot Topic DD · 2026-10-20 · v3 · First-hand test log + official docs and browser compatibility data + value research (read 2026-10-20 to 10-28)
A tab needs model, file, process, and network to work. I measured all four doors: the first three push open, the fourth is only cracked. Then I asked whether it is worth it: what holds up is the layer where execution runs in the browser and the model stays in the cloud.

When Can an Agent Live in the Browser

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.

DeepDive · Agent Engineering  |  Model, File, Process, Network — the Four Doors  |  Two Runtimes, One Agent Shell
13 / 14
Model interface preflight passes / tests
(re-tested 10-28; 10-20 was 14 / 14)
11 / 31
Public URLs allowing cross-origin reads
/ tests
29 s · 61 s
Same bug-fix task:
WebContainers · Wasmer
0
Working git in either runtime
TL;DR / 30 s

Four doors,
the first three push open

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.

#
Key Point
Details
01
Model:
On October 20 I tested 14 model interfaces and every preflight passed; on October 28 I re-tested, and BigModel alone no longer returns the allow-origin header while the other 13 are unchanged. The switch for this door is in the API provider's hands. Anthropic only allows it if the request declares a header saying "I know this is risky"; Volcano Ark's error responses carry no CORS header, so the page can't read the 401. Local small models are another matter: 7B ones invent their own "observation results."
02
File:
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.
03
Process:
The gate is cross-origin isolation. Same Agent shell, same 3-bug task: fixed in 29 s on WebContainers, 61 s on Wasmer (34 s of that is cold start). Neither has git. I then ran 11 tasks against a cloud sandbox: red-green tests and pure JS deps work the same across all three; git, grep, and native modules work only in the cloud.
04
Network:
Of 31 public URLs, only 11 allow cross-origin reads. The pattern: machine-readable endpoints allow it; human-readable pages don't. TCP requires a relay; Wasmer's relay client is AGPL, and the relay can see which hosts you connect to.
05
Who controls the runtime:
WebContainers' runtime is hosted by StackBlitz; the SDK is MIT but the runtime isn't in the package. Wasmer is open source; SDK is still alpha. There's no browser-level standard—standards exist only underneath: File API, cross-origin isolation, WebAssembly.
06
Worth it:
It depends on which layer you put in the browser. Execution only, with the model in the cloud, has been validated by products like bolt.new, though their own docs limit it to JS backends and Chromium; put the model in the tab too, and one live product measured only 40.7% of users meeting the conditions, with a local median of 7.7 s against 1.3 s hosted, and its author pulled it; WebMCP is still a preview and WebKit opposes it. Monthly npm downloads of cloud sandbox SDKs are one to two orders of magnitude higher than those of in-browser SDKs.
Counter-intuitive · Where to really watch

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.

Opening / Suspect the Security Model First

What I suspected first
was the security model

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.

§ 01 / Decision Table

Which tasks
can move in

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.

TaskCan it run in a tab?Evidence
Read your project directory, write changes backChromium yes; Firefox/Safari degrade to an in-memory blank workspaceDocs. 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 testsYesTested, 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 testsWebContainers yes; Wasmer requires you to provide a relay, and only pnpm worksTested
Call GitHub, npm, PyPI, Wikipedia APIsYesTested (CORS allows)
Read an ordinary news or documentation webpageMostly noTested, 19 of 31 URLs lack allow headers
git commit, pushNo, neither runtime has gitTested
ssh, connect to a databaseNoDocs + inferred: browser has no TCP
Run a Python scriptWasmer yes (Python 3.13, ~22 s first time); WebContainers has only RustPython alphaTested; scientific computing libs not tested
Unattended, run overnightNo: close the tab and it stops; a background tab can also be frozen after 5 minutesDocs (Chrome 133's freezing rules) plus inference; not tested
Thousands of files, project needing native compilationNoPage 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.

FIG 1 · A tab's four doorsTabYour page+ Agent① Model13/14 interfaces passModel APIor local OllamaOpen, provider holds the switchBigModel closed it 10-28② FileChrome 86+ onlyYour project dirone authorization at a timeFirefox / Safari lack itOPFS is not a real disk③ Processneeds cross-origin isolationWebAssembly runtimebash · Node · PythonNeeds COOP + COEP headersNeither has git④ Network11/31 pass · No TCPPublic APIs & pagesnpm · ssh · databasesOnly a crack: needs relayCan't read most pagesOpenOpen, with conditionsOnly a crack
Fig 1 · Door states from § 02–§ 05 tests and doc checks; model interfaces scored 14/14 on 10-20 and 13/14 when re-tested on 10-28, and 11/31 is the 10-20 measurement, all preflight and GET tests using curl impersonating a page · Source: author's tests; MDN compat data
§ 02 / Model

Door one:
Model

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.

§ 03 / File

Door two:
File

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.

§ 04 / Process

Door three:
Process

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:

WebContainersWasmer
Where's the runtimeStackBlitz-hosted, loaded from their domain, closed-sourceSDK served same-origin with the page (~5 MB); bash, Node, etc. downloaded from Wasmer's package repo on first use
What's insideNode 22, npmbash, Node 24 (Edge.js), pnpm, Python 3.13 loaded on demand
Cold start27.2 s (1 sample); other samples 7–8 s; online I measured 15.1 s27–38 s (~89 MB); Python another ~22 s
Warm start0.34–0.68 s0.66 s
Network installWorks out of the boxRequires your own WISP relay; only pnpm works
Real glm-5.3 fixing cart29 s61 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.

FIG 2 · Cold start & warm startCold startWebContainersWasmer7.2–7.715.127.226.733.7–34.657.8With Python, ~140 MB0 s10 s20 s30 s40 s50 s60 sWarm start (cached)WebContainersWasmer0.34–0.68 s (6 times)0.66 s (1 time)0 s0.25 s0.5 s0.75 s1 s
Fig 2 · Each dot is one test run. WebContainers cold start: another session 3 times (27.2 / 7.2 / 7.4 s), my online page 1 time (15.1 s), later three-runtime comparison 2 times (7.7 / 7.5 s); warm start 6 times. Wasmer cold start: bash + Node ~89 MB, 4 times (34.4 / 34.6 s, plus comparison experiments 33.7 / 26.7 s); hollow dot is first experiment, three included Python ~140 MB, 57.8 s; warm start 1 time. Samples are small—not benchmarks · Source: author's tests

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.
  • In bash, 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.
  • vitest 5 won't run; mocha 12 won't either; mocha 10 works.
  • 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.

TaskWebContainersWasmerCloud 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 loop120 M18 M1.6 M
Cold start7.5–7.7 s27–34 s9–13 s
Warm command (echo)~105 ms~58 ms150–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.

§ 05 / Network

Door four:
Network

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.

ResultCountExamples
Allowed11GitHub raw, GitHub API, npm registry, PyPI JSON, jsDelivr, unpkg, Wikipedia REST, Hacker News API, Hugging Face API
Only allows own domain1Damai
No allow headers19github.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.

FIG 3 · CORS testsModel interfaces · 14 (10-28)Public URLs · 31Of which: machine-readable · 12Of which: human-readable · 1913 allow1BigModel: no CORS headers since 10-28; Anthropic needs a declared header; Volcano Ark's 401 has none11 allow19 no allow headers10 allow2arXiv API no allow headers; Reddit JSON returns 40317 no allow headersThe 1 that allows is Cloudflare docs; Damai only allows own domainAllowedOwn domain onlyNo allow headers (incl. 3 × 403)
Fig 3 · curl impersonating a page from roam.xiaopingfeng.com, one machine, one User-Agent, one request per URL. Model interfaces scored 14/14 on 10-20, and BigModel no longer passed on the 10-28 re-test; the public URLs are the 10-20 measurement. "Machine / human" classification is by URL nature; sample biased toward developer sites, not random · Source: author's tests
§ 06 / Runtime

Who controls
the runtime

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:

  • WebContainers: The @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.
  • Wasmer: SDK is MIT plus a clause: commercial products with >1 M MAU or >$1 M monthly revenue must prominently display "Wasmer" in the UI. The SDK and its wasm can be served from my own domain; bash, Node, etc. are still downloaded from Wasmer's package repo—Node and Python packages are 75 MB and 59 MB respectively (my measurement). Its README calls itself alpha.
  • CheerpX: Free for individuals, solo companies, and open-source projects with attribution; self-hosting the runtime library requires a commercial license.
  • BrowserPod: The vendor's own comparison page says free for individuals, requires the same response headers. I only read that page; haven't tried it.

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.

§ 07 / Worth It

What layer
did you put in

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:

FIG 4 · How much goes in the browser, and is it worth it① Execution onlyCode runs in the tabExecutionOrchestration (cloud)Inference (cloud)Validated, with limitsbolt.new, about $40M annualized(2025-03, secondhand)② Agent loop tooThe page is the Agent shellExecutionOrchestrationInference (cloud)No backend; no usage evidenceBrowserCode, 148 starsShow HN scores 6 and 5③ Model tooLocal inferenceExecutionOrchestrationInferenceCoverage and capability fall shortSendCheckIt: 40.7% eligiblelocal 7.7 s vs hosted 1.3 s④ Page hands out toolsWebMCP, the other directionTools in the pageAgent (elsewhere)Still a previewWebKit opposes, Mozilla neutralChrome 149 / Edge 150 trialsIn the tabIn the cloud or elsewhere
Fig 4 · Each of the first three rows puts one more piece in the tab; the fourth is the opposite direction: the page hands its tools to an Agent elsewhere. bolt.new's figure is Sacra's estimate, secondhand, with no newer number after 2025-03; the rest is in § 07 · Sources: Sacra, GitHub, Hacker News, SendCheckIt, Chrome, and the two browser vendors' position issues

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:

FIG 5 · npm monthly downloadsCloud sandboxes@vercel/sandbox21.8 Me2b7.7 M@daytonaio/sdk2.6 MIn-browser SDKs@webcontainer/api537 K@mlc-ai/web-llm445 K@wasmer/sdk28 K0 M5 M10 M15 M20 M
Fig 5 · npm downloads over the last 30 days (2026-09-27 to 10-26), linear scale, so the short bars of the in-browser SDKs are the true proportion. Downloads include CI, mirrors and server-side use and do not equal end users; @vercel/sandbox may also be installed indirectly through templates · Source: npm's public download API, fetched 2026-10-28

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.

  1. The form that holds up is the hybrid: model in the cloud, execution in the browser, falling back to the cloud when needed. Bolt falls back to a hosted preview in Safari and adds hosted services, Chrome officially recommends a built-in model plus cloud fallback, and a small orchestrator scores by dispatching a strong model; the three lines point the same way.
  2. What decides the value is who pays and whether the user is present, not how fast the browser runs. Cost shifting is validated; "an interactive session where you are present" fits the tab's lifecycle, "leave it running for half an hour" does not.
  3. "Replacing the local Coding Agent" has no evidence behind it. The leading vendors' actual route is system-level sandboxes plus cloud sandboxes (Anthropic's October 2025 write-up).
  4. For the two pages I built: as a product, the value is unproven because there is no usage data; as a measured set of limits and a test bed that can be re-run, the value is already delivered, and that is the first six sections.

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.

§ 08 / Five Questions

Before building,
ask five questions

  1. Does the task need git, ssh, or databases, or need to keep running after you leave? If yes, don't move it in. Neither runtime has git, the browser has no TCP, and a background tab may also be frozen.
  2. What browser do your users use? The file and process doors are fully open only in Chromium. If your users are on Safari, all you get is an in-memory workspace.
  3. Can you configure response headers for the page? Hosted on GitHub Pages or similar where you can't customize headers? Cross-origin isolation usually won't work (Service Workers can bypass this; I haven't tried).
  4. Who provides the network egress? If you only read public APIs and don't install dependencies, you don't need one; to install packages, someone must operate a relay or you accept the vendor's proxy.
  5. Does the license allow your use? WebContainers' commercial terms, Wasmer's attribution clause, the WISP client's AGPL—none are visible after reading just the first screen of the README.

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.

§ 09 / Limitations

Unverified,
and next steps

Unverified:

  • Neither live page has been regression-tested with a BigModel key: the real-model tasks ran on local copies, and BigModel's direct browser access had already broken on October 28 (§ 02). On October 28 I switched to the local Ollama gemma4:31b-mlx and ran the cart task twice on local copies of both pages (same response headers as production): Bash was really called both times (3 calls on WebContainers, 2 on Wasmer), I re-ran the tests in host Node and got 5/5, and cart.test.js was not changed; the Agent took about 38 and 40 seconds on WebContainers and about 27 and 56 seconds on Wasmer.
  • Not a single test on Safari or Firefox behavior.
  • The whole folder-picker path (authorization, read, write-back). I prepared a test directory and scripts; the picker and the write permission are system dialogs that a person has to click, and I haven't done it yet.
  • Real inference on local WebLLM; only confirmed model IDs exist.
  • Whether an Agent can still run after the browser throttles a background tab. My automation fixed page visibility to visible, so I can't reproduce; per Chrome 88's explanation, when a page is hidden for >5 min, muted for ≥30 s, and not using WebRTC, chain timers (nested ≥5 deep) are checked only once per minute; that post doesn't mention Web Workers or whether Wasm threads are affected, so I have no answer.
  • WebContainers column numbers come from another session; I only verified the online page portion.

Things that would rewrite this article's conclusions:

  • WebMCP reaching stable, or WebKit and Mozilla changing their positions; Chrome's built-in model function calling moving from "Proposed" to usable; the size of model a phone browser can hold rising noticeably. These would rewrite § 07.
  • Bolt publishing new revenue figures: the latest is still March 2025.
  • Firefox or Safari implement showDirectoryPicker, or Direct Sockets ships beyond Isolated Web Apps. Then the conditions on the file and network doors would change.
  • Wasmer SDK reaches beta and takes TCP and relay in-house, no longer requiring users to self-provide.
  • WebContainers opens self-hosting, or a second compatible implementation appears.

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.

Appendix / Sources & Methodology

Sources & methodology

Changelog

3 versions
  1. v3 Adds §07 "Worth It": the four ways of putting an Agent in the browser, with evidence layer by layer (bolt.new, CodeSandbox, npm downloads, BrowserCode, SendCheckIt, BFCL, Chrome's built-in model, WebMCP positions), plus two figures (Fig 4 the four placements, Fig 5 npm monthly downloads), and fused into the original: §02 adds that BigModel stopped passing CORS on 10-28 (13/14), the §01 decision table adds the freezing rule and the gemma4 regression, §09 adds the real-model regression results; the old §07 and §08 become §08 and §09 View v3
  2. v2 §04 adds three-runtime comparison: same 11 tasks against WebContainers, Wasmer, and a temporarily deployed Cloudflare Sandbox, covering toolchain, outbound network, compute, cold start, local CPU evidence, and silent failure on unisolated pages; TL;DR process row synced with §08; cold/warm start chart adds 4 cold start samples, figure numbers re-sequenced (cold/warm start is Fig 2, CORS is Fig 3); appendix runtime-lab.txt (tasks, adapters, raw results) View v2
  3. v1 Initial release: four doors for running an Agent in the browser (model, file, process, network), WebContainers vs. Wasmer same-task comparison, CORS tests of 14 model interfaces and 31 public URLs, with 3 figures and a reproducible test log View v1