Disclosure: Save Image As Type is ours, and this blog is published by the same people. Anything said here about our own software is written by an interested party. Route 1 below is a feature of our own extension, and it is the only route that renames the file before it is written rather than after. The other two routes are here because each is the right answer in a case the first one cannot reach.
Why is the image you just saved called download.jpg?
Because nothing told the browser what else to call it. You right-clicked an
image, chose Save image as…, and the name waiting in the dialog was
download.jpg. Or unnamed.png, or 1f4a9c30e2b7.webp, or image (3).jpeg
because you had already saved image, image (1) and image (2) from the same
page.
None of those names came from the picture. They came from the browser doing the best it could with what the page handed it, which on most pages is nothing.
What actually names a saved file
The HTML standard describes the exact order a browser follows to pick a filename, and it comes down to three inputs.
A Content-Disposition: attachment header on the image response. If the
server sent one with a filename, that name wins. This is the only mechanism
that names the file deliberately, and almost no site sets it on images, because
images are meant to be displayed, not downloaded.
A download attribute on the link you clicked. A page author can write
<a href="photo.jpg" download="skyline-2026.jpg"> and that value becomes the
filename. It only applies when you follow a link, not when you right-click an
image on the page, so it does nothing for Save image as….
Failing both, the URL. When there is no Content-Disposition attachment
header and no download attribute, the standard says the filename is “derived
from the URL of response in an implementation-defined manner”.[1] That is the
specification declining to specify. Each browser guesses, usually from the last
segment of the URL path, and then falls back to a fixed word like download
when the path has nothing usable in it.
After the guess, the browser cleans up: it removes characters that are illegal
in a filename, trims whitespace, and if the extension in the name disagrees with
the response’s Content-Type it rewrites the extension to match.[1] That last
step is why a file whose URL ended in .php still lands as .jpg, and it is
also why renaming a .webp to .jpg by hand changes nothing about the bytes
inside.
Why the URL usually has no name in it either
The last-path-segment guess worked when an image lived at
example.com/images/skyline.jpg. Modern image URLs are not shaped like that.
- A content delivery network serves the image from a hashed key:
cdn.example.com/8f3a1c2e9b4d, no extension, no words. - A Next.js site serves images through its optimizer at
/_next/image?url=%2Fprofile.jpg&w=828&q=75, where the real image is a query parameter and the path is just/_next/image.[2] The browser sees the path, names the fileimage, and drops the query string. - Social platforms append the format as a parameter:
pbs.twimg.com/media/Abc123?format=jpg&name=largesaves asAbc123with no extension until theContent-Typefixes it. - A
blob:ordata:URL, which is what you get from a canvas, a cropped preview, or a lazy-loaded gallery, has no path at all. The browser names itdownload.
You did not choose the format the image arrived in, and
the same content negotiation that hands your browser a .webp
hands it a URL with no filename to read. The name problem and the format problem
have the same root: the file was built for a browser to display, not for you to
keep.

