webscrape.dev

Self-Hosting Headless Chrome vs Managed Browser Infrastructure: The Cost Math

Browser fleets are an ops problem before a cost problem. What self-hosting really costs in memory, crashes and on-call, and when managed wins.

Nathan Kessler
Nathan Kessler··Reviewed
15 min read

Each tool referenced is evaluated against our methodology using public docs, vendor demos, and hands-on testing.

A browser-hour of your own instance capacity costs about three cents. Managed vendors charge $0.08 to $0.24 for the same hour, three to eight times more, which makes the decision look obvious right up until you price the crash loop at 3am. Vendor pricing pages stop before the operational work. Open-source advocates put the software at zero and stop before the pager. Proxyway's scraping-browser roundup, some of the strongest neutral coverage in this space, skips the managed browser infrastructure layer entirely, which makes sense for a site built around proxy comparisons rather than compute.

This page does the arithmetic: browser-hours derived from page counts, memory per concurrent context, the container work that keeps a self-hosted pool alive, and the costs that never appear in a spreadsheet. The answer flips depending on volume shape and on whether anyone on your team wants to own a fleet, so it ends in conditions rather than a verdict.

Every price below was read from the vendor's own pricing page on 27 July 2026 and is dated as such. Pricing in this category moves, and two of the five vendors here do not publish a per-hour rate at all, which is noted where it applies. There is no first-party performance testing anywhere on this page.

Start with browser-hours, not instances

The unit that makes both sides comparable is the browser-hour: one browser session open for one hour. Every managed vendor prices in it, directly or through a proxy metric, and it is also the right unit for sizing your own pool.

The derivation is simple:

browser-hours per month = (pages per month × average session seconds) ÷ 3600
average concurrency     = browser-hours per month ÷ 730

The second line is the one people skip, and it is where self-hosted plans go wrong. Average concurrency is what your instance count has to cover on a smooth day. Peak concurrency is what it has to cover on the day a backfill lands, and for most crawl schedules the peak sits several times above the average. A pool sized for the average queues; a pool sized for the peak idles most of the month and bills the whole time.

Two worked examples, using nothing but the formula above:

WorkloadPages/monthAvg sessionBrowser-hours/monthAvg concurrency
Price monitoring, light pages1,000,00012s3,333~4.6
Agent workflows, heavy SPAs5,000,00025s34,722~47.6

Average session length is the variable worth measuring before anything else, and it is also the variable you control. Blocking images, fonts and third-party trackers through request interception in Playwright or Puppeteer cuts session time on ad-heavy targets, and it cuts proxy bandwidth at the same time. If you are billing per browser-hour, session length is your cost lever. If you are self-hosting, it is your concurrency lever. Either way the tuning pays twice.

One caveat before you plug numbers in. If a large share of your targets do not need JavaScript at all, you should not be counting browser-hours for them. A web scraping API or a plain HTTP client handles static documents at a fraction of the cost, and the guide to choosing a web scraping tool covers that split. Browser infrastructure is for pages that genuinely require a rendering engine.

What a self-hosted pool actually costs

Memory and CPU per concurrent context

Chrome's memory footprint is a distribution with a long tail. A freshly launched headless instance is cheap, and the same instance twenty pages into a session on a single-page app can cost several times as much.

For planning, budget roughly 300 MB to 1 GB per concurrent browser context under scraping load, then measure your specific targets before committing to an instance count. The upper end of that range is not pessimism. Lightpanda publishes a benchmark run with chromedp against 933 real web pages on an AWS EC2 m5.large, reporting headless Chrome at a 2 GB memory peak and 46 seconds of execution time, against 123 MB and 5 seconds for Lightpanda itself. That is a vendor benchmark published by a competing engine and should be read as such. The multiple matters less than the absolute figure: Chrome's peak memory on a real page mix lands in gigabytes rather than megabytes.

CPU matters at launch and during layout. A cold browser start compiles shaders, initializes a V8 isolate and sets up inter-process communication, which is why warm pools exist. Reusing an existing browser and opening a fresh context per job avoids most of that cost, at the price of carrying whatever state and memory the previous job left behind.

