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.