The Weight of a Checkbox

Sage.is AI-UI asks you a few questions the first time you run it. Do you want to connect a model provider. Do you want to invite your team. Which features should be on.

Six checkboxes. One screen.

We measured what it costs to put that screen in front of you. On a cold load, the browser made 127 network requests and downloaded 1.9 megabytes.[1]

This is our own software. We wrote it. Nobody else gets blamed for this number.

The Number We Ran on Ourselves

The measurement is not clever. We opened the setup wizard in a real browser and read the browser's own performance log, twice, on two separate runs. The results landed within one request of each other.[2]

To show six checkboxes, the old path needed:

  • 127 network requests
  • 1.9 megabytes transferred
  • 699 milliseconds before anything readable appeared
  • 396 elements in the page

None of that is unusual. It is roughly what a modern web application costs, and most teams would call it fine. We had called it fine for two years.

What the Browser Was Actually Doing

A modern web app does not send you a page. It sends you a whole program.

Your browser downloads that program, starts it, and then the program turns around and asks the server what to draw. The server answers. The program draws it. That is three round trips and a compiler's worth of JavaScript to render a form that has existed in HTML since 1995.

There is a reason it works that way, and the reason is real: applications that need to feel instant after the first load are genuinely better built this way. A chat window is one of those.

A setup wizard is not. You see it once.

Three Requests

So we rebuilt the wizard's nine panels as ordinary pages. The server renders the HTML. The browser displays it. There is no program in between.

Old path Rebuilt
Time to content 699 ms 221 ms
Network requests 127 3
Data transferred 1.9 MB 4 KB
Elements on the page 396 50

Three requests: the page, the stylesheet, the icon. The content arrives inside the first one.

The server's share of that 221 milliseconds is not worth discussing. Rendering the settings panel takes 0.013 milliseconds. Rendering the full release-notes page (every version, every entry, seventy kilobytes of output) takes 0.379 milliseconds.[3] Everything else is the network and the browser.

That surprised us. We had assumed there was a server cost hiding somewhere. The round trips were the whole bill.

Then We Measured It on a Real Network

Every number so far was taken on the same machine, where the network delay is effectively zero. That is the most flattering condition a page with 127 requests will ever see, and our first write-up said the ratios would carry forward to real conditions.

That was wrong. They do not carry forward. They get worse.

Delay is charged per round trip. One path makes three. The other makes 127. So we ran both again with the browser's network throttled to conditions our customers actually work in.[4]

Network Old path Rebuilt Gap
Same machine 538 ms 73 ms
Office broadband 554 ms 55 ms 10×
Shared school Wi-Fi 944 ms 52 ms 18×
Rural LTE, weak signal 1,863–2,274 ms 48–67 ms 28–47×

Read the rebuilt column downward. It barely moves. Forty-eight milliseconds to seventy-three, across conditions that differ by a factor of two hundred. The rebuilt page does not care what network you are on: there is almost nothing to fetch, so there is almost nothing to wait for.

The old path nearly quadruples over the same span. The code did not get slower. Every round trip started costing real time, and there are 127 of them.

What Speed Is Actually For

Sage.is runs on hardware you own. That is the whole product. Our customers put it in schools, in clinics, on boats, and in buildings where the network was installed once and has not been touched since.

In those buildings, 1.9 megabytes is a school Chromebook on shared Wi-Fi at nine in the morning, when every device in the building wakes up at once. Or a clinic on a satellite link. Or a site with no internet at all, where the machine works from whatever is already on it.

The gap between 52 milliseconds and 944 is the difference between a screen that is simply there and one you watch arrive. Multiply it by every screen a teacher opens before lunch.

The rebuilt pages have one more property, and it matters more than speed: they still work when the outside world is unreachable. We test this deliberately. Every release, we cut the connection to our stylesheet host and check that the pages remain usable.[5] An air-gapped installation is not an edge case for us. It is a customer.

The Part That Is Not About Speed

Two things fell out of this work that we did not go looking for.

Four secrets stopped leaving the server. The old setup screens loaded your stored credentials into the browser so the form could show them: both OAuth client secrets, your SMTP password, and your model provider API key. They arrived in the page and sat in your browser's memory. The rebuilt pages never send them. The field shows up empty and tells you a secret is stored. Leave it blank and the stored one stays.

That was a real exposure. It was ours, it was shipped, and it is now closed.