Renaming afterwards is the tax, not the fix
The usual answer is to fix the name in the Save As dialog before you hit save, or to sort it out in the Downloads folder later. Both work for one image. Neither scales, for three reasons.
You are typing the name at the worst moment. You are looking at the page, you know exactly what the image is and where it came from, and the dialog gives you a text field and a picture that is not in it. Whatever context you had is gone by the time the file is on disk.
A page of images multiplies it. Save ten product shots, or a “save all”
batch from the popup, and you get image, image (1), through image (9), in
save order, with nothing to tell them apart. Renaming them afterwards means
opening each one to see what it is.
The Downloads folder fills with names you never go back and fix. A folder
with two hundred files called download, download (1), unnamed, and Abc123
is not something anyone renames later. It is something you end up searching by
date instead.
The fix is to have the name decided at save time, from information the page already carries, without you typing anything.
Route 1: rename as you save, from a template
Save Image As Type builds the filename itself from a template you set once,
and passes the finished name to the browser’s download API, whose filename
argument is “a file path relative to the Downloads directory”.[3] The name is
chosen before the file is written, so it never depends on the browser’s guess or
on a header the site did not send.
In the extension’s Settings, under Filename, the Filename template field takes these placeholders:
| Placeholder | Fills in with |
|---|---|
{original} | The image’s own name, cleaned from the URL. If the URL only has a hash, this falls back to the site’s domain and the date. |
{domain} | The domain of the page you saved from. |
{alt} | The page’s alt text for that image. Falls back to {original} when the page set none. |
{title} | The image’s title attribute, same fallback. |
{date} | The local date, as 20260904. |
{time} | The local time, as 143205. |
{n} | The image’s position in a batch save. 1 for a single save. |
A template of {domain}-{original}-{date} turns an anonymous CDN save into
figma.com-8f3a1c2e-20260904.png. A template of {alt} names the file after
what the page says the image is. Anything in the template that is not a
recognised placeholder is kept exactly as typed, so shoot-{date}/{n} is a
valid way to drop a numbered batch into a dated subfolder.
Two settings sit next to the template and matter as much:
- Append a timestamp to saved filenames is on by default. It adds
-20260904-143205to every name so a second save of the same image never silently overwrites the first. It steps aside if your template already contains{date}or{time}. - Subfolder routes every save into a folder inside Downloads. With the Save As dialog on, that folder is where the dialog opens, and it reopens at the last folder you used rather than at the Downloads root.
Because Route 1 is our extension, the honest limits belong here too. It renames images you save through it, so it does nothing for a file a colleague emailed you or one already sitting in Downloads. Those are Routes 2 and 3.
Route 2: name it on the server
If the images are on a site you control, send the name with them:
Content-Disposition: attachment; filename="skyline-2026.jpg"
Any browser that downloads that response uses the name, with no extension
involved.[4] For names with non-ASCII characters, add a filename* parameter in
UTF-8, which browsers prefer over plain filename when both are present.[4]
This is the most reliable route and the least useful one, because it only helps for images you are publishing yourself. It does nothing for the pages you are saving from.
Route 3: rename in bulk after the fact
For images that are already on disk, the job is a batch rename, and every platform has a tool for it:
- macOS Finder selects a group of files, right-click, Rename, and does find-and-replace or numbered sequences without extra software.
- PowerToys PowerRename on Windows adds regex find-and-replace to the right click menu.
- On the command line,
renameor aforloop covers pattern renames, andexiftool "-filename<CreateDate"renames photos by the date they were taken, read from the file’s own metadata.
This is where you end up when the images never came from a page you could right-click. It is a real answer, it is just a second pass over files that could have been named correctly the first time.
Which route should you use?
| Route | Works on | Names the file before it is written | Effort |
|---|---|---|---|
| Rename as you save (extension) | Images on a web page | Yes | Set the template once |
Content-Disposition header | Images on your own server | Yes | Server config, once |
| Bulk rename tool | Files already on disk | No | A pass per batch |
For images you are saving off web pages, which is where the download.jpg
problem actually lives, Route 1 is the one that removes the step instead of
moving it. Route 2 is for what you publish. Route 3 is for cleaning up what was
saved before you fixed the other two.
If you are here because a whole page of images saved as hashes, the image converter extensions roundup covers which of them can save in bulk at all, and the WebP to JPG walkthrough is the one to read if those images also came down in a format your editor will not open.
Sources
- HTML Standard, 4.6.6 Downloading resourcesPrimary source
That when a response carries no Content-Disposition attachment header and the download did not come from a link with a download attribute, the saved filename is "derived from the URL of response in an implementation-defined manner", and that the browser then strips characters that are not legal in filenames and rewrites the extension to match the response's Content-Type. Read .
- RFC 6266: Use of the Content-Disposition Header Field in HTTPPrimary source
That a server can set the filename a browser saves a response under with Content-Disposition: attachment; filename=, and with filename* for names containing non-ASCII characters, where filename* takes precedence.
- chrome.downloads API referencePrimary source
That the downloads.download() filename parameter is "a file path relative to the Downloads directory", so an extension decides the saved name before the file is written. Read .
- Next.js: Image Component API referencePrimary source
That the Next.js Image component serves optimized images from /_next/image with the original image passed as the url query parameter (for example /_next/image?url=%2Fprofile.jpg&w=828&q=75), so the URL the browser sees has no image filename in its path. Read .