{"slug": "i-built-a-json-toolkit-that-never-sends-your-data-anywhere", "title": "I built a JSON toolkit that never sends your data anywhere", "summary": "A developer built JSONLinter, a client-side JSON toolkit with 42 tools across six categories, ensuring data never leaves the browser. The project uses React 19, TypeScript, Vite, Tailwind v4, and CodeMirror 6, and includes a prerendering solution using headless Chromium to serve real HTML to crawlers without SSR. An optional AI assistant supports bring-your-own-key for OpenAI or Anthropic, with no backend involved.", "body_md": "Most \"paste your JSON here\" tools online send that JSON to a server to\n\nprocess it. For internal API responses, config files, or anything with\n\nreal data in it, that's not something I wanted to do — so I built\n\n[JSONLinter](https://jsonlinter.io), a JSON toolkit where literally\n\neverything happens client-side.\n\nIt started as a validator/formatter, then grew into 42 tools across six\n\ncategories:\n\nThere's also an optional AI assistant on the validator page — it's\n\nbring-your-own-key (OpenAI or Anthropic), and since there's no backend at\n\nall, the key and your JSON go straight from your browser to the provider.\n\nI never see either.\n\nStack is React 19 + TypeScript + Vite, Tailwind v4 for styling, CodeMirror\n\n6 for the editor. A few things I had to solve that were more interesting\n\nthan expected:\n\n**Prerendering without SSR.** I didn't want to take on a Next.js-style\n\nserver just to get real HTML for crawlers. Instead, the build runs a\n\nheadless Chromium pass (Playwright) over every route after `vite build`\n\nand saves the fully-rendered output to `dist/<route>/index.html`\n\n. Crawlers\n\nget real content and correct per-page meta tags on first paint; once JS\n\nloads, React takes over exactly like a normal SPA. No server, no\n\nhydration mismatches to worry about.\n\n**Structural JSON diff.** A text diff on two JSON documents is mostly\n\nuseless because key order doesn't matter semantically. The diff tool\n\nparses both sides and compares the actual structure, so reordering keys\n\nshows as no change, but changing a value does.\n\n**Selection highlighting, CodeMirror edge case.** CodeMirror renders its\n\nselection layer *behind* the text layer (z-index -2, deliberately, so\n\nglyph rendering stays crisp), while the active-line highlight paints on\n\nthe text layer itself. If the active-line background is opaque, it\n\ncompletely hides the selection highlight on whatever line your cursor is\n\non — which is every line right after a double-click. Fix was making the\n\nactive-line background translucent instead of a solid fill, so it blends\n\nwith the selection color underneath instead of occluding it. Took a while\n\nto track down since \"selection isn't visible\" and \"double-click doesn't\n\nwork\" looked like different bugs at first.\n\nIt's live at [jsonlinter.io](https://jsonlinter.io) — no signup, no\n\naccount, nothing to install. Would genuinely appreciate feedback, especially\n\non anything that feels missing compared to tools you already reach for.", "url": "https://wpnews.pro/news/i-built-a-json-toolkit-that-never-sends-your-data-anywhere", "canonical_source": "https://dev.to/sekhar_babu_1095c83b17413/i-built-a-json-toolkit-that-never-sends-your-data-anywhere-1nlm", "published_at": "2026-08-23 09:21:17+00:00", "updated_at": "2026-08-23 09:43:07.116532+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools"], "entities": ["JSONLinter", "React", "TypeScript", "Vite", "Tailwind", "CodeMirror", "OpenAI", "Anthropic"], "alternates": {"html": "https://wpnews.pro/news/i-built-a-json-toolkit-that-never-sends-your-data-anywhere", "markdown": "https://wpnews.pro/news/i-built-a-json-toolkit-that-never-sends-your-data-anywhere.md", "text": "https://wpnews.pro/news/i-built-a-json-toolkit-that-never-sends-your-data-anywhere.txt", "jsonld": "https://wpnews.pro/news/i-built-a-json-toolkit-that-never-sends-your-data-anywhere.jsonld"}}