What each CAPTCHA loads (2026)
Updated
A form widget runs on every page that shows your form. I put each of eight widgets on the same small page. I loaded each page in a headless browser and counted what the widget adds: bytes, requests, cookies and other domains.
I make Bot403, one of the eight widgets. For this reason, read the method and the caveats. The raw data has every request of every run.
Results
The byte, request and cookie counts are medians of 3 runs on 23 October 2026, with Chromium 153.0.8010.12 headless, Playwright 1.55.1. The bytes are the transferred bytes, compressed as the server sent them.
| Widget | All bytes | Script bytes | Requests | Cookies | Other domains | Token with JS / without |
|---|---|---|---|---|---|---|
| reCAPTCHA v3 | 469.1 KB | 357.4 KB | 15 | 1 third-party | 3: fonts.gstatic.com, www.google.com, www.gstatic.com | yes / no |
| reCAPTCHA v2 (checkbox) | 469.1 KB | 357.4 KB | 15 | 1 third-party | 3: fonts.gstatic.com, www.google.com, www.gstatic.com | yes / no |
| Cloudflare Turnstile | 202.9 KB | 28.3 KB | 3 | none | 1: challenges.cloudflare.com | yes / no |
| hCaptcha | 317.3 KB | 112.0 KB | 6 | 1 third-party | 4: *.w.hcaptcha.com, api.hcaptcha.com, js.hcaptcha.com, newassets.hcaptcha.com | yes / no |
| Friendly Captcha | 84.9 KB | 14.2 KB | 5 | none | 2: cdn.jsdelivr.net, global.frcapi.com | no / no |
| ALTCHA | 33.0 KB | 32.7 KB | 2 | none | 1: cdn.jsdelivr.net | yes / no |
| Cap | 27.0 KB | 26.8 KB | 4 | none | 1: cdn.jsdelivr.net | yes / no |
| Bot403 | 6.8 KB | 6.4 KB | 2 | none | 1: bot403.com | yes / no |
"All bytes" counts every response: scripts, frames, styles, fonts, images and API calls. "Script bytes" counts only JavaScript and WebAssembly files. Several widgets run in a frame, and the HTML page of the frame contains most of their code inline. For these widgets, "All bytes" is the better number. "Token with JS" shows whether the widget put a token in its form field during the run. "Without" is the same form, sent with JavaScript off.
What I measured
For each widget, I counted:
- The bytes that the browser downloads.
- The number of requests.
- The cookies, from the test page and from other domains.
- The other domains that the browser connects to.
- If the form gets a token, with JavaScript and without it.
How I measured
- Each widget has its own HTML page, served from a local server on 127.0.0.1. The page has one text field, a submit button and the embed code from the widget's docs. Nothing else is on the page.
- Each run starts with a new browser profile. The cache is empty and no cookies remain.
- The browser opens the page and waits until the network is idle. It clicks in the text field, because some widgets start on focus. If the widget has a checkbox, the browser clicks it too. Then it waits until the token field has a value, for 15 seconds at most, and then 3 seconds more.
- Each request after the page counts, with the size of its response body as transferred. Headers do not count. A file that a frame takes from the memory cache does not count as a request.
- The cookies are the cookies in the browser after the run. First party means 127.0.0.1, the test page. Third party means every other domain.
- For the test without JavaScript, a second browser with JavaScript off sends the form. The local server checks whether the widget's field arrived with a value.
The setup of each widget
- reCAPTCHA v3
- api.js?render= and grecaptcha.execute() on the first focus. Google publishes no v3 test key, so the run uses its documented v2 test key; Google still returned a token for it. A production v3 key may load a different amount.
- reCAPTCHA v2 (checkbox)
- The checkbox with Google's public test key. The key always passes, so no image puzzle loads.
- Cloudflare Turnstile
- The managed widget with Cloudflare's public test key that always passes. A test key may skip the checks a real key runs.
- hCaptcha
- The checkbox with hCaptcha's public test key that always passes, so no image puzzle loads.
- Friendly Captcha
- The v2 SDK (@friendlycaptcha/sdk 1.1.1) from jsDelivr, as the Friendly Captcha docs show. There is no public test key, so the run uses a dummy key: the widget loads and its API refuses the key, so no puzzle is solved and no token comes back.
- ALTCHA
- The widget (altcha 3.5.0) from jsDelivr with auto="onfocus". The challenge comes from this local server (altcha-lib, SHA-256), as a self-hosted install does.
- Cap
- The widget (@cap.js/widget 0.1.58) from jsDelivr. The challenge and redeem endpoints run on this local server (@cap.js/server), as a self-hosted install does. The widget loads its WebAssembly solver from jsDelivr when it starts.
- Bot403
- The script tag from the quickstart, served by a local Bot403 server with a real site. In production the script and the challenge come from bot403.com, so the other domain is bot403.com. On the same day, one GET of the production script (https://bot403.com/v1/bot403.js) transferred 6.3 KB, compressed with gzip.
Caveats
- With a test key, a widget can load less than with a production key. The Turnstile and hCaptcha test keys always pass. A real visitor with a real key can get more checks and more files.
- reCAPTCHA has no v3 test key. The v3 row uses the v2 test key from Google. Google still returned a token for this key.
- Friendly Captcha has no public test key. Its row uses a dummy key. Its API refused this key, so the widget did not solve a puzzle. With a working key, the widget also gets and solves a puzzle. Thus it probably loads more.
- ALTCHA and Cap are self-hosted. Their challenge requests went to the local server. On a real site, they go to your own server, so they add no other domain.
- Numbers change with every release of a widget. These numbers are for the versions that the vendors served on 23 October 2026.
- The test used one browser, one computer and one network in the EU. A CDN can send different files to a different browser or country.
- No widget makes a token without JavaScript, and Bot403 does not either. If a form arrives without a token, the check fails. Your server then decides what to do with the form.
Raw data
captcha-weight-2026.json has the setup, the median and every run of each widget, with the URL, type and bytes of each request. If a number is wrong or a widget changed, email me. Then I will run the test again.