Yes — byte for byte. I ran 53 conversions on this converter today and got four distinct files out of them: one per input-and-quality pair, identical every single time.
Short answer: the conversion is deterministic. The same HEIC at the same quality setting produces the same JPG down to the last byte — I compared the files with SHA-256, not by eye. One real photo (41,465 B, 700×476) came out as 38,078 B on all 31 runs I did of it today, with one hash: 93859de257dc44a7ff3dc41eb965d07ff84c8630ec8a3db44e24e89120713c81. Reloading the page did not change it. Opening a brand-new browser profile with an empty cache did not change it. Converting it in a different browser did not change it. Only one thing changed the bytes: the quality setting.
The practical upshot is that you never need to run a conversion twice hoping for a better result, and you can use a hash to prove two files are the same picture. What I cannot promise is that this stays true forever — if the converter's own code is updated one day, today's hash will not match tomorrow's output. Everything below was measured today on the live site.
I used two source files: a real iPhone photo (41,465 B, 700×476) and a synthetic 12-megapixel image (18,327 B, 4032×3024). Because the upload control ignores a second selection of the identical path, each run used a byte-identical copy with a different filename — the bytes going in were the same in every case. After each conversion I pulled the JPG out of the page and hashed it.
| Set | What I did | Runs | Distinct outputs |
|---|---|---|---|
| A | ten conversions in a row, same page, never reloaded | 10 | 1 |
| B | reloaded the page before every conversion | 10 | 1 |
| C | three quality settings, three runs each | 9 | 3 — one per setting |
| D | the same bytes under a different filename | 1 | 1 |
| E + I | the 12 MP file, three runs and then ten runs | 13 | 1 |
| F | a freshly opened browser tab | 1 | 1 |
| G | a brand-new browser profile with an empty cache | 1 | 1 |
| H | small and large file interleaved, three rounds | 6 | 2 — one per file |
| — | the same file in two different browsers | 2 | 1 |
That is 53 conversions and four distinct files. Every run finished with the page's error box empty, and every output kept the dimensions of its input — no cropping, no resizing, no warning.
Set A is the plainest version of the question. I loaded the page once and converted the same photo ten times without reloading. All ten downloads were 38,078 B with the same hash. The timings are the interesting part — they moved a lot while the bytes did not.
| Run | Conversion time | Output |
|---|---|---|
| 1 | 1,098 ms | 38,078 B |
| 2 | 238 ms | 38,078 B |
| 3 | 170 ms | 38,078 B |
| 4 | 132 ms | 38,078 B |
| 5 | 128 ms | 38,078 B |
| 6 | 108 ms | 38,078 B |
| 7 | 168 ms | 38,078 B |
| 8 | 130 ms | 38,078 B |
| 9 | 99 ms | 38,078 B |
| 10 | 92 ms | 38,078 B |
The first conversion in a session costs about ten times what the later ones do, because that is the one that has to get the decoder working. What matters here is that the fast runs and the slow run wrote exactly the same file. I compared the first and the tenth byte by byte afterwards: 0 of the 38,078 bytes differ.
Set B reloaded the page before each of ten conversions, so every run started from a clean page. Times ran from 646 ms to 1,201 ms; all ten outputs were 38,078 B with the same hash.
Set G went further: a brand-new browser profile with an empty cache, so the decoder had to be downloaded from scratch. That run took 883 ms and produced the same 38,078 B file — I compared it with a warm run byte by byte and again found 0 differing bytes. A fresh tab (617 ms) and an interleaved run (158 ms) matched too.
Then I ran the same file in two browsers installed on this machine, each in its own fresh session: 38,078 B in 1,255 ms in one, 38,078 B in 1,716 ms in the other, same hash in both. And when I looked back at the numbers I recorded on 27 September from those same two browsers — 1,264 ms and 1,488 ms — the hash was the one I got today. So this input has produced one identical file across three days, two browsers and several dozen runs.
Quality. The page offers three settings, and each one has its own stable output — I ran each three times with a page reload in between and got the same file every time.
| Quality | Runs | Output size | SHA-256 (first 16) | Times |
|---|---|---|---|---|
| 0.75 | 3 | 30,231 B | 45be985b347327e6 | 720 / 676 / 644 ms |
| 0.85 | 3 | 38,078 B | 93859de257dc44a7 | 628 / 669 / 652 ms |
| 0.95 | 3 | 57,617 B | de678d5206fb5ce2 | 745 / 740 / 653 ms |
Note that the quality setting changes the size but not the speed: all nine runs landed between 644 ms and 745 ms. That matches what I measured on a much bigger set of files in the 200-file batch article.
I made a copy of the same photo called My Photo (1) - final.HEIC — spaces, brackets, an uppercase extension. It converted in 665 ms to the same 38,078 B file with the same hash. The download was named My Photo (1) - final.jpg. So the name you give the file decides the name you get back, and nothing about it reaches the encoded picture.
One worry with a converter that runs in a browser tab is whether a previous conversion leaves something behind. I interleaved the two files — small, large, small, large, small, large — in a single page session. The small file came back at 256 ms, 192 ms and 158 ms, always 38,078 B. The large file came back at 1,601 ms, 2,206 ms and 2,067 ms, always 100,826 B with hash 280de806af9863d5. Neither file's output moved when the other one was converted in between.
The 12-megapixel file also got its own run of ten: 1,457 / 1,576 / 1,318 / 731 / 651 / 647 / 684 / 710 / 612 / 606 ms, ten times 100,826 B, one hash. The first few runs are the slow ones again — the same warm-up pattern as the smaller file, and the same absence of any effect on the bytes.
Two reasons, one structural and one that I checked in the code.
First, there is nowhere in the output to put a timestamp. I walked the structure of every output file: each one is FFE0 (JFIF), FFE2 (an ICC profile, 472 B), two quantisation tables, FFC0 (the frame header), four Huffman tables, then the scan. There is no FFE1 — no EXIF block — and the frame header declares 3 colour components. I also searched the raw bytes of the outputs for Exif, Adobe, CREATOR, Software and for the strings 2025 and 2026: zero occurrences of each. A file with no metadata block and no date field cannot differ between two runs unless the pixel data itself differs.
Second, the decoder does contain calls that look like sources of randomness — I read the file: Math.random once, Date.now 13 times, new Date 7 times, crypto.getRandomValues once. But the single Math.random is used to mint an identifier for messages sent to the worker thread; crypto.getRandomValues sits in the filesystem shim; the new Date calls are in file-status and time-zone helpers. None of them are on the path from decoded pixels to encoded JPEG. That is a reading of the code, though — the proof is the 53 runs, and they never disagreed.
Determinism is not the same as losslessness, of course. The JPG is a re-encode of the HEIC and it does lose detail — I measured how much, pixel by pixel, in the quality-loss article. What is stable is that the loss is always the same loss.
Yes. Ten in a row on one page, ten with a reload before each, and one from a brand-new browser profile all produced 38,078 B with the same SHA-256. I compared the first and tenth byte by byte: 0 differences.
Only the name of the download. A copy called My Photo (1) - final.HEIC produced the same 38,078 B hash as the original, and came back as My Photo (1) - final.jpg.
Not in my runs. Each of the three settings produced its own fixed output — 30,231 B, 38,078 B and 57,617 B — repeated identically three times, at speeds between 644 ms and 745 ms that did not track the setting.
Warm-up. In one session the first run took 1,098 ms and later runs settled between 92 ms and 238 ms, all writing the same bytes. The slow run is the one that has to get the decoder going.
No. 53 conversions today produced four distinct files, one per input-and-quality pair. Re-running is not a way to change the outcome — changing the quality setting is.
No. I read the structure of the outputs: JFIF, an ICC profile, quantisation tables, frame header, Huffman tables, scan — no EXIF block at all, and no date strings in the bytes. That is also why two runs can be identical.
No — determinism is not losslessness. The output is a re-encode; how much it costs is measured in the pixel-by-pixel article.
Try it: open the converter, convert the same HEIC twice and compare the two files — they should be the same size to the byte.
First published: 30 September 2026