日本語JA Current language: EnglishEN
Contact

"Your Files Never Leave Your Device": How to Check a Browser-Only Tool Yourself

Oct 9, 2026 Guide 12 min read

How to check, as a user, whether a web tool that claims not to upload your files really keeps them local. Combine Chrome DevTools' Network panel, an offline test, and the page's CSP, and know what each can and cannot prove.

Contents (9)

PDF converters, image compressors, Markdown previewers, transcription tools.

These days I keep seeing online tools that say "processed entirely in your browser" or "your files are never sent to our servers."

I build tools like that myself, so the claim matters a lot to me.

From the user's side, though, there is a problem:

A page saying "we don't upload your files" and your files actually not being uploaded are two different things.

A privacy policy does not show you the implementation. On the other hand, running in the browser does not mean a tool must be sending everything to a server. With the File API and WebAssembly, a tool can read and convert a file entirely on your device.

So is there a way for users to check for themselves where a file is going?

While researching this and trying it on my own tools, I found that the Network panel in Chrome DevTools alone tells you a lot. But it does not, on its own, prove that nothing could ever be sent.

The short version: look at both actual traffic and allowed traffic

When you check an online tool, it helps to separate three things.

The Network panel shows what was actually sent and received while you performed an action.

An offline test is supporting evidence for whether the processing works without a remote server.

The Content-Security-Policy (CSP) tells you where the browser is allowed to connect for that page.

Network is observation, CSP is a constraint, and the offline test is supporting evidence.

Rather than calling a tool "completely safe" based on any one of them, the realistic approach is to combine actual behavior with the page's structure.

Reference: Chrome DevTools: Network panel

First, look at what was actually sent

The easiest place to start is the Network panel in Chrome DevTools.

Open Network before you choose a file

In Chrome, open the page, open DevTools, and select Network.

On Windows you can use F12 or Ctrl + Shift + I; on a Mac, Command + Option + I.

The important part is to open the Network panel before the action you want to check.

Network records requests while DevTools is open. So check in this order:

  1. open the tool
  2. open Network
  3. clear the log
  4. choose a file
  5. run the conversion, preview, or other processing
  6. look at the requests that appeared at that moment

Just opening a page can trigger requests for JavaScript, fonts, analytics, and so on.

What you want to know is what new requests appeared the moment you chose a file or pressed the button to process it.

Look at All, not just Fetch/XHR

File uploads often use fetch() or XMLHttpRequest, so filtering by Fetch/XHR is useful.

But concluding "nothing was sent" from that filter alone is premature.

Data can also leave through WebSockets, beacons, images, form submissions, and more.

For example, suppose a Markdown file contains an external image like this:

