Managed Cloud Browser vs Self-Hosted Puppeteer: We Tested Kernel on 200 URLs

We tested the Kernel cloud browser against our self-hosted Puppeteer on 200 real URLs: success rate, latency, a stage timing table and a build vs buy checklist.

Written byAndrii
Published on
Managed Cloud Browser vs Self-Hosted Puppeteer: We Tested Kernel on 200 URLs

Tests run and numbers read October 24, 2026. I run WebCrawlerAPI, so I am a competitor to browser vendors in an adjacent space. This was one run per test, with Kernel in a basic configuration (no proxy, no stealth). I did not tune either side, I have no deal or sponsorship with Kernel, and I did not measure cost. Results may change as the vendor updates its product. If Kernel has a better configuration for this kind of test, I will happily rerun it and update the post.

We run Puppeteer ourselves. Browser fleets, memory leaks and restarts are our job, and they are not the product. So I wondered whether we should hand that part to a managed cloud browser vendor.

We already know Kernel. WebCrawlerAPI uses Kernel headful browsers as one of its browser sources. So this was not a cold start. The question was bigger: can Kernel replace our self-hosted Puppeteer, without sacrificing quality, and win on speed?

Speed was one of the main reasons to look. Kernel advertises very fast browsers, and I hoped that moving browsers out of our own infrastructure would cut latency. It turned out the opposite.

Before changing anything, I ran a test. I took 200 real URLs and sent them through our self-hosted Puppeteer and through the Kernel cloud browser. Then I compared success rate and latency. One detail: the test used Kernel in headless mode, which is not the headful mode we run in production for that browser source.

This is a small, focused test, not a full benchmark. If you want larger comparisons of scraping and crawling APIs, run on the same inputs for every tool and with our own numbers included, see our open benchmarks.

The short answer

  • Can Kernel replace Puppeteer? Not without losing something. I wanted to keep quality and gain speed. On easy sites I lost on both: lower success rate and higher latency.
  • Latency: this was a main reason to try it, and the result went the other way. Kernel was slower in every comparison I ran, in both packs.
  • Easy sites: warm self-hosted Puppeteer won. It got 95% of pages, against 84% for Kernel. It was about 3 seconds faster on the pages both handled.
  • Hard sites: the managed browser won on success. It got 45% of pages, against 14% for plain Puppeteer. That is about 3.2x more pages recovered. But it took about 1.8x to 1.9x longer on successful requests, and it still failed on more than half of the pages.
  • Where the time goes: a fresh managed browser session has a fixed cost of about 1.6 seconds before any page work starts. A warm browser that stays open does not pay it.
  • What I take from it: a managed browser looks like a fallback tier for sites that block plain Puppeteer. It does not look like a full replacement.
  • Who should buy: teams that do not want to run browsers at all, or that have a lot of blocked sites. Who should build: teams with mostly easy sites and a latency budget.
ScenarioSelf-hosted PuppeteerKernel (basic config)
100 easy URLs95% success84% success
100 hard URLs14% success45% success
Speed on successful requestsFaster in both packsSlower in both packs

Bar chart of success rate. Easy URLs: Puppeteer 95%, Kernel 84%. Hard URLs: Puppeteer 14%, Kernel 45%.

The full numbers are in the tables below. Please read the caveats section before you quote any of them.

Why we looked at outsourcing our browsers

Running headless browsers is real work. Chrome eats memory. Pages hang. Processes need to be restarted and pools need to be sized. None of it is what customers pay us for.

Managed browser vendors promise to remove that. You ask for a browser over an API, you drive it, and you close it. Someone else keeps the fleet healthy.

I picked Kernel for the test. We already use its headful browsers as one of our browser sources, so I know the product. Their docs describe "extremely fast cloud browsers" and publish a browser-create time of 30 ms at p50. Lower latency was one of the most important reasons for me to consider it. I wanted to learn three things:

  1. Would we lose anything in quality on the sites we already handle well?
  2. Would we win in speed?
  3. Would it help on the sites that block plain Puppeteer?

One honest note. The vendor did not get a chance to tune this test. Neither did our own setup. Both ran the way they run by default.

How I benchmarked

What I compared

  • Option A: self-hosted Puppeteer. The browser is already running and warm. Each request opens a tab in it.
  • Option B: the Kernel cloud browser. Headless, no proxy, no stealth mode. A fresh browser session for each request, with a 10 second session timeout.

