If your team scrapes at high volume through residential proxies, bandwidth isn't a rounding error. You pay for every byte the proxy carries, and across millions of requests that adds up fast. The biggest lever on that bill is how your scraper is built.
We measured it on Hyatt's hotel search. A default headless browser used 4.0 GB of proxy traffic per 1,000 searches. A request-based scraper got the same data for 178 MB. That's 22 times less traffic for the same results.
The second finding is about proxy quality. A request-based scraper spends most of its traffic on one thing: getting past the site's bot protection when a session starts. Every time a session fails and you start over, you pay that cost again. That's where the stability of your IPs, not just the size of the pool, shows up on your bill.
Key Takeaways
A default headless browser used 4.0 MB per Hyatt search. Blocking images, fonts, and third-party scripts brought that down to 1.1 MB. A request-based scraper used 178 KB.
At scale, the gap is large. Extrapolated to 1 million searches, that's about 4.0 TB of proxy traffic for the default browser and about 178 GB for the request-based scraper.
Most of a browser's traffic is JavaScript and images that you never read. Even with assets blocked, JavaScript made up 76% of the traffic.
For the request-based scraper, the bot protection check at the start of a session cost 342 KB, about three times more than a search. In a longer test, five sessions each ran 100 searches on a single check without being blocked.
Every session that has to restart pays that check again. That's why proxy quality matters more than raw pool size.
If you measure traffic in your browser's developer tools, you'll undercount it. In our default browser runs, DevTools missed 25% of what the proxy actually carried.
Why proxy bandwidth matters at scale
Residential proxies are usually priced per gigabyte (GB). So the real cost of a scraper isn't the number of requests it sends. It's the number of bytes those requests pull through the proxy. For a small project, the difference barely matters. For a team collecting data at high volume, it becomes a real line item.
The two common ways to scrape a protected site handle those bytes very differently:
A headless browser is a real browser, like Chrome, that runs without a window. It loads a page the way you would: the HTML, every script, every image, fonts, maps, chat widgets, and ads.
A request-based scraper sends only the HTTP requests that return the data you want. It never renders the page, so it never downloads what you don't need.
Everyone agrees that browsers are heavier. We wanted to measure how much heavier on a real, protected site, and what that means for a proxy bill.
The test setup
We scraped hotel search results from Hyatt. Each search asks for hotels and prices in a US city for random dates two to 12 weeks out. The prices are public, and they live in the HTML of the search results page.
Hyatt is protected by Kasada, a bot protection service. The first time you visit, Kasada answers with a block page and a large JavaScript challenge. Your client has to solve it and send the answer back before Hyatt shows you any data. We call this step the bootstrap.
We ran three scrapers. Each one handled the same kind of searches, five per session:
Headless browser, default. Headless Chrome with Playwright. It loads each search page and waits for the page to finish loading.
Headless browser, assets blocked. The same browser, but it blocks images, fonts, media, maps, analytics, and other third-party scripts. This is what a careful browser scraper would do.
Request-based. A Go program that sends only the requests needed: the bootstrap and the search pages.
Both browser scrapers solved Kasada with the Hyper Solutions Playwright SDK. The request-based scraper used the Hyper Solutions Go SDK. We ran 50 sessions per scraper, 750 searches in total.
How we measured traffic
To compare the scrapers fairly, we measured all three the same way. We put a small counting proxy on our machine, between each scraper and SOAX. It counts every byte that goes to and from SOAX: the connection setup, the encryption handshake (TLS), the request headers, and the compressed responses. That's as close as we can get to what the provider bills.
We also recorded what the browser itself reported through the Chrome DevTools Protocol. We'll come back to why those two numbers differ.
Setting up SOAX for sticky sessions
Session stability turned out to be the main factor in request-based cost, so the proxy setup matters. Every session used its own SOAX residential IP in the US and kept that IP for the whole session. This is called a sticky session.
To get the same setup, create a package at platform.soax.com/packages. We named ours "hyatt", picked the residential network and the HTTP protocol, and left the traffic cap at unlimited.
&w=3840&q=75)
Then set the rules for the package. We targeted the United States and set rotation to On error. With this rule, a session keeps the same IP until something fails, so you don't throw away a session that bot protection has already accepted. Under error handling, we picked Fail. A failed request comes back as an error, and the next request with the same session ID starts fresh on a new IP. Our scrapers handled that retry themselves.
The connection string has a session ID in the username. Our scrapers replaced it with a new ID for every session, so every session got its own sticky IP.
The results
These numbers include everything: the bootstrap, every retry, and every search. Per search, that's:
Default headless browser: 4.0 MB per search.
Headless browser with assets blocked: 1.1 MB per search.
Request-based: 178 KB per search.
To turn these into money, multiply by your per-GB rate. The gap grows with every search you run. If you extrapolate the measured per-search averages to 1 million searches, the default browser would move about 4.0 TB of proxy traffic and the request-based scraper about 178 GB. That's an estimate based on our 750-search benchmark, not a separate measurement.
Where a browser's traffic goes
The default browser made about 917 requests per five-search session. More than half of the traffic (54%) went to other companies' servers: maps, analytics, ads, and a chat widget.
Blocking those helps a lot. It cut traffic per search from 4.0 MB to 1.1 MB. But it can't fix the main problem: the page is a JavaScript application. Even with images and third-party scripts blocked, 76% of the remaining traffic was JavaScript. The browser needs those scripts to render the page. Your scraper needs none of them, because the prices are already in the HTML.
The browser cache helped less than we expected. In the default browser, Chrome downloaded Hyatt's largest JavaScript file (213 KB) again on every search, even though Hyatt marks it as cacheable for hours.
Where request-based traffic goes
The request-based scraper downloads two main things, plus a small IP lookup (9 KB):
The bootstrap, once per session: 342 KB. Almost all of it is the Kasada JavaScript challenge (about 300 KB compressed). Our scraper reads that script and sends it to the Hyper Solutions API, which returns the answer to post back to Kasada. The script itself still has to come through the proxy.
The search results page: 104 KB. That's the whole cost of a search once the session is through.
So the bootstrap costs about three times more than a search. With five searches per session, the bootstrap was 41% of all request-based traffic. That makes the bootstrap the number to manage, and session stability is how you manage it.
Why clean IPs matter more than pool size
The bootstrap is a one-time cost only if the session lives. Once Kasada accepts a session, you can keep using it. In our longest test, we ran five sessions with 100 searches each. Every one of them got through all 100 searches on a single bootstrap, and Kasada never blocked them. Over those runs, traffic averaged 106 KB per search, because the bootstrap was spread across so many searches.
Every time a session dies, you start over: a new IP, a new block page, and a new bootstrap. A session can die for two reasons:
The IP is already flagged. IPs from a heavily abused pool can already be known to bot protection services. The site blocks them, and you pay for a bootstrap that leads nowhere.
The connection fails. A residential IP is a real device on a real home network. If it drops mid-download, you have to do the bootstrap again.
The chart below shows what that does to the bill. It uses the bootstrap and search costs we measured and asks one question: what happens as more sessions have to start over?
In our runs, no request-based session had to start over because of its IP. Kasada didn't block any session again after it cleared the check. The model puts that case at 174 MB per 1,000 searches; the 178 MB we measured also includes retries. If half of all sessions had to start over, the same scraper would move 244 MB per 1,000 searches. Most of that extra traffic buys nothing: it pays for bootstraps on sessions that fail anyway.
That's why pool size alone doesn't tell you what a proxy network will cost you. At high volume, what counts is how many successful searches each bootstrap buys. A huge pool of flagged or unstable IPs makes you pay for a bootstrap on every attempt. A pool of clean, stable residential IPs lets each bootstrap pay for many searches.
If you're choosing proxies for a high-volume job, look past the pool size. Run a short test like this one and measure traffic per successful result, restarts included.
Practical tips
Measure at the proxy, not in DevTools. Chrome's DevTools doesn't count TLS handshakes, request headers, or downloads cut off by the next page load. In our default browser runs, it reported 25% less traffic than the proxy carried.
Keep sessions alive. Use sticky sessions so one IP stays with one session, and reuse a session for as many requests as the site allows. With SOAX, a session ID in the username and the On error rotation rule do this for you.
Block what you don't need. If you must use a browser, block images, fonts, media, and third-party scripts. It cut our browser traffic by 72%.
Go request-based when you can. If the data is in the HTML or in an API response, you don't need to render the page. It's more work to build, but it moved 22 times less traffic in our test.
FAQ
Does headless browser scraping use more proxy bandwidth?
In this benchmark, yes, by a wide margin. On Hyatt hotel searches over SOAX US residential proxies, a default headless browser used 4.0 MB per search, a browser with assets blocked used 1.1 MB, and a request-based scraper used 178 KB. Other sites will give different numbers, but here most of the browser's extra traffic was JavaScript and images the scraper didn't need.
Why does proxy quality matter for large-scale scraping?
Because every session that fails has to pass bot protection again. In our test, that bootstrap cost 342 KB, about three times more than a search. Stable, clean IPs let one bootstrap cover many searches, so pool size alone doesn't tell you what your traffic will cost.
Why do sticky proxy sessions matter?
A sticky session keeps the same IP for the whole session. That keeps a session that bot protection has already accepted alive, so you spread one bootstrap over more successful requests. In our longest test, five sticky sessions each ran 100 searches on a single bootstrap and averaged 106 KB per search.
When should you use request-based scraping instead of a browser?
When the data you need is already in the HTML or in an API response, and your volume is high enough that bandwidth matters. In our test, the request-based scraper moved 22 times less traffic than a default browser. It's more work to build, so if you must use a browser, blocking assets cut our browser traffic by 72%.
What tools were used in this benchmark?
We used SOAX US residential proxies with sticky sessions. Both browser scrapers ran headless Chrome with Playwright and solved Kasada with the Hyper Solutions Playwright SDK. The request-based scraper was a Go program that used the Hyper Solutions Go SDK and API.
Methodology notes
Dates and scale. We ran the tests on October 8, 2026 on SOAX US residential IPs, five searches per session. The longest test ran five more request-based sessions with 100 searches each.
What counts. Traffic is what our counting proxy saw between the scraper and SOAX, divided by the number of searches that returned prices. Failed attempts and retries are included.
Browser setup. The browsers were Chrome 154 in headless mode with a fresh browser context per session. The default browser moved on to the next search when the page's load event fired. The browser with assets blocked moved on when the HTML was parsed.
Out-of-band API calls. The calls to the Hyper Solutions API went straight from the scraper's machine, not through the proxy, so they are not counted.
This benchmark was run by the engineering team at Hyper Solutions, which provided the Kasada tooling used in both the browser and request-based tests.
&w=3840&q=75)
&w=3840&q=75)
&w=3840&q=75)
&w=3840&q=75)