![](https://example.com/pixel.png)

Even if the tool never sends the Markdown text itself to an API, displaying that image may send an HTTP request to example.com.

In other words, "the document is not uploaded" and "there is no external traffic at all" are different things.

When checking, it is safer to set Network to All and look at everything.

If a request looks suspicious, check the destination, Payload, and Initiator

When you select a request, Chrome shows Headers, Payload, Response, Initiator, Timing, and more.

The things to look at are:

  • which domain it is going to
  • what is being sent, for example in a POST
  • which code started the request

If a POST to an unknown API appears the moment you choose a file, and the Payload contains the file's data, then at the very least you cannot say the tool "processes everything in the browser."

On the other hand, the existence of network traffic is not automatically dangerous.

Analytics, error logging, web fonts, WebAssembly files, and a one-time download of an AI model are all traffic that has nothing to do with the contents of your file.

What matters is not whether there is traffic, but what is sent, where, and when.

Reference: Chrome DevTools: Network features reference

Next, test whether it works without a connection

After checking actual traffic in Network, an offline test gives you a hint about where the processing happens.

If it works offline all the way through, that is evidence of local processing

Chrome DevTools lets you switch the network condition to Offline.

Load the page and the resources it needs once, switch to Offline, and try the same file processing.

If, say, a Markdown conversion or image compression finishes while offline, it becomes much more likely that the tool does not need to contact a remote server every time to complete that processing.

This is not proof either, though.

The data it needs might still be in a Service Worker or cache. A tool could also be built to send usage logs only when it is online.

Conversely, a tool that downloads WebAssembly or an AI model the first time may fail to start offline on first use, yet still never send your files anywhere.

Working offline does not mean zero traffic when online.

To go one step further, check what traffic is allowed with CSP

Even if Network shows that nothing was sent right now, the implementation might still be able to send data.

That is where the Content-Security-Policy is worth checking.

connect-src restricts outbound connections from JavaScript

CSP lets the browser restrict where a page can load scripts and images from, where JavaScript can connect, and so on.

For example, with

Content-Security-Policy: connect-src 'none'

JavaScript connections covered by CSP are not allowed.

According to MDN, connect-src restricts the destinations of fetch(), XMLHttpRequest, WebSocket, EventSource, Navigator.sendBeacon(), and others.

This is different in kind from writing "we don't send anything" in a description.

If JavaScript tries to connect somewhere the policy does not allow, the browser itself blocks it.

Reference: MDN: CSP connect-src

When I built a tool, connect-src 'none' alone was not enough

This is where I actually got caught when building Markdown Viewer.

At first I thought blocking API calls would be enough.

But when I audited it, I found I was allowing images to load from any https: source.

So even with fetch() and similar calls blocked, an external image URL in the Markdown still left a path for a request to go out to fetch that image.

Now I also restrict img-src, so external images are not loaded as is.

I wrote up how that happened in How to Make "No Upload" Enforceable in the Browser.

Besides connect-src, CSP has separate controls for each type of request or resource, such as img-src, media-src, font-src, frame-src, and form-action.

So you should not conclude that outbound traffic is completely impossible by looking at a single directive.

A policy that starts from default-src 'none' is easier to read

When I read a CSP, I find deny-by-default policies the easiest to follow:

Content-Security-Policy:
  default-src 'none';
  script-src 'self';
  style-src 'self';
  img-src 'self' data:;

Everything is forbidden by default, and only the types that are needed are allowed.

This makes it less likely that a type you forgot to list ends up implicitly unrestricted.

But CSP does not solve web security as a whole.

It does not stop browser extensions or malware on your device, and it is not a feature that mathematically proves no information can ever leave your computer.

The fair way to put it: CSP is strong structural evidence, not a universal proof of safety.

Reference: MDN: Content Security Policy

Reference: MDN: CSP img-src

Easy mistakes when you investigate

Network and CSP give you a lot more to go on, but there are some easy ways to misjudge.

Mistaking a browser extension's traffic for the site's own

Extensions such as ad blockers, password managers, translators, and AI assistants may inject scripts into the page or make their own requests.

If you want to check carefully, it is easier to isolate the cause in something like a new browser profile with extensions disabled.

It is also important not to jump to "there is an unknown domain, so the tool sent it."

Treating "zero traffic" as "safe"

Even if there is no external traffic at all, the tool is not necessarily safe.

It might have a bug that corrupts files. The output might not be what you intended. A malicious input might make the browser sluggish.

What local processing reduces is one specific risk: handing your data to a third-party server in order to process it.

That needs to be kept separate from a guarantee of security as a whole.

Checking it yourself does not override your organization's rules

If you are handling contracts, code, unpublished drafts, or customer data, seeing nothing wrong in Network does not mean you are free to use the tool.

If your company or organization has a security policy, approval process, or data classification rules, those come first.

Record traffic separately for each stage of what you did

Whether the Network tab is empty or shows external requests, that single moment is not enough to conclude whether your document was sent. Splitting your actions into stages, like this, makes the investigation easier to reproduce:

Stage What to observe Watch out for
A: First page load Where HTML, CSS, JS, images, etc. are loaded from Do not confuse loading libraries with sending your document
B: Paste test content New requests and request bodies that appear Use dummy content with no personal information
C: Convert or preview Whether anything containing the file contents or text is sent Check not only URLs but also the Payload where possible
D: Save or download Where the result is stored Distinguish local saving, syncing, and server-side storage
E: Reload or go offline Whether the feature keeps working Pre-cached files alone do not prove that nothing is sent

It is also important not to claim that traffic you did not observe does not exist. Record the app version, browser, and the features and conditions you tested at the time.

If you want to check in practice, this order works well

Even if you are not a developer, you can check at least this much, in this order:

  1. Open Network in DevTools and clear the log.
  2. Load a file and look at the requests that appear right after processing.
  3. Check for POSTs and Payloads going to external domains.
  4. Switch to Offline and see whether the same processing still works.
  5. Check the CSP in the Response Headers, looking at connect-src, img-src, and so on.

These five steps are not a complete audit.

Still, they move you well beyond "I trust it because the privacy policy says so."

FAQ

When should I open the Network panel?

Before the action you want to check. Network records requests while it is open, so clear the log, then choose a file and look at the requests that appear at that moment.

If nothing shows up under Fetch/XHR, does that mean nothing was sent?

That is premature. Data can also leave through WebSockets, beacons, images, form submissions, and more, and an external image URL in Markdown is enough to trigger a request. It is safer to set Network to All and look at everything.

If it works offline, can I conclude it processes locally?

Not as proof. The data it needs might still be in a Service Worker or cache, and a tool could be built to send usage logs only when online. Working offline and sending nothing while online are different things.

If the CSP has connect-src 'none', can nothing be sent out?

connect-src restricts where JavaScript, such as fetch() and XMLHttpRequest, can connect, but if img-src or similar directives are loose, a path for fetching external images remains. You should not conclude that outbound traffic is completely impossible from a single directive.

If there is traffic to a domain I do not recognize, is the tool sending it?

You cannot tell right away. Browser extensions such as ad blockers and password managers can make their own requests. To check carefully, it is easier to isolate the cause in a new profile with extensions disabled.

A real example to check: the Karuku image compressor

oka-project's Karuku is built to compress and resize images inside the browser.

If you open the Network panel while you add and process an image, you can check for yourself whether any request sends the image data to an external API. I care about users being able to observe the actual traffic using the steps in this article, not just read a description.

You can use it as a test subject if you want to try the steps in this article on a real tool.

"We don't upload your files" is stronger as a verifiable structure than as a promise

At first I assumed that when a service says "we don't upload your files," users have no choice but to believe it.

In practice, that is not quite true.

Network shows you the traffic that happened during an action.

Offline mode lets you test whether processing needs the network.

The CSP shows you which destinations are allowed for JavaScript, images, and so on.

None of this is complete proof.

Still, a tool that only makes a promise is very different from one whose behavior and constraints users can check for themselves.

As someone who builds browser-only tools, I think this matters.

It is not enough to write "we don't send your data." Network should show that nothing is actually sent, and the CSP should show that the browser restricts outbound requests even if something tries.

The privacy of a web tool can be shown not only by its description but by behavior you can observe and a structure you can verify.

That was the biggest takeaway from looking into this.

References

← All articles