Privacy by Architecture: How Browsy Keeps Your Data Private by Design
Most AI tools promise privacy in their policy. We built it into the architecture so there's nothing to promise — your data has nowhere to go but where you send it.
Key takeaways
- Browsy has no backend servers — your text travels directly from your browser to Gemini or Grok, and the response comes straight back.
- Your API key lives in chrome.storage.local only — device-local, never synced, never transmitted to Browsy.
- The background service worker is the sole AI egress point. Content scripts on pages you visit cannot make API calls directly.
- Shadow DOM (closed mode) prevents page JavaScript from reading what Browsy displays in its toolbar or result card.
- You can verify the architecture using Chrome DevTools Network tab — every AI call goes to your provider's domain, nothing to browsy.ai.
On this page
Privacy policies are written by lawyers, for lawyers, to protect companies from liability. They describe what a company can do with your data in the broadest possible terms, with enough hedging to leave room for future decisions that haven’t been made yet.
The alternative — and this is what we built — is to structure the system so there’s nothing meaningful to decide. If your data never reaches our servers, we can’t store it, analyze it, sell it, or lose it in a breach. That’s not a policy choice; it’s an architectural constraint.
This post describes how that architecture works and why we made the specific decisions we did.
The problem we were solving
Most browser AI extensions work as proxies. You highlight text, click a button, and your text travels to the extension’s servers, which forward it to an AI API, receive the response, and return it to you.
This model has practical advantages — the extension can add features, apply consistent model settings, and manage provider relationships on your behalf. But it introduces a party in the middle who has access to everything you ask the AI: your draft emails, your documents, your questions about sensitive topics.
That party has a privacy policy, presumably. They’ve made choices about retention, logging, training data, and third-party sharing. You’ve probably agreed to those choices without reading them, because the alternative was not using the tool.
We built Browsy to remove that party from the equation, not by having a better privacy policy, but by eliminating the role entirely.
How the data flow actually works
When you use Browsy to rewrite a paragraph, here’s what happens at the code level:
- You select text in a text field on a webpage
- The content script detects the selection and renders the toolbar (inside a closed Shadow DOM, isolated from the page’s own CSS and JavaScript)
- You click “Rewrite”
- The content script sends a message to the background service worker: “run the rewrite command”
- The background service worker reads your API key from
chrome.storage.local - The background service worker assembles the request: selected text + a system prompt template
- The background service worker sends a direct HTTPS request to the Gemini or Grok API endpoint
- The streaming response arrives back at the background service worker
- The background service worker streams tokens back to the content script over an internal Chrome message port
- The toolbar displays the tokens as they arrive
- You click Replace and the text swaps in
At no point in this sequence does anything touch a browsy.ai server, because there isn’t one.
Why the background service worker matters
Step 4 above is important: the content script doesn’t make the API call. The background service worker does.
This is an intentional invariant in Browsy’s architecture, encoded as a test that fails CI if it’s ever violated. The reason is twofold:
CORS. The content script runs in the context of the page you’re visiting. Most AI APIs have CORS restrictions that prevent browser pages from calling them directly — these restrictions exist specifically to prevent third-party scripts from silently calling AI APIs from within pages you visit. The background service worker runs outside the page context and doesn’t have this restriction.
Privacy guarantee. If content scripts could make API calls, a future module could inadvertently (or intentionally) expose keys or text through the wrong channel. By centralizing all AI egress in the background service worker, there’s one place to audit, one place to test, and one place where the “no data leaves except to the provider” invariant must hold.
Where your API key is stored
Your API key goes into chrome.storage.local.
This is meaningfully different from chrome.storage.sync. The sync storage backs up to your Google account and roams across devices. The local storage stays on your device, period. We chose local intentionally and enforce it: there’s a test in CI that asserts no key material ever appears in sync storage.
The key is also never included in log messages (the logger strips anything matching an API key pattern), never sent in cross-runtime messages (only the background service worker reads it to make API calls), and never exposed to the content scripts running on pages you visit.
If you’re security-conscious, you can rotate your API key at any time — generate a new one from your provider, paste it into Browsy, and the old one is useless even if someone had it cached somewhere.
Shadow DOM and page isolation
Browsy’s inline UI — the selection toolbar, the result card — runs inside a closed Shadow DOM.
Shadow DOM is a browser feature that creates a scoped subtree with isolated CSS and JavaScript. The “closed” variant adds an additional restriction: no external code can access the .shadowRoot of the element. This means the webpage’s own JavaScript can’t reach into Browsy’s UI to read what’s displayed there.
This matters in a few scenarios:
- Malicious or analytics-heavy websites can’t scrape what Browsy shows you
- Page-level JavaScript can’t intercept the text you’re rewriting
- Browsy’s CSS doesn’t bleed into the page’s styling, and vice versa
The accessibility tree is not affected — screen readers can still access the UI because ARIA roles and attributes are exposed outside the shadow root.
What permissions Browsy requests and why
Browsy requests host permissions to the domains it needs to call:
https://generativelanguage.googleapis.com/*— Gemini APIhttps://api.x.ai/*— Grok API
These are optional permissions, requested only when you add a key for a given provider. If you only use Gemini, Browsy never requests permission to contact xAI’s API.
The catch-all <all_urls> permission (which many AI extensions use) is something we’ve documented in our security review. Our extension needs to inject content scripts into pages where you want to use Browsy — that requires host permission for those pages. We’ve used <all_urls> because “any page” is the product’s actual scope, and we’d rather be honest about that than false-restrict it to a list that leaves things out. We’ve disclosed this in the Chrome Web Store listing with an explanation of what it’s used for.
What <all_urls> does not allow us to do: read page content we don’t specifically request (content scripts are explicit about what they read), make API calls on your behalf (all calls go through the background service worker and require your key), or transmit anything to our infrastructure (there is none).
What would have to go wrong for your data to leak
Given the architecture above, the realistic threat scenarios are:
Your AI provider is breached. If Gemini or Grok has a security incident, requests you made could be in logs. This is the same risk you have using any AI tool — moving to BYOK doesn’t eliminate it for the provider relationship, but it does eliminate the extension company as an additional attack surface.
Your device is compromised. If someone has access to your Chrome profile, they can potentially read chrome.storage.local. This is the same risk as any password or sensitive data stored locally.
A malicious Chrome extension has broad permissions. Another extension with <all_urls> permissions could theoretically intercept content script messages. This is a general Chrome extension security concern, not specific to Browsy.
A bug in Browsy. We could have a coding error that inadvertently sends data somewhere it shouldn’t. We test for the key invariants (no key in sync storage, no API calls outside the background worker), but we’re not infallible. The source is open — we’d encourage anyone who wants to audit it to do so.
What can’t go wrong: us deciding to start logging your data, selling access to your text, or having our servers breached — because none of those require a server.
Why we made this a structural choice and not a policy
A privacy policy is a statement of intent. It can change. Companies get acquired, business models shift, “we will never sell your data” becomes “we have merged with an entity that has different data practices.”
An architecture that has no mechanism to receive your data doesn’t need to make promises. The thing you’re trusting is the code, which you can read, and the absence of infrastructure, which you can verify by looking at DNS records and network requests.
We built Browsy this way because we think it’s the right design for a tool that runs on every page you visit. We also think it’s more defensible long-term — there’s no temptation to change the data model when there’s no data model to monetize.
Want to verify the architecture yourself? Open Chrome DevTools (Network tab) and make an AI request in Browsy. Every request will go to generativelanguage.googleapis.com (Gemini) or api.x.ai (Grok) — nothing passes through browsy.ai. You can also inspect the extension’s manifest and content scripts in chrome://extensions with Developer mode enabled.