Now the compute arithmetic, with the assumption stated plainly rather than dressed up as a quote. Take a general-purpose instance with 8 vCPU and 16 GiB. Assume something in the region of $0.30 to $0.35 per hour on-demand, and check your own region's current list price before trusting the result, because instance pricing varies by region and changes without announcement. Leave a few GiB for the OS, your orchestrator and page-weight spikes, and you land around ten to twelve concurrent contexts per instance if your targets are moderate. That is roughly three cents per browser-hour of raw compute, and closer to two on a one-year reservation.

Hold onto that number. It is the entire self-hosting argument, and it is also smaller than it looks.

The container work

Getting one browser running in Docker takes an afternoon. Getting a pool of them to survive a week takes considerably longer, and the work is unglamorous.

Shared memory. Docker gives a container 64 MB of /dev/shm by default. Chrome uses it heavily and crashes when it fills, with an error message that reads like a disk problem. The fixes are --shm-size=1g or the --disable-dev-shm-usage flag, and both are documented well enough that you will find them within an hour of your first crash. You will still lose that hour, and everyone who joins the team later loses it again.

Zombie processes. Chrome spawns a tree of child processes. Kill the parent carelessly and the children survive, holding memory. Without an init process as PID 1 to reap them, a long-running container accumulates orphans until the host runs out of memory. This is a common cause of a pool that looks healthy at 9am and is dead by morning.

Crash recovery. A browser that dies mid-session has to be detected, replaced, and its queued work retried without losing the job. That means health checks that actually exercise a browser rather than pinging a port, a warm replacement pool so the queue does not stall during a cold start, and idempotent job handling so a retry after a partial extraction does not duplicate rows downstream.

Session recycling. Assume the leak rather than hunting it. Cap every browser at a maximum number of sessions and a maximum wall-clock lifetime, kill it when either trips, and let a replacement take over. This turns an unbounded leak into a bounded, predictable cost.

Concurrency limits and queueing. Something has to refuse work when the pool is full instead of launching browser number thirteen on a twelve-browser host. Managed vendors do this for you and publish the ceiling. Self-hosted, it is your code, and getting the backpressure wrong turns a busy hour into an out-of-memory cascade.

None of this is hard engineering. It is engineering that produces no product, and it never finishes, because each new class of target finds a new way to break the pool.

Image, font and locale dependencies

The container detail that surprises people is typography. A minimal Linux image ships almost no fonts. Render a page in it and CJK text becomes boxes, emoji vanish, and any layout that depends on measured text width shifts. If your extraction reads rendered text, or you generate screenshots or PDFs, you need font packages installed and you need to know which ones.

Add locale and timezone configuration. A container defaulting to UTC and the C locale renders dates and currency differently from a real user in the market you are presenting yourself as browsing from, which is exactly the kind of inconsistency an anti-bot system looks for. The image also has to pin a Chrome version matching your automation library, and both have to be rebuilt together. That leads directly to the next cost.

The costs that never reach the spreadsheet

Upgrade churn

Chrome ships fast and occasionally ships something that breaks automation outright. The clearest recent example is documented on the Chrome for Developers blog in a post dated 23 October 2024: the old headless mode was removed in Chrome 132, and from that version --headless=old produces an error instead of launching. The post gives two migration paths, the standalone chrome-headless-shell binary for the old behavior, or the newer headless mode introduced in Chrome 112 and reached through --headless or --headless=new.

That was one change, well telegraphed, with a clean migration path and more than a year of notice. Plan for the class rather than the instance. Chrome ships stable releases on a fast cadence, and Playwright and Puppeteer pin their own Chromium builds, so your automation library, your browser binary and your container image form a version triangle that has to move together. Fall behind and detection rates rise, because a browser advertising an old build against a current user-agent string is itself a signal. Move too fast and you ship an untested browser into production.

On a managed platform this is the vendor's problem. That is not a small part of what you are buying.

On-call for a pool that leaks overnight

The failure mode that defines self-hosted browser fleets is slow degradation rather than the crash. Memory creeps up over eight hours, page loads get slower, timeouts increase, success rate drifts down, and nothing alerts because nothing has technically failed. By the time someone notices, a night of collection is thin rather than missing, which is worse, because thin data looks like real data and flows straight into whatever consumes it.