The software also learned 55 more languages. The old image carried one translation catalogue: English. It could not have answered in anything else. It now ships all 56, and it picks the right one from the address of the page you asked for.[6]

Neither change shows up in a timing table, and both are better reasons to have done the work.

What We Banked

Here is the part most write-ups leave out.

Until the end of July we had not deleted anything. Both versions sat in the codebase side by side so we could test them against each other and prove the new one did everything the old one did. That is the honest way to do it, and for a month the project made the software larger, not smaller. We said so in the first version of this article, because quoting a saving before the deletion landed was quoting a promise.

The deletion landed on 31 July 2026. The component that held the setup wizard together and the nine screens it opened (2,132 lines) went in one commit. What shows those screens to you now is 168 lines that fetch a page and put it in a window.

The saving is 522 lines, about 29% of what was there.[7] Our first two estimates did not survive contact with the actual deletion. This one did.

One of the nine panels is worse on paper. Rewriting the sign-in settings took 214 lines of server code to replace 65 lines of the old kind, so it costs us about 150 lines. We kept it anyway. It is the panel that stopped sending your OAuth secrets to your browser, and that trade is worth 150 lines of anything.

Why This Matters If You Run Your Own

If you rent your software, none of this is your problem. Somebody else pays for the bandwidth and the servers, and the weight of a page is a line in their budget.

If you run your own, every megabyte is yours. It crosses your network, on your worst connection, to hardware you bought. Software that is careless about weight is spending your money without asking you.

We are not going to claim we got this right the first time. We shipped 1.9 megabytes to display six checkboxes and did not notice for two years, because it worked fine on our laptops.

That is the trap. A developer's laptop has no network delay worth measuring, so it is the one place where 127 round trips look survivable, and it is where every developer tests. The cost only appears once there is distance between the user and the machine, and distance is what real users have.

Then we measured under that distance, and the gap went from seven times to nearly fifty.

The measurement is the point. Wright named his painting for the air pump, then spent the canvas on the faces around it: a family leaning in to see what survives when something is taken away.



The views expressed are those of the editorial board. Sage.is AI-UI is a product of Startr LLC, licensed AGPL-3.0 and self-hostable on hardware you control. The measurements in this article were taken against our own shipped software, and the least flattering of them are ours. Full disclosure and transparency is a feature, not a bug.


  1. Measured 31 July 2026 against Sage.is AI-UI 3.0.0 in the project's end-to-end test container, Chrome over TLS. Figures read from the browser's PerformanceResourceTiming API on a cold cache. Two independent runs: 126 and 127 requests, 1.76 MB and 1.93 MB. ↩︎

  2. A third run reused a warm bundle and transferred far less, but made more requests, not fewer. A warm cache does not close the gap. It moves where the cost is paid. We report the cold-load figures because that is what a first-time operator experiences. ↩︎

  3. Server-side render timing, 100 iterations each, measured inside the running container. The settings panel emits 2.7 KB in 0.013 ms; the release-notes page emits 70 KB in 0.379 ms. ↩︎

  4. Chrome's own network emulation, applied through the DevTools Protocol, measured twice. Profiles are round-trip delay and bandwidth: office broadband 20 ms / 20 Mbps, shared school Wi-Fi 80 ms / 5 Mbps, rural LTE edge 200 ms / 1.5 Mbps. Both runs agreed within a few milliseconds on every profile except rural LTE, where the old path varied between 1,863 ms and 2,274 ms, so the range is reported rather than an average. Our first write-up of this work claimed the localhost ratios would carry forward. They do not. Correcting that in public is cheaper than being quoted on it. ↩︎

  5. pages-cdn-outage.cy.ts in the AI-UI repository blocks the stylesheet host outright and asserts every control still renders and nothing overflows the screen. It runs on every release. ↩︎

  6. The language travels in the page address rather than a cookie. That keeps a page cacheable on its own address, which a cookie would prevent. It is the same approach Django has used for years, and we adopted the idea without adopting the framework. ↩︎

  7. 1,816 lines of the deleted implementation against 1,294 of the replacement (1,126 on the server and 168 in the component that shows those pages in a window). Code only on both sides: blank lines, comments and docstrings excluded. Two earlier figures were quoted and both were wrong. An internal note said 50%, which predated one of the nine panels. The first version of this article said 32%, which counted the server pages before the component that displays them existed. 29% is the number that survives the deletion actually landing. ↩︎