Paste a JWT into a "free online JWT debugger." Paste a config file into a "free JSON formatter."
Then open DevTools, hit the Network tab, and watch it POST your payload to api.something-saas.com/v1/parse.
I got annoyed enough to check. Of the first dozen "free" tools I tried, eight shipped data off the device. Some had a privacy policy. Some had a privacy policy that said "we may share data with partners." Your production tokens, in a partner's S3 bucket.
Most of them weren't even doing it to be evil. They just built a Next.js app, needed the logic somewhere, and the server was already there. Formatter on the server. Base64 decode on the server. For a 3-line JSON.stringify.
The part that actually costs you
It's not just privacy theater. Server-side tooling has real costs you pay every day:
- Latency. Round-trip to a region that isn't yours, on a connection that isn't yours. My regex tester took ~400ms to say "no match."
-
Rate limits and paywalls. Free tier hits you at 10 operations. The tool that was "free" is now a $9/mo subscription for
btoa. - Availability. Their server goes down, your tool goes down. Great during an incident, when you actually need to decode something.
- Offline. On a plane, on a locked-down corporate network, the tool is gone.
Every one of those problems disappears if the code runs in the browser tab you already have open.
What client-side actually means
There is no API. There is no fetch to a backend. Network stays empty except for the static assets. Concretely:
// Base64, no server. 2 lines and no data leaves the tab.
const encode = (s) => btoa(String.fromCharCode(...new TextEncoder().encode(s)));
const decode = (s) => new TextDecoder().decode(Uint8Array.from(atob(s), c => c.charCodeAt(0)));
// JWT verify with a real signature check, in-page.
// WebCrypto handles HS256/384/512 and RS/ES via importKey.
const [h, p, s] = jwt.split(".");
const key = await crypto.subtle.importKey(
"raw", new TextEncoder().encode(secret),
{ name: "HMAC", hash: "SHA-256" }, false, ["verify"]
);
const sig = Uint8Array.from(
atob(s.replace(/-/g, "+").replace(/_/g, "/")), c => c.charCodeAt(0)
);
const ok = await crypto.subtle.verify(
"HMAC", key, sig, new TextEncoder().encode(`${h}.${p}`)
);
That's the whole "backend." The <input> is the API.
The interesting cases are where people assume you need a server:
| Task | Why people think it needs a server | How it's actually done client-side |
|---|---|---|
| SQL formatting | "Parsing is hard" | Tokenizer + formatter in a Web Worker — keeps the main thread at 60fps |
| Image conversion | "Encoding is server work" | Canvas + toBlob('image/webp')
|
| SVG to PNG | "Rasterization needs a service" | Draw the SVG into a canvas via a data-URI image |
| Regex testing | "Sandboxing" | It's a regex. RegExp has been in the engine forever |
| Hashing (SHA/MD5) | "Performance" |
crypto.subtle, native speed |
WebCrypto also gives you something the SaaS tools don't: the key never crosses the wire. A server-side JWT verifier has to receive your signing secret to check a signature. That's a much bigger deal than the payload leak.
What I built
23232322.xyz — 80+ tools, one page each, no build step. JSON formatter and validator, Base64 encode/decode, regex tester, JWT debugger with real HS256/384/512 and RS/ES256-512 verification, hash generators, UUID, URL encode/decode, diff checker, HTML minifier, and a bunch more.
No account. No upload. No analytics on your input. Source for each page is plain HTML + vanilla JS, so you can read it and confirm nothing is being sent anywhere.
How to check any tool yourself in 20 seconds
Before you trust any "free online X":
- Open DevTools → Network.
- Filter to Fetch/XHR.
- Use the tool with obvious dummy data (
{"test":1}). - If a request appears with your input in the body — that data left your machine.
Do that to my tools too. It's the point.
If a tool can't be written this way, it's because it needs a real backend. Most of them don't. They just needed somewhere to put the code.
The whole set is at 23232322.xyz.
Top comments (0)