Catching that requires per-instance memory and CPU metrics, success-rate alerting that fires on drift rather than on zero, and someone who will actually get paged. If you already have that apparatus for other services, adding a browser pool to it is incremental. If you do not, the browser pool is what forces you to build it, and that is a real project with a real cost that no comparison table shows.

Put a rough number on it. A fifth of one senior engineer's time, fully loaded, runs to several thousand dollars a month in most US markets. Compare that against the managed bills below before deciding which option is expensive.

The debugging surface you gain and lose

Self-hosting gives you the process. You can attach a profiler, dump heap snapshots, run the browser headful on a workstation with the exact container image, and inspect anything. When something is genuinely strange at the engine level, nothing beats having the engine.

Managed platforms give you the session. Session replay, live viewers and request-level metrics are standard across this category, and rebuilding video replay of a failed agent run on your own infrastructure is a project most teams never get to. It also happens to be the single most useful artifact when an agent does something inexplicable on a page you cannot reproduce.

The trade is depth against breadth. Self-hosted, you can debug anything and will build the tooling yourself. Managed, you get good tooling for the failures that matter most, and you hit a wall when the problem sits below the API.

What managed infrastructure charges

Read from each vendor's own pricing page on 27 July 2026. Treat this as the shape of the market rather than a quote.

ToolEntry paid planConcurrency thereMeterRate beyond included
Browserbase$20/mo Developer25browser hours, 100 included$0.12/hr; $0.10/hr on $99 Startup (100 concurrent, 500 hrs)
Browserless$25/mo Prototyping15units of up to 30s each, 20,000 included$0.0020/unit, about $0.24/hr; $0.0015/unit on $350 Scale, about $0.18/hr
BrowserCloud$19/mo Hobby5credits, 1,000 credits = 1 browser hour, 120 hrs includedno overage rate published; included hours imply about $0.16/hr, falling to about $0.08/hr on $249 Business
Steel$250/mo Scale, plus usagenot published per tierusage-based credits, $100 monthly credits on Scaleper-hour rate not published on the pricing page

Two gaps worth stating rather than filling with a guess. Steel's pricing page advertises Launch at $0 per month plus usage with $30 of one-time credits, Scale at $250 per month plus usage, and Enterprise with 1,000 or more concurrent sessions, but it does not publish a per-browser-hour rate or per-tier concurrency for the lower plans, and the docs URL it points to for a detailed breakdown returned a 404 on 27 July 2026. Hyperbrowser pricing could not be retrieved at all on that date, because its pricing page did not render server-side. No figures are quoted for either beyond what their own pages state.

Three things matter more than the headline rates.

Concurrency is the real tier gate. Browser hours are cheap and plentiful; parallel sessions are what plans actually ration. Browserbase publishes 3 concurrent browsers on Free, 25 on Developer, 100 on Startup and 250 or more on Scale. Browserless sells 2, 15, 40 and 100 across Free, Prototyping, Starter and Scale. BrowserCloud lists 1, 5, 50 and 100 up to Business, and 300 or more on Enterprise. If your peak concurrency is 60, your plan is decided before you look at hours.

Session length caps are a hard constraint. Browserless caps sessions at 1 minute on Free, then 15, 30 and 60 minutes across its paid public plans. Browserbase's free tier caps at 15 minutes per session, and BrowserCloud's free tier does the same. Steel is the outlier, advertising sessions up to 24 hours across all three of its listed tiers. A crawler that opens a browser, works a queue for two hours and closes it will not run on most entry plans at all, no matter how many hours you bought. Restructure toward short sessions or pick the vendor whose caps fit.

Proxy bandwidth is metered separately and frequently exceeds the browser bill. Browserless publishes its rates in the same unit currency as browser time, at 6 units per MB for residential traffic and 2 units per MB for datacenter traffic. If your targets need residential IPs, model that line separately using the proxy pricing models guide, because it can dwarf compute. The same is true self-hosted, where a proxy network is an entirely separate contract.

The arithmetic, worked

Take the second workload from earlier: 5,000,000 pages a month at 25 seconds average, so 34,722 browser-hours and about 48 average concurrency.

Managed, at $0.10 per browser-hour, is roughly $3,472 a month for browser time. Add a plan fee and proxy bandwidth on top, and note that 48 average concurrency puts you on a mid or upper tier at every vendor in the table, well above the entry plans.

