How I Built 15 Privacy Focused Dev Tools That Run in the Browser
Lessons from building Utilio, a suite of browser based developer tools with no sign ups and no server uploads: architecture, trade offs, and results.
Every developer has a folder of bookmarked utility sites: a JSON formatter here, a JWT decoder there, some Base64 tool with twelve ad banners and a suspicious “upload” button. I got tired of wondering where my data went every time I pasted a token into one of them, so I built my own. Utilio is a suite of 15 free, privacy focused, browser based developer tools where every byte you paste is processed in the browser, with no sign ups, no server uploads, and no tracking of your payloads. This post explains how I built it, the architecture decisions behind it, and what I’d do differently.
The full lineup: JSON beautifier, XML beautifier, Base64 encoder/decoder, MD5 hash generator, JWT decoder, regex tester, UUID generator, hash compare, QR code generator, case converter, lorem ipsum generator, text compare, markdown editor, IP lookup, and a browser info detector. All of them run entirely in your browser tab.
Why I built it
The trigger was a JWT. I was debugging an auth issue at work and needed to inspect a token’s claims. The obvious move is to paste it into one of the popular decoder sites. Except that token was a live credential for a real system, and I had no idea whether the site logged inputs, sent them to a backend, or piped them into an analytics blob. Most of these sites give you no way to verify. Some openly POST your input to their servers because that’s how they built the tool.
The same discomfort applies to almost every utility in the category. A JSON blob you’re formatting might contain customer emails. A Base64 string might decode to an API key. A text diff might be two versions of a confidential document. These are exactly the inputs you should never send to an unaudited third party server. And yet the tools we all reach for are ad funded pages with zero transparency about data handling.
There’s also a quality problem. Ad heavy tool sites are slow, cluttered, and hostile: cookie walls, interstitials, “premium” nags for features that are three lines of JavaScript. None of these tools need a server. Formatting JSON, decoding a JWT, generating a UUID: every one of these operations can run locally in the browser, instantly, for free.
So the pitch to myself was simple: build the 15 tools I actually use, make every one of them provably run in the browser, ship them fast, and never ask anyone to create an account.
The architecture behind browser based developer tools
The entire suite is a Next.js App Router project compiled with static export. There is no backend. next build with output: "export" produces a folder of plain HTML, CSS, and JavaScript that can be served from any static host or CDN:
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "export",
trailingSlash: true,
images: { unoptimized: true },
};
module.exports = nextConfig;
That one config line is doing a lot of work. It means there is no server to upload data to even if I wanted one: the privacy promise is enforced by the architecture, not by a privacy policy. It also means hosting is effectively free and the site survives any traffic spike a static CDN can handle, which is all of them. I wrote up the details, including the sharp edges, in my Next.js static export guide, so I’ll keep the overview short here.
Each tool page follows the same pattern: a statically rendered shell (heading, description, FAQ content, everything crawlers need) that hydrates a single client component containing the interactive logic.
The tool logic itself leans on platform APIs wherever possible. Hashing is the best example. Instead of shipping a crypto library, the SHA family comes straight from the Web Crypto API:
async function sha256(input: string): Promise<string> {
const data = new TextEncoder().encode(input);
const digest = await crypto.subtle.digest("SHA-256", data);
return [...new Uint8Array(digest)]
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
}
Zero dependencies, hardware accelerated, and the input never leaves the function scope, let alone the machine. The one exception is MD5: crypto.subtle deliberately doesn’t implement it because it’s broken for security purposes, so that tool uses a small pure JS implementation and the page says plainly what MD5 is still good for (checksums, legacy compatibility) and what it isn’t (anything security sensitive).
The same “platform first” rule shaped the other tools. The JWT decoder is atob plus JSON parsing with proper base64url handling. A decoder needs no secret and no server, since the payload of a JWT is just encoded, not encrypted. The UUID generator is crypto.randomUUID(). The regex tester runs the browser’s own regex engine, which has the nice side effect of testing the exact behavior your JavaScript will have in production. For the few places a real dependency earned its place (QR code generation, structured text diffing, markdown parsing), I picked small, focused libraries and checked what they added to the bundle before committing.
The two tools that look like exceptions are IP lookup and the browser info detector, and the honest answer is that they’re the boundary cases. Browser info is read entirely from navigator and friends locally. IP lookup necessarily involves a network request, since you can’t learn your public IP without asking someone outside your network, so that page is explicit about the request it makes. Being clear about the exception, rather than pretending it doesn’t exist, felt more honest than quietly breaking the rule.
Design decisions
Neobrutalism, on purpose
The UI uses a neobrutalist style: thick borders, hard offset shadows, unapologetic colors. Partly taste, but mostly strategy. Utility sites in this space all look the same: gray, dense, forgettable. A distinct visual identity makes the site memorable enough to come back to without a bookmark, and the style is cheap to implement consistently: a handful of Tailwind utilities and CSS variables cover all 15 tools. Constraints like “every card is a bordered box with a 4px shadow” also kill design bikeshedding, which matters a lot on a side project where design time competes directly with shipping time.
Zero backend as a feature, not a compromise
No backend means no database, no auth, no rate limiting, no server bills, no 3 a.m. pages. It also forced good scoping: any tool idea that required a server got cut or redesigned until it didn’t. That constraint is why the suite exists at all: a version of this project with accounts and a backend would still be half finished.
Instant tools, no ceremony
Every tool works the moment the page loads. No sign up wall, no “choose your plan,” no cookie consent theater beyond what’s legally necessary, because there’s nothing to consent to when nothing is collected. Output appears as you type wherever that’s feasible, because a format button is one more click than a useEffect. The bar I held myself to: a tool should be usable faster than it takes the average competitor page to finish loading its ads.
AI assisted, human reviewed
Fifteen tools is a lot of UI that’s repetitive but not identical. I leaned heavily on AI pair programming for scaffolding tool pages, generating test cases (especially nasty regex and Unicode edge cases), and porting the same layout pattern across tools. I’ve written about my workflow in how I use AI coding assistants: the short version is that assistants are excellent at the fifteenth variation of a pattern and dangerous at the first, so I hand built the first tool page carefully and let the assistant replicate it.
What I learned
Static export gotchas are real, but front loaded
output: "export" disables anything that needs a server at request time: dynamic route handlers, on demand image optimization, middleware, server actions. You find this out the hard way once, then design around it. The workflow that saved me: run next build locally early and often, because the export step is where these errors surface. Dev mode will happily run code that the export will reject. Also, decide on trailingSlash on day one; changing URL shape after search engines have indexed you is self inflicted pain.
SEO for tool pages is its own discipline
A tool page with just an input box is thin content to a crawler, no matter how useful the tool is. Every Utilio page got real prose: what the tool does, how the format works, common pitfalls, and an FAQ, content that exists in the static HTML, not behind hydration. Titles target the phrases people actually search (“JSON beautifier online” beats “JSON Tool”). Each page also got proper metadata, structured data for the FAQ sections, and internal links between related tools (the Base64 page links to the JWT decoder, because that’s a real user journey). None of this is glamorous; all of it is why individual tool pages can rank at all.
Scope control decides whether side projects ship
My original list was around 40 tools. I cut it to 15 by asking one question per tool: have I personally needed this in the last six months? That filter removed everything speculative and kept the suite coherent. The other scope rule: no tool gets settings before it works from end to end with sensible defaults. Options are easy to add later and impossible to remove.
Trust needs to be verifiable, not asserted
“We don’t upload your data” is a claim every site makes. What actually convinces developers: open the network tab, use the tool, watch nothing happen. Architecture that makes the privacy claim checkable in ten seconds is worth more than any policy page, and it’s the thing I’d tell anyone building privacy focused dev tools to optimize for.
FAQ
Are browser based dev tools safe for sensitive data?
Safer than server based alternatives, with one caveat. When processing genuinely happens in the browser, your input never crosses the network. The operative risk is the same as any local software: do you trust the code being served? You can verify behavior yourself by watching the network tab while using a tool. For truly critical secrets (production signing keys, for example), the strictest answer is still local, offline tooling. But for the everyday case of formatting JSON or decoding a JWT during debugging, a tool that verifiably runs in the browser eliminates the biggest risk, which is handing your payload to an unknown server.
Why not build a CLI instead?
I use CLIs daily, and jq, openssl, and uuidgen cover some of this ground. But browser tools win on three fronts: zero installation (useful on locked down machines, or anyone else’s machine), a visual interface where it matters (diffs, regex match highlighting, QR codes, live markdown preview), and shareability. I can send a colleague a link instead of installation instructions. The two aren’t competitors; the browser versions are for the moments a terminal isn’t the right surface.
What stack do you need for browser based tools?
Less than you’d think. The essentials: a framework that produces static output (Next.js with output: "export" in my case, though Astro or plain Vite work fine), components that run in the browser for interactivity, and the browser platform itself. Web Crypto for hashing, crypto.randomUUID(), TextEncoder/TextDecoder, the built in regex engine. Add small focused libraries only where the platform has a gap (QR generation, diffing, markdown parsing). Any static host serves the result. No database, no auth, no API layer: the absence of a backend is the point.
Wrapping up
Building Utilio confirmed a suspicion I’d had for years: most developer utilities never needed a server, and the ones that have them mostly serve the site owner, not you. A static Next.js export, the browser’s own platform APIs, and disciplined scope produced a suite of browser based developer tools that are fast, free to run, and private by construction rather than by promise.
If you want to see the result, or just need to decode a JWT without wondering who’s reading it, the tools are live at utilio.naumanm.dev. Open the network tab while you use them. That’s the whole pitch.
Get new posts in your inbox
No spam, no fluff: one email when I publish something worth your time. Unsubscribe anytime.
Signup opens soon. Grab the RSS feed meanwhile.
Keep reading
Next.js Static Export: The Complete Guide (What Works, What Breaks)
A practical guide to output: 'export' in Next.js: supported features, common breakages, image handling, routing gotchas, and deploying to a static host.
How I Actually Use AI Coding Assistants as a Senior Engineer
A senior engineer's real AI coding workflow: where assistants genuinely help, where they waste time, and the habits that make the difference
From Mid Level to Senior Engineer: What Actually Changes
The senior title isn't about harder code. What changed for me: ownership, ambiguity, communication, and multiplying the effect of everyone around me.