I ran two OCR engines and a BERT model entirely in the browser — here's what I learned
Every day, someone pastes a dashboard screenshot into Slack, a Jira ticket, or a slide deck with customer names, emails, and revenue figures still perfectly readable. The usual fix is a redaction tool — and almost every redaction tool uploads your screenshot to a server, which is exactly the thing you were trying to avoid. So I built VaultSnip: a free, open-source tool that finds and blurs sensitive text in screenshots. The constraint I set myself: everything runs on your device. No backend, no account, no upload. The whole app is static files on Cloudflare Pages; your screenshot never leaves the browser tab. That constraint forced me to run a full ML pipeline client-side. Here's what that actually took. The pipeline: two OCR engines and a PII model, all in the tab To decide what to blur, you first need to know what text is in the image and where. VaultSnip layers three engines, each running in a Web Worker: Tesseract.js does the fast first pass. Masks land in a few seconds, so the user sees results immediately. PP-OCRv5 (PaddleOCR's mobile detection + recognition models, as ONNX) catches what Tesseract misses — small print, low-contrast labels, text inside chart chrome. I run the official ONNX exports through ONNX Runtime Web and wrote the DB post-processing and CTC decoding myself in TypeScript. A BERT-small PII model (int8-quantized ONNX, via Transformers.js) classifies the recognized text: is this a person's name, an email, an ID, a company? That decides what gets masked versus left alone. A design rule that mattered more than any model choice: later passes only ever add masks, never remove them. The user watches the screenshot get progressively safer, and an engine disagreement can't un-redact something. Lesson 1: cross-origin isolation is the real price of admission ONNX Runtime Web's threaded SIMD build needs SharedArrayBuffer, and browsers only give you that when the page is cross-origin isolated — Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp headers on everything. That sounds like two lines of config. In practice it means every resource you load — every script, every wasm file, every model weight — must either be same-origin or explicitly opt in. It shaped the entire architecture: all models are bundled and served from the same origin, nothing is pulled from a CDN at runtime. Which turned out to be a feature. "No requests to third-party servers" stopped being a promise and became something you can verify in the Network tab. Lesson 2: model size is a UX problem, not a bandwidth problem The int8-quantized BERT is small by ML standards, and the PP-OCRv5 mobile models are a few megabytes each, gzipped. Users will wait for that once — if the app is honest about it and useful before the download finishes. That's why the layering matters: Tesseract.js (which is comparatively tiny) delivers first masks in seconds while the heavier models are still warming up. The slow part runs while the user is already getting value. Lesson 3: measure what you miss, and publish it Any detection pipeline misses things. Most tools in this space deal with that by never mentioning it. I went the other way: the repo has an automated benchmark that renders fictional dashboards, runs the full pipeline, and measures exactly how much readable text area survives unmasked. Right now that's about 0.25% of readable area, and the number is published in the repo's ACCURACY.md, failure cases included. This felt risky ("my tool's README admits it's imperfect!") and has been nothing but positive. Users trust a published 0.25% far more than an implied 0%, and the benchmark doubles as a regression gate in CI — no change ships if the number gets worse. Lesson 4: the replica — editing pixels in place Blurring is fine for chat, but sometimes you need a screenshot that still looks real — for a demo, a tutorial, a portfolio. VaultSnip's "replica" mode replaces each sensitive value, in place, with a synthetic one: same position, same font size, same color and alignment, with plausible fake data (via Faker, also running locally). The hard rule, enforced by a pixel-diff e2e test: zero changed pixels outside the replaced text boxes. No redrawing charts, no reconstructed layouts. A bar-chart edge that runs through a text box survives the replacement. The replica is the original image, surgically edited — which is the only way it stays believable. What it became What started as a web page is now also a Chrome/Edge extension (same pipeline, plus one-key blurring of charts on live pages) and a Windows desktop app (Tauri 2, with a global hotkey that snips any screen region straight into the masker). All of it Apache-2.0, all of it offline-capable. Try it (no sign-up): https://vaultsnip.pages.dev Source: https://github.com/karthikvalluri85/vaultsnip karthikvalluri85 / vaultsnip Turn sensitive report snips into client-safe replicas VaultSnip Blur sensitive text in any screenshot. Free, offline, in your browser. Paste a screenshot of a dashboard, report, table or app. VaultSnip finds names, numbers, emails and IDs and masks them on your device, shows the first masks within seconds, keeps checking in the background, and gives you a masked image you can copy straight into Slack, Teams, a ticket or a slide. Nothing is uploaded and nothing is stored. Try it: https://vaultsnip.pages.dev (no sign-up, no key, no upload) · Chrome · Edge · Hugging Face Works with screenshots of Power BI, Tableau, Looker, Qlik, Excel, Google Sheets, Salesforce, Jira, PDF report pages and any other app on your screen. On the desktop: a small app with a hotkey. Press Ctrl+Alt+V (Control+Option+V on a Mac), drag over the part of the screen you want, and once the check passes the masked image is on your clipboard. Installers are… View on GitHub If you've run models in the browser — or hit a wall trying — I'd genuinely like to hear how it went. And if you can break the masking with a screenshot it misses, file an issue; the benchmark suite grows from exactly those.
This is a summary aggregated from Dev.to. Read the complete article on the original site:
Read full article at Dev.to