Self-hosted needs about 48 concurrent contexts on average, so five instances at ten contexts each, and realistically eight to ten to absorb peaks and hold spare capacity for failure. Ten instances at the assumed $0.32 per hour is about $2,336 a month on demand, less on a reservation. Add load balancing, monitoring, log storage and the engineering time from the previous section.

So the compute saving at roughly 35,000 browser-hours a month is on the order of $1,000 to $1,500 against on-demand pricing, and it evaporates entirely if the fleet consumes even a fifth of one engineer. At the lighter workload, 3,333 browser-hours, the managed bill is roughly $333 and the argument is not close: no amount of instance tuning saves money that small.

This is why the crossover sits higher than intuition suggests. The per-hour gap is real, but the absolute gap only becomes interesting in the tens of thousands of browser-hours, sustained. Below that, you are buying control and paying for it in engineering attention.

The gap widens in your favor under four specific conditions: spot instances, viable precisely because browser jobs are short and retryable; reserved capacity, if your volume is predictable a year out; high packing density, if your targets are light enough to run more contexts per instance; and existing infrastructure, if the pool joins a cluster you already operate rather than justifying a new one. Miss all four and the arithmetic stops working.

Where each tool fits, and who it is wrong for

Playwright is the default automation layer for self-hosting, maintained by Microsoft, driving Chromium, Firefox and WebKit through one API with auto-waiting and network interception. It is wrong for you if you only ever target Chromium and would prefer a smaller API surface. It is also wrong as a complete answer in any case: it drives browsers, it does not manage a fleet or handle blocking.

Puppeteer is the narrower Node option from Google's Chrome team, closest to the Chrome DevTools Protocol and the shortest path if your stack is already Node and Chromium-only. It is wrong for teams needing Firefox or WebKit coverage, and wrong for anyone expecting anti-bot handling in the box, the same caveat as Playwright and the subject of the guide on why scrapers get blocked.

Browserless suits teams with existing Puppeteer, Playwright or Selenium code who want to change launch() to connect() and stop operating browsers, and it publishes a self-hostable core if you want an exit path. It is wrong for teams optimizing purely on published per-hour cost, because its 30-second unit model prices out at the top of the range here, and wrong for long-session workloads given the 60-minute ceiling on its highest public tier.

Browserbase is the well-funded default for agent workloads, with a Sessions API, a session inspector, and contexts for persisting authentication state. It is wrong for teams that need on-premises deployment or want the option to self-host later, because it is a hosted service only.

Steel is the answer when you want a managed API, an open-source core with Docker self-hosting, and long sessions: its pricing page advertises up to 24 hours on every listed tier, which is unusual in this category. It is wrong for teams that need to model cost precisely before committing, because per-hour rates and per-tier concurrency are not published on that page.

Hyperbrowser goes further up the stack, adding scrape, crawl and extract endpoints alongside raw sessions, which suits agent teams that would otherwise build extraction themselves. It is wrong for teams that want raw browser control and nothing else, since you would be paying for a layer you do not use, and wrong for anyone who needs published pricing before a sales conversation.

BrowserCloud prices aggressively at the entry tier, and its bundled hours imply one of the lower effective rates in the table at the Business plan. It is wrong for anyone who needs an overage rate published before committing, since the plans bundle hours without stating what happens past them, and wrong for anyone who needs substantial outside evidence, because independent signal on it is thin.

Lightpanda is the interesting third option: a headless engine written from scratch in Zig, executing JavaScript through V8 and processing the DOM without graphical rendering, exposing the DevTools Protocol so Puppeteer and Playwright can connect. If memory is your binding constraint, this attacks the constraint directly rather than buying around it. It is wrong for targets requiring faithful Chromium rendering or that fingerprint the browser aggressively, because a from-scratch engine has not worked through the compatibility edge cases Chromium settled years ago. Its published figures are the project's own.

Worth naming the gap: none of these are antidetect browsers, and none substitutes for a proxy layer. Stealth features on a managed platform reduce fingerprint surface. They do not give you a rotating proxy pool. Those are separate purchases with separate bills, and conflating them is how browser-infrastructure budgets get set several times too low.

Crossover conditions

Self-hosting wins when all of these hold. Sustained utilization in the tens of thousands of browser-hours a month, with a load shape flat enough that reserved or spot capacity is usable. Existing container orchestration you already run for other services. An on-call rotation that can absorb one more component. Targets stable enough that the pool is not re-tuned monthly. A team that treats browser infrastructure as part of its competence rather than a distraction.

Managed wins when any of these hold. Volume below roughly 5,000 browser-hours a month, where the entire bill is smaller than the ops time it replaces. Bursty load with long idle stretches, since idle costs nothing on a per-hour meter and full price on an always-on pool. No container infrastructure or on-call rotation. A need for session replay to debug agent behavior. Proxies and stealth required anyway, where bundling saves a second integration and a second contract.

A hybrid is often correct and rarely considered. Run the steady baseline on self-hosted capacity sized for the average, and burst to a managed API for peaks and for the hard targets that need bundled stealth. The engineering cost is a routing layer and two integrations instead of one. The benefit is that you stop paying peak-sized instance bills for average-sized load, and you keep a working escape hatch for the night your own pool degrades.

The thing to avoid is the decision made once, at low volume, and never revisited. The arithmetic above takes an afternoon with your own page counts and session timings. Redo it when volume changes by an order of magnitude, and browse the browser infrastructure category when you do, because this is one of the faster-moving parts of the web scraping stack and the published rates have not stayed still.

Frequently asked

How much RAM does one headless Chrome session need?
Plan for roughly 300 MB to 1 GB per concurrent context under real scraping load, then measure your own targets instead of trusting any single number. A freshly launched instance is much smaller, but memory grows with page weight, and ad-heavy single-page apps are far worse than static documents. Lightpanda's published benchmark, run with chromedp against 933 real web pages on an AWS EC2 m5.large, reports headless Chrome peaking at 2 GB against Lightpanda's 123 MB. That is a vendor benchmark from a competing engine, so read it as directional, but the order of magnitude matches what teams report once they stop counting idle browsers.
What does a managed browser hour typically cost?
Published rates as of 27 July 2026 cluster between roughly $0.08 and $0.24 per browser-hour. Browserbase's pricing page lists $0.12 per browser-hour past the Developer plan's 100 included hours, and $0.10 on the $99 Startup plan. Browserless meters 30-second units rather than hours, so its $0.0020 and $0.0015 overage rates work out near $0.24 and $0.18 per hour. BrowserCloud bundles hours into plans instead of publishing an overage rate, and its included hours imply about $0.16 on Hobby down to about $0.08 on Business. Proxy bandwidth bills separately everywhere.
How do I stop a self-hosted browser pool from leaking memory?
Stop trying to make long-lived browsers stable and recycle them instead. Give every browser process a hard cap on sessions handled and on wall-clock lifetime, kill it past either, and start a replacement from a warm pool so the request queue never sees the gap. Set a container memory limit so the kernel reaps a runaway process before it takes the host down, and raise Docker's shared-memory size past its 64 MB default, a common source of tab crashes that present as leaks. Close contexts and pages explicitly on every code path, including error paths.
Do managed browser vendors include proxies and stealth?
Most bundle both, as separately metered add-ons rather than free extras. Browserbase, Hyperbrowser, Steel and BrowserCloud all advertise proxy routing and fingerprint handling alongside sessions. Browserless publishes its rates in the same unit currency as browser time, charging 6 units per MB of residential traffic and 2 units per MB of datacenter traffic, which makes the separate metering explicit. The bundling matters more than any discount: one vendor, one integration and one bill, instead of a browser fleet plus a separate proxy contract that you glue together and monitor yourself.
At what volume does self-hosting become cheaper?
Later than most teams expect. At 5,000 browser-hours a month, a managed bill near $0.10 per hour is about $500, less than a day of senior engineering time. Compute for the same work is a few hundred dollars, so the saving cannot pay for the operational work around it. The crossover realistically sits in the tens of thousands of browser-hours a month, sustained rather than bursty, and only if you already run container infrastructure and an on-call rotation. Below that, self-hosting buys control rather than savings.

Weekly briefing – tool launches, legal shifts, market data.