Short answer: this green screen remover keys the image inside your tab. The file is read with the browser’s File API, drawn to a canvas, keyed pixel by pixel, and exported from that same canvas — no account, no upload, no server copy. Two honest limits: Cloudflare’s page-view beacon still fires, and the working canvas is capped at 1400 px on the long edge.
The path your file takes (and where it stops)
“Runs in your browser” is not the same as “never leaves your browser”. A web page can decode an image locally and still POST the bytes a second later. The only useful question is whether the code has a way to send them. On this page, it does not:
- Read locally. The drop handler passes the
Fileobject straight toURL.createObjectURL(). That creates a blob URL that points at the file on disk; the browser reads it, not a server. - Decode and shrink. An
Imagedecodes the blob, thendrawImagecopies it onto an off-screen canvas scaled to at most 1400 px on the long edge. This is the step that creates the resolution cap explained below. - Key in memory.
getImageData()returns the pixels as a typed array. A single loop compares each pixel’s RGB distance from the sampled green and writes an alpha value into a second array. Nothing in that loop knows what a network is. - Export from the canvas. The download button calls
canvas.toBlob('image/png')and saves the result. The PNG is encoded by the browser, from the canvas, on this machine.
Measured 2026-10-26 by scanning green-screen-remover.html; the delivered page is the same file plus one Cloudflare-injected tag, covered below.
| Capability the page could use to send a file | Occurrences in the keyer |
|---|---|
fetch(), XMLHttpRequest, sendBeacon, WebSocket, FormData, EventSource, dynamic import() | 0 of each |
External <script src> in the local file | 0 (one inline script) |
| External assets | styles.css only |
localStorage, sessionStorage, indexedDB, document.cookie, service worker | 0 of each |
| Ways to retain the image after the tab closes | none |
What still leaves: the beacon, and why it is not in your file
I fetched the live URL and removed the Cloudflare tag from the HTML; the remainder matched the local file. So the extra tag is the one thing the deployed page has that the source does not. It is Cloudflare Web Analytics, injected at the edge, and the script it loads uses sendBeacon to post a page-view measurement to cloudflareinsights.com/cdn-cgi/rum.
That is a real network request. It is also not part of the keyer: the keyer never hands it the file, the canvas, or the blob URL. Any script in the tab can in principle reach the DOM, which is why the checks below use the Network panel rather than a privacy badge.
| What | Who can see it | Leaves the device? |
|---|---|---|
| The image pixels and alpha channel | this tab, not sent by the keyer | No |
| The file name and EXIF inside the file | this tab — the keyer never puts either in a request | No |
| Page URL and the beacon’s page-view data | Cloudflare Web Analytics | Yes |
The HTML and styles.css requests | Cloudflare’s CDN (it serves this site) | Yes — metadata only |
| The keyed PNG | your downloads folder | No |
Cloudflare is also the host, so it sees the request for this page. That is not the same as seeing the photo you drop after the page has loaded.
The number “no upload” pages hide: 1400 px
The keyer does not process your original resolution. It scales the long edge to 1400 px before the first pixel is read, and the export uses that same canvas. A 6000×4000 photo leaves as a 1400×933 PNG: 23.3% of the original width, and 5.4% of its pixels. That is not a preview — it is the file you download.
| You drop in | Working canvas | Width kept | Pixels kept |
|---|---|---|---|
| 6000×4000 (24 MP) | 1400×933 | 23.3% | 5.4% |
| 5000×3333 | 1400×933 | 28.0% | 7.8% |
| 4000×3000 (12 MP) | 1400×1050 | 35.0% | 12.3% |
| 3000×2000 (6 MP) | 1400×933 | 46.7% | 21.8% |
| 1920×1080 | 1400×788 | 72.9% | 53.2% |
| 1600×900 | 1400×788 | 87.5% | 76.6% |
| 1400×1400 or smaller | unchanged | 100% | 100% |
The cap is also why the tool feels instant. Four RGBA copies of a 1400×1400 frame — source canvas, display canvas, input ImageData, output ImageData — add up to about 31 MB. The same four buffers at 6000×4000 would be about 384 MB, before the browser’s own decoded copy. The key loop itself, measured on this machine with the page’s exact formula, takes 13.1 ms at 1400×1400 (median of 31 runs; slowest 24.4 ms). That is the loop only, not JPEG decode or PNG encode.
| Frame already at that size | Pixels | Key loop, median |
|---|---|---|
| 1400×933 | 1.31 MP | 11.3 ms |
| 1200×800 | 0.96 MP | 8.0 ms |
| 1400×1400 | 1.96 MP | 13.1 ms |
| 1920×1080 (reference; the page would shrink it first) | 2.07 MP | 13.6 ms |
Node 24.19 on an AMD EPYC 9754, 31 runs per size, medians reported. A desktop browser runs the same V8 loop but adds canvas readback and PNG encoding, so treat these as the floor, not the full click-to-download time.
Full resolution without a server: tile it 3×3
Here is the useful part of the cap. The matte is computed per pixel with no blur radius and no neighbour lookup — edge softness is just an alpha ramp on each pixel’s own colour distance. That means splitting the frame into tiles and keying each tile with the same sampled colour produces the same matte, not an approximation.
Tested
4000×3000 synthetic frame, 9 tiles of at most 1334×1000 (every tile inside the 1400 px limit), tolerance 22%, softness 3%. Compared all 12,000,000 alpha values: 0 mismatches. 19,947 pixels landed in the soft band, so the comparison did include partial alpha, not just 0 and 255.
Cost
One full-resolution pass: 100 ms. Tiled pass including the copy in and out: 112 ms. The 12% overhead is array copying, not extra keying. Same machine, same formula, same run.
- Cut, do not resize. Split 4000×3000 into 3 columns × 3 rows. Each tile is at most 1334×1000, under the cap; the last column is 1332 px wide. Any resize changes pixel colours and breaks the equality.
- Sample once. Key the first tile, note the exact hex and the tolerance. Use those same values for all nine tiles — a different sample per tile gives each tile its own matte.
- Key and export each tile. Nine transparent PNGs, in order.
- Paste at integer offsets. Reassemble on a 4000×3000 canvas at x = 0, 1334, 2668 and y = 0, 1000, 2000. No scaling, no feathering; either one re-samples the edge you just calculated.
This is a workaround, not a feature. The page has no tile mode and no batch import; you are doing the split and the stitch. If a 1400 px export is enough for a thumbnail or a web hero, skip it. If you need the full frame for print, tiling is the only way to keep this exact matte without uploading.
Five checks that prove it on your own machine
- Network panel. Open DevTools → Network, clear it, then drop an image. No request should carry a body the size of your file. A page that uploads will show it here even if the UI says “local”.
- Search the source. View source and search for
fetch(,XMLHttpRequestandsendBeacon. On this page the inline keyer has none; the onlysendBeaconin the delivered HTML is inside Cloudflare’s beacon file, which is a separate script. - Unique filename. Rename a test image to something you can search for, drop it, then search the Network panel for that string. The name never appears because it is never serialised into a request.
- Offline after load. Load the page, then set Network to Offline. Drop a second image. Keying and PNG export do not need the network; only the initial page load and the analytics beacon do.
- Check the export size. If the PNG comes back at 1400 px on the long edge, the cap is real. A tool that claims full resolution and returns 1400 px is not lying about upload — it is lying about resolution.
Login-free, compared with the pages that rank for this term
Privacy is the one claim you cannot check from a feature list. Here is what the three pages in my benchmark actually ask of your file; the snapshot is 2026-10-18, and policies change, so the point is the category, not the wording.
| Page | What it runs | What it asks of the file | What it means for a private photo |
|---|---|---|---|
| sleek.design | Browser-side image keyer; video listed as coming | Tool copy says no signup; the site nav has a Log in for its design product | Browser-side is a good sign, but only the network panel proves it |
| onlinepngtools.com | Browser PNG chroma key | Free tier limited; commercial use paid | “Free” and “no upload” are separate questions |
| picsart.com | AI background remover, not a manual chroma key | Account required | The file goes to an account-backed AI service |
| This page | Browser-side keyer, stills only | No account; 1400 px cap | Local keying, with a page-view beacon and a real resolution trade-off |
Green screen remover without upload: FAQ
Is it safe to use an online green screen remover for client photos?
Only if you have checked where the bytes go. “Online” and “uploads your file” are not synonyms, but neither is “browser-based” a guarantee: JavaScript can read a canvas and POST it. The check takes ten seconds — open the Network panel, clear it, drop the image, and look for a request with a body. If there is none, the pixels stayed. If there is one, the tool is a server tool with a local-looking interface. On this page the keyer has no network call; the only request after load is Cloudflare’s page-view beacon, which never receives the image.
Why is my exported PNG smaller than the photo I dropped in?
Because the page scales the long edge to 1400 px before keying, and exports from that canvas. A 6000×4000 photo becomes 1400×933 — 23.3% of the width and 5.4% of the pixels. This is a fixed working size, not a free-tier limit and not something an account unlocks. If you need the full frame, use the 3×3 tiling method above; do not upscale the 1400 px export, which adds pixels without adding detail.
Does “no upload” mean it works offline?
The keying and the PNG export do, because neither calls the network. The page itself still has to load first, and the Cloudflare beacon will fail silently while offline. Load the page, open DevTools → Network → Offline, then drop a second image: it should key and download normally. That test separates “the page needed the network once” from “the tool needs the network every time”.
What exactly does Cloudflare’s beacon see?
It is the script Cloudflare injects into the delivered HTML for Web Analytics. It sends a page-view measurement with sendBeacon to cloudflareinsights.com/cdn-cgi/rum. It is not part of the keyer, and the keyer never hands it the file. Third-party code still runs in the same tab, so the trustworthy check is the Network panel: drop an image and look for a request that carries it. If the beacon is unacceptable, block static.cloudflareinsights.com — the keyer keeps working, because it never depended on that script.
Can I key a 6000 px photo at full resolution here?
Not in one pass. The cap is in the code (max = 1400), and the export uses the same canvas, so a single drop always returns a 1400 px PNG. The tested alternative is to cut the photo into tiles no larger than 1400 px on the long edge, key every tile with the same sampled colour and tolerance, and paste the nine PNGs back at integer offsets. The matte is per-pixel, so the tiled result matched a full-resolution pass on all 12,000,000 alpha values in the test above. The catch is manual work: no batch import, no automatic stitch.
Do you store my images or keep a copy after I close the tab?
No copy is written to storage. The page uses no localStorage, sessionStorage, indexedDB, cookies or service worker, so the image exists only as decoded pixels and canvas buffers in the tab’s memory. Closing the tab discards them. The downloaded PNG is the only persistent copy, and it is in your downloads folder, not on the server.
Is a browser keyer worse than a desktop editor for a paid job?
For a single still at web resolution, it is faster: 13 ms for the key at the cap, and no round trip. For full-resolution print, hair-heavy edges or a sequence of frames, a desktop or command-line keyer is the better tool because it works at native resolution and can write a matte you can inspect frame by frame. The honest split is: use this page to test the colour and the tolerance quickly, then move the same values into a full-resolution tool when the output has to be bigger than 1400 px.
Next step
Drop a frame into the green screen remover and watch the Network panel while you do it. If the export is too small, tile it. If the edge is the problem rather than the size, run the edge check before you export, and if the subject still has a green rim, that is spill — the despill step is the next page. Video is a different path entirely: green screen remover for video explains why a browser still-frame keyer cannot hand you a transparent MP4.