"Runs in your browser" is a privacy claim that needs auditing, not trust. Browser-based AI means the computation happens locally, but the browser still makes network requests for many other reasons: loading the app, downloading model weights, fetching fonts, calling remote APIs, sending analytics beacons. An on-device chatbot can still leak your conversation to a server if any part of the pipeline phones home. This post is a practical checklist for figuring out what actually leaves the device — the same audit ReLU.chat's design aims to make trivially passable: no servers, no LLMs, no tracking, MIT-licensed and open source at https://github.com/yunusemrejr/relu-chat.

The Six-Step Audit

Step 1: Inventory the First Load

The most important network traffic happens before you type anything. Open DevTools, switch to the Network tab, and hard-reload the page with an empty cache (Ctrl+Shift+R). Then categorize every request:

  • The app's own HTML, JavaScript, and CSS.
  • Model weights. An on-device embedding model like all-MiniLM-L6-v2 (quantized ONNX, roughly 22 MB) is fetched once. ReLU.chat's service worker pre-caches the model and policy weights, so the download happens once and subsequent visits load from cache.
  • Third-party content: fonts, CDNs, analytics scripts, ad networks.

Anything in the last category deserves scrutiny. A "privacy-first" app should have none of it, or at most self-hosted fonts and resources.

Step 2: Watch a Live Conversation

Now type a message and watch the Network tab while the response streams. Filter to Fetch/XHR and WebSocket to ignore static resources. Ask three questions:

  1. Does any request fire per message? If yes, where does it go? That request carries the conversation to a server.
  2. Are there periodic beacons? Some apps send telemetry on a timer regardless of what you type.
  3. Do the requests carry query text in the URL or body? Inspect the payload of any request you find.

A useful trick is the Performance API, which lists every resource the page loaded without needing to watch the Network tab live:

const resources = performance.getEntriesByType("resource");
const dataCalls = resources.filter(r =>
  r.initiatorType === "fetch" || r.initiatorType === "xmlhttprequest"
);
console.table(dataCalls.map(r => ({
  url: r.name,
  size: r.transferSize
})));

Step 3: Go Offline and Keep Talking

The single most convincing test is to cut the network. In DevTools, open the Network tab, set throttling to "Offline", reload the page, and have a conversation.

  • If chat still works, inference is genuinely local: the model, the retrieval index, and the policy all live in the page or the service worker cache.
  • If the page refuses to load at all, check whether the service worker was installed on a previous visit (Application tab → Service Workers). A properly pre-cached app loads fully offline.
  • If the page loads but responses stall or error, something in the pipeline needs the network — a remote LLM, a search API, or an analytics endpoint that fails loudly.

ReLU.chat's service worker pre-caches model and policy weights precisely so that the heavy lifting works from cache; the three chatbots — Game Theory Chat, Golden Age Inquiry, and Data Science Chat at https://relu.chat/chat/game-theory-chat/, https://relu.chat/chat/golden-age-inquiry/, and https://relu.chat/chat/data-science-chat/ — plus the interactive ML tools at https://relu.chat/tools/ are designed to run fully in-browser.

Step 4: Audit Storage and Persistence

Network is not the only channel. Browsers provide several persistent stores, and each one can hold data you did not expect:

  • localStorage and sessionStorage — check the Application tab. Is a transcript being written to disk? Is it cleared when you leave the site? Does a "clear conversation" button actually wipe it?
  • IndexedDB — commonly used by ML pipelines for caching; inspect its contents.
  • Cache Storage — this is where service worker caches live. Cached model weights are fine; a cached transcript is data-at-rest you should know about.

For a chat app, ask: after closing the tab and reopening, does the conversation come back? If yes, it was persisted somewhere — find out where and whether clearing site data removes it. Session-only memory is the stricter privacy posture: state lives in the running page and evaporates with the tab.

Step 5: Read the Source

Closed-source claims of privacy are unverifiable. Open source is the only way to confirm that the code does what the landing page says. For ReLU.chat the repo is at https://github.com/yunusemrejr/relu-chat under the MIT license. When auditing a browser-AI project, look for:

  • Hardcoded API endpoints: search the source for fetch(, axios, WebSocket, XMLHttpRequest, and URL strings pointing at external hosts.
  • Third-party scripts included from other domains in the HTML head.
  • Telemetry libraries (analytics, crash reporting, session replay) that initialize on page load.
  • The model itself: where do the weights come from, and is the runtime (ONNX Runtime, transformers.js, WebGPU) doing inference locally?

The point of the audit is not to find malicious code — it is to confirm the absence of anything that transmits user data, because that is a property you can only verify, never assume.

Step 6: Consider the Residual Risks

Even a perfectly local app has a small residual surface:

  • The model weights themselves reveal nothing about the user, but their download footprint is visible to the network operator (only that a download happened, not its content).
  • The page's JavaScript can be updated by a future deployment; a privacy audit is a snapshot, not a guarantee. Pin versions and re-audit after updates.
  • Browser extensions and the browser's own telemetry are outside the site's control.

None of these undermine the on-device model; they just mean "verified today" rather than "true forever".

Key Takeaway

Privacy in browser-based AI is a checklist, not a slogan: inventory the first load, watch a live conversation for per-message requests, test offline, audit storage, and read the source. An open-source, serverless design — no LLM calls, no tracking, weights pre-cached by a service worker — makes every step of that checklist trivially green, which is exactly what a privacy-first chatbot should do.