4 min read
What a tool downloads before you press anything
Our background remover was sending 1386 KB of JavaScript to your phone before you had chosen a photo. Nobody had asked for it and nothing on the screen needed it. Here is how it got there, what we cut it to, and how to measure any tool the same way in about thirty seconds.
The number nobody publishes
Every tool site publishes its feature list. Almost none publish what a page weighs before you use it. That number decides how a tool actually feels: on a phone on a normal mobile connection, roughly every 400 KB of JavaScript is another second of staring at a page that looks ready but is not.
For us it matters more than for most. nopa runs on your device — the merge, the compression, the transcription all happen in your browser, so nothing is uploaded. The flip side of that promise is that the code has to arrive first. The download is not overhead around the product. It is the product arriving.
How we measured it
A script in our repo opens each route in a real Chromium, with an empty cache and the service worker disabled, and adds up the transferred bytes of every script the page pulls before any interaction. Not the unzipped size, not the bundle report — the bytes over the wire, which is what your connection actually pays for.
We ran it across the whole site: the home page, the catalogue and hub pages, and every tool page. Seven routes came back over a megabyte.
What we found in our own code
The before column is what we shipped. The after column is the same page today, with no feature removed from any of them.
| Page | Before | After |
|---|---|---|
| Background remover | 1386 KB | 405 KB |
| Emoji picker | 1318 KB | 740 KB |
| Transcriber | 940 KB | 402 KB |
| File converter | 845 KB | 403 KB |
| Reader | 839 KB | 427 KB |
| Home page | 325 KB | 28 KB |
| Catalogue and hub pages | 318 KB | 21 KB |
It is never the feature. It is the import.
Not one of these pages was heavy because of what it does. Every case was a single line at the top of a file, pulling in something the page would never run.
- A check for “is the AI model already downloaded?” imported the whole machine-learning runtime — 539 KB — onto pages that never load a model. It now reads the browser cache directly, in nine lines.
- A zip helper was imported at the top of the PDF engine, so any page that touched zipping also downloaded 443 KB of PDF code. Loading the helper at the moment it is used cut four tool pages in half.
- The emoji picker shipped its keyword table — half the dataset by weight — before a single keystroke. It now arrives with your first search, which is the only time anything reads it.
- A whole animation library was loading for one sheet that slides up on phones. The browser has an animation API built in; the library went.
- A 373 KB catalogue index was loading on every page to render one row of “related tools” links.
Why there are no competitor numbers here
We wanted to put other tools in that table. We could not do it honestly. Our first attempt fetched competitors’ pages and counted the scripts in the HTML; it reported that a well-known PDF suite ships 2 KB of JavaScript, because the real application is loaded by the JavaScript, not written into the page. A number we cannot reproduce is worse than no number, and a benchmark where we grade ourselves is not a benchmark.
So the table above only contains pages we own, and instead of numbers you have to take on trust, here is the method.
Measure any tool in thirty seconds
This works on any site, including ours. If our figures are wrong, this is how you catch us.
- Open the tool in a desktop browser and open developer tools (F12), Network tab.
- Tick “Disable cache”, filter to JS, then reload the page.
- Read the transferred total at the bottom before you click anything. That is the download you pay for on every cold visit.
- For the local-first claim: after the page loads, switch the network to offline and run your job. If it completes, the work is on your device. If it fails, your file was going somewhere.
What we hold ourselves to now
Every route has a hard ceiling of 600 KB of JavaScript, and the script that measures it fails loudly when a page goes over. That is what keeps this from coming back: the four fixes above took a day, but the reason they were needed for months is that nobody was counting.
The tools are here whenever you need them, and none of them will ask you to sign up to find out how heavy they are.