That last point matters. Option B pays the cost of creating and connecting to a browser on every request. Option A does not. This is a real difference between the two models, and I come back to it later.

Equal conditions

Both options ran through the same test harness, in the same region, with cache off and markdown as the output. WebCrawlerAPI has its own proprietary logic to decide when a page has finished loading, and both setups used the same one.

Two URL packs

I wanted to see easy sites and hard sites separately, so I built two packs of 100 URLs each.

  • Pack A, easy: 100 URLs that already worked on plain Puppeteer. They come from about 60 hosts, with at most 3 URLs per host, taken from the last 7 days of real customer traffic.
  • Pack B, hard: 100 URLs that previously needed an unblocker service to load. 83 of them came from one unblocker service and 17 from another.

Both packs have a built-in bias. Pack A favors Puppeteer by design, because those URLs were picked for working on it. Pack B favors the unblockers by design, because those URLs were picked for needing them. So a 95% result on Pack A is not "Puppeteer is great". It is about what I expected.

Success and measurement

A request counted as a success if the job finished with non-empty markdown. I sent 5 requests at a time. Latency is client-side wall clock, with a 120 second timeout. Each pack ran once per option.

Table 1. Test setup

Option A: PuppeteerOption B: Kernel
BrowserSelf-hosted Chrome, warmManaged cloud Chrome, headless
Session modelReused browser, new tab per requestFresh browser session per request
ProxyNoneNone
StealthNoneNone
Scraper regionUS Central cloud regionKernel browsers run in us-east
Timeout120 s client timeout10 s session timeout, 120 s client timeout

Results: easy sites (Pack A)

Table 2. Pack A results (100 easy URLs)

MetricPuppeteerKernel
Success rate95%84%
Average latency4,540 ms7,483 ms
p504,158 ms7,352 ms
p957,668 ms10,445 ms
p998,512 ms12,460 ms
Max9,429 ms13,533 ms
Failures4 timeouts, 1 non-success page15 timeouts, 1 host error

Puppeteer got 95 of 100. Kernel got 84 of 100. On pages both handled, Kernel was slower.

Table 2b. Pack A, paired view

MeasureValue
Both succeeded84
Kernel only0
Puppeteer only11
Neither5
Average difference (Kernel minus Puppeteer)+3,141 ms
Median difference+2,818 ms
Pages where Kernel was faster5 of 84

So Kernel did not win a single page that Puppeteer lost. Puppeteer won 11 pages that Kernel lost. And on the 84 pages both got, Kernel was about 3 seconds slower on average. It was faster on 5 of them.

The 15 Kernel timeouts

Most of the Kernel failures were timeouts. All 15 of them ended between 6.4 and 9.5 seconds. That is just under the 10 second session cap I had set. Several of them landed on two or three slow hosts.

It is tempting to say the cap caused them. I cannot say that. I did not raise the cap and rerun, so the cause is not confirmed. It is the first thing I would test next.

Also keep the bias in mind. Pack A was built from pages that worked on Puppeteer. A 95% against a perfect 100% is run-to-run noise plus a few flaky pages. It is not a flaw in Puppeteer.

Results: hard sites (Pack B)

Table 3. Pack B results (100 hard URLs)

MetricPuppeteerKernel
Success rate14%45%
Average latency (all requests)2,745 ms8,348 ms
p50 (all requests)1,328 ms6,790 ms
p95 (all requests)8,869 ms13,584 ms
p99 (all requests)9,234 ms31,190 ms
Max10,106 ms120,042 ms
Average, successful requests only5,169 ms9,090 ms
p50, successful requests only4,278 ms8,183 ms
p95, successful requests only8,736 ms14,812 ms

Kernel recovered 45 pages. Plain Puppeteer recovered 14. That is about 3.2x more pages, and it is the reason a managed browser is interesting at all.

Do not trust the "fast" Puppeteer average

Look at the all-requests row. Puppeteer shows a 2.7 second average and a 1.3 second p50. That looks great. It is not.

Puppeteer fails fast on these sites. It gets blocked, and the block comes back quickly. Fast failures pull the average down. So for hard sites, compare latency on successful requests only.

On that basis, Kernel was slower:

  • Average: 9,090 ms vs 5,169 ms, about 1.8x.
  • p50: 8,183 ms vs 4,278 ms, about 1.9x.

So the honest summary is "about 3.2x more pages at about twice the time per successful page".

What failed

Table 4. Pack B failure types

Failure typeKernelPuppeteer
Access denied2461
Timeout187
Host returned an error1210
Non-success page08
Other10
Total failures5586

Most of what stopped Puppeteer was access denied (61 of 86). Kernel got past many of those, but not all. It still had 24 access denied pages, and it had more timeouts (18 vs 7). One Kernel request hit the full 120 second client timeout.

Paired view and by origin

Table 4b. Pack B, paired view and by origin

SegmentKernelPuppeteer
Both succeeded1111
Only this option succeeded343
Neither succeeded5252
Pages from the first unblocker service (83 URLs)41 of 8312 of 83
Pages from the second unblocker service (17 URLs)4 of 172 of 17

Kernel won 34 pages that Puppeteer lost. Puppeteer won 3 pages that Kernel lost. And 52 pages failed on both.

Be careful with the second row of origins. 17 URLs from about 7 hosts is too small to say anything. I show it for completeness only.

What this tells me

Kernel in a basic configuration is not a drop-in replacement for a dedicated unblocker. More than half of these pages failed on it. But it did recover 34 pages that plain Puppeteer could not. That is worth something, and it is a different kind of value than "faster browsers".

Stage by stage: where the time goes

The batch numbers show a gap of about 3 seconds on easy pages. I wanted to see where it comes from. So I ran a controlled test on one simple page (our own site), 4 runs each.

Table 5b. Single-page repro, end-to-end API wall clock

RunKernelPuppeteer
16,915 ms4,027 ms
26,821 ms3,999 ms
36,986 ms3,834 ms
46,569 ms3,593 ms
Averageabout 6.8 sabout 3.9 s

The gap is steady, at about 2.9 seconds. It is not random noise.

Then I looked at the time spent inside the scraper, split into six generic stages. These numbers are scraper-side only. They are not end-to-end, so do not compare the totals with the table above.

Table 5. Stage timing (scraper-side, seconds)

StageKernelPuppeteerDifference
Get a browser ready0.890.31+0.58
Navigate to the page0.540.35+0.19
First page-state checks0.380.16+0.22
Wait for the page to settle2.500.77+1.73
Extract the content0.430.31+0.12
Convert and return1.16about 1.0about +0.16
Totalabout 5.95about 2.92about +3.0

Horizontal bar chart of scraper-side stage timing in seconds. The wait-for-the-page-to-settle stage takes 0.77 s on Puppeteer and 2.50 s on Kernel. Totals: about 2.92 s vs about 5.95 s.

The largest gap by far is the "wait for the page to settle" stage. It took 2.50 seconds on Kernel and 0.77 seconds on Puppeteer. That is +1.7 seconds, more than half of the total difference.

I do not know why. I have not confirmed a cause, and it is under investigation. It could be the setup, the remote connection, the region, or something in how I drive the browser. I would be guessing, and I do not want to put a guess in a table. Keep that in mind: the numbers are solid, the explanation is not.

The browser-ready stage (+0.58 s) is easier to explain. It is the cost of creating and connecting to a remote session, which a warm local browser does not pay.

Where the time goes at a high level

Fixed cost per session

To understand the session cost, I ran a small separate micro-benchmark. It ran from a client in the Netherlands, not from our scraper.

Table 6. Fixed overhead per fresh session

StepMeasuredNote
Create a browserabout 100 to 130 msVendor docs claim 30 ms p50
Connect to itabout 850 to 900 ms
Open the first pageabout 320 ms
Navigateabout 700 ms
Close the sessionabout 240 ms
Fixed cost before page workabout 1.6 s

Each fresh session costs roughly 1.6 seconds before any real work. That fits the "get a browser ready" gap I saw in the stage table. A warm browser skips most of it.

Geography

Treat the vendor's 30 ms figure with care. It comes from the vendor's docs, and as I understand it, it was measured colocated, from a client in the same place as the browsers (us-east). My micro-benchmark client was in the Netherlands. My scraper was in a US Central region. Kernel's browsers were in us-east.

So I did not reproduce their conditions, and I do not claim their number is wrong. I got about 100 to 130 ms from a different region. Connect time of 850 to 900 ms is also something I would expect to shrink if the client sat next to the browsers.

One fresh session per request vs a warm browser

This is a structural difference, not a quality difference. In my test Kernel got a new session each time. Puppeteer reused a warm browser.

A fairer comparison would be Kernel with a browser pool. According to Kernel's docs, pools skip start-up and are plan-gated, and they do not remove the connect cost. I did not test pools, so I will not say how much they help. It is the next test on my list.

Configuration knobs

From the vendor's docs and my own micro-benchmark:

  • Stealth mode: about +120 ms on browser creation.
  • Residential proxy: +100 to 150 ms on creation and roughly 2x slower navigation.
  • Headless vs headful: no difference I could see.
  • Custom viewport, extensions or kiosk mode: these trigger a Chromium restart that, per the vendor's docs, takes several seconds.

Check the current docs before you rely on these. They can change.

What I would try next

I stopped at a basic configuration on purpose. These are the experiments I would run next, and what each would tell me:

  1. A higher session timeout. If the 15 easy-site timeouts go away, the 10 second cap was the cause.
  2. Stealth mode. Does it lift the access denied count on Pack B?
  3. A residential proxy. Same question, with a latency cost.
  4. A browser pool. How much of the 1.6 second fixed cost does it remove?
  5. Running next to us-east. How much of the connect time and settle gap is distance?

Each one has a clear question and a clear yes or no. I will publish a follow-up if the results are interesting.

What we are doing with this

Based on this single test:

  • Keep self-hosted Puppeteer for easy sites. It is faster and succeeds more.
  • Evaluate a managed browser as a fallback tier, next to or ahead of an unblocker, for pages that plain Puppeteer cannot get.
  • Do not replace anything until I have run the follow-up tests above on our own traffic.

Kernel did some things well. Creating and connecting to a browser is quick. And it recovered 34 hard pages that our Puppeteer lost. That is a real result.

How to evaluate a managed browser vendor yourself

You can copy this process. It works for any vendor, not just Kernel.

Sample design

  • Use real URLs from your own traffic.
  • Build an easy pack and a hard pack. Test them separately.
  • Cap the number of URLs per host (I used 3) so a few slow hosts do not dominate.
  • Write down the selection bias of each pack.

What to measure

  • Success rate.
  • p50, p95, p99 and max latency.
  • Latency on successful requests only.
  • Failure types: timeout, access denied, host returned an error, non-success page.
  • A paired comparison: who won which URL.
  • Cost per 1,000 successful pages.

A simple results table is enough:

URLHostOutcomeFailure typeLatency by stageRegion

Fair-test rules

  • Same harness, same region, same page-completion logic.
  • Cache off on both sides.
  • Same timeout, or a note about why not.
  • More than one run if you can.

Pitfalls

  • A fast average that hides fast failures.
  • A few hosts counting for many URLs.
  • A session timeout that cuts off slow pages.
  • A region mismatch between you, your code and the vendor.
  • Vendor numbers that were measured somewhere else.
  • A cold vendor session against your own warm browser.
  • A single run.

Build vs buy

CriterionLean build ifLean buy if
VolumeHigh and steady, where per-session fees add upLow or spiky, where idle servers waste money
Team time on browser opsYou already have people who handle itBrowser upkeep keeps pulling engineers off product work
Share of blocked sitesMost of your sites load fine on plain PuppeteerA large share block plain browsers
Latency budgetTight (a few seconds end to end)Loose (you can afford 1.5 to 2 extra seconds)
Compliance and data residencyYou need full control over where pages are fetchedThe vendor offers regions and terms that fit
Lock-inYou want to avoid a vendor APIA thin, standard browser protocol makes switching easy
Cost per successful pageYour own cost is clearly lowerThe vendor is cheaper once you count ops time

Rules of thumb

These come from my test. They are not universal.

  • Budget about 1.5 to 2 seconds of fixed cost for each fresh managed browser session.
  • Judge latency on successful requests only.
  • Cap the URLs per host in your sample.
  • Test easy and hard packs separately.
  • A vendor's published latency was measured where the vendor is, not where you are.

Questions to ask the vendor

  1. Can I reuse sessions, or use a pool? Which plan includes it?
  2. Which regions do you offer, and can I pick one near my servers?
  3. What are the session timeout limits?
  4. What proxy and stealth options exist, and what do they cost in latency?
  5. Is pricing per session, per minute, or per request? What does an idle session cost?

Caveats

This test cannot tell you everything. Here is what it cannot say.

  • One run per pack. Run-to-run noise exists, and I did not measure it.
  • Basic Kernel setup. No proxy and no stealth were tuned.
  • The 10 second session timeout may explain some of the timeouts. I did not test that.
  • Real customer URLs with per-host caps. Some hosts still appear more than once.
  • Pack A is biased toward Puppeteer and Pack B toward the unblockers.
  • The second unblocker group has only 17 URLs from about 7 hosts.
  • Fresh session vs warm browser. It is a structural gap, not a pure browser comparison.
  • Latencies are API wall clock, including our own pipeline overhead. The overhead is the same for both options.
  • Kernel was called from a different region than where its browsers run.
  • The stage-timing numbers (5.95 s vs 2.92 s) are scraper-side, and the single-page repro (6.8 s vs 3.9 s) is end-to-end. They measure different things.
  • I did not measure cost.

Summary

Table 7. Summary

ScenarioWinnerSuccess gapLatency gapRecommendation
100 easy URLsSelf-hosted Puppeteer95% vs 84%Kernel about 3 s slower on the 84 shared pagesKeep Puppeteer
100 hard URLsKernel (basic config)45% vs 14%Kernel about 1.8x to 1.9x slower on successful requestsUse as a fallback tier, not a replacement

My takeaways:

  1. A warm browser you own beats a fresh managed session on easy pages.
  2. On blocked pages, a managed browser can recover pages that plain Puppeteer cannot, at the price of speed.
  3. It still failed on more than half of the hard pages, so it is not a substitute for a real unblocker.
  4. Measure on your own URLs. Mine are not yours.

Where WebCrawlerAPI fits

We built WebCrawlerAPI because we did not want to run browser infrastructure and fallback tiers for every project. You send a URL and get markdown back. We decide how to fetch it, and we move to a stronger tier when a page is blocked. That is the same problem this post is about, solved on our side.

If you scrape a handful of known, easy sites, you probably do not need us. A small Puppeteer setup will do the job, and this test says it will be fast. If you have many sites, some of them blocked, and you do not want to own the browser fleet, it is worth a look. The getting started guide takes a few minutes. We also publish open tests of scraping and crawling APIs, with wins and losses, on the benchmarks page.

For background, these posts may help: JavaScript rendering in web crawling, web scraping with Playwright, web scraping with JavaScript and Node.js and best web scraping APIs. If you build a knowledge base from websites, see website to markdown knowledge base.

FAQ

Is a managed browser faster than self-hosted Puppeteer?

Not in my test. A warm self-hosted browser was about 3 seconds faster on easy pages, because the managed setup paid about 1.6 seconds of session cost on every request. Browser pools or running next to the vendor's region might close some of the gap. I have not tested that.

Can a cloud browser bypass anti-bot protection?

Sometimes. In my test a basic Kernel setup got 45% of hard pages, against 14% for plain Puppeteer. That is a real gain, but it still failed on more than half. Stealth, proxies and tuning may help. A managed browser is not a guarantee.

How much does a managed browser cost compared with running your own?

I did not measure cost, so I will not give numbers. Check the vendor's pricing page and see whether it charges per session, per minute or per request. Then compare it with your own server cost plus engineering time, per 1,000 successful pages.

Should I use a browser pool?

Probably, if you pay the fixed cost on every request. According to the vendor's docs, pools skip browser start-up but are plan-gated and do not remove the connect cost. I have not tested one. Run your own pack with and without a pool before you commit.

Do I still need a proxy or unblocker with a cloud browser?

For hard sites, most likely yes. A basic cloud browser with no proxy still hit access denied on 24 of 100 hard pages and failed on 55 in total. If your sites block datacenter traffic, plan for a proxy or an unblocker tier. Test it on your own URLs first.


About the Author

Andrii Mazurian
Andrew Mazurian@andriixzvf

Founder, WebCrawlerAPI · 🇳🇱 Netherlands

Engineer with 15 years of experience in APIs, big data, and infrastructure. Founded WebCrawlerAPI in 2024 with a single goal: to build the best data API, and have been shipping it every day since.