Downloading one image is easy. Downloading 80 product photos from a spreadsheet gets tedious, especially when you also need consistent filenames and a way to tell which downloads failed.
The most useful starting point is a list of direct image URLs. Once you have that list, you can download the files together with a browser tool or a small command-line workflow.
This tutorial covers both approaches, plus a JavaScript snippet for collecting image links when your starting point is a webpage. The examples are intended for assets you own or have permission to download and use.
1. Work out what kind of links you have
Before picking a downloader, open one of your links. Does it show an image by itself, or does it open a page containing an image?
These are different inputs:
Product page:
https://shop.example/products/blue-chair
Direct image URL:
https://cdn.example/products/blue-chair.jpg
The domains above are placeholders. Replace them with your own links.
A URL-list downloader needs the second kind. Passing it a product page usually gives it HTML rather than the image you wanted.
Also, a direct image URL does not have to end in .jpg or .png. A CDN might serve an image from a path such as /media/abc123?width=1200. What matters is the response, not the spelling of the URL.
| What you have | First step | Next step |
|---|---|---|
| A spreadsheet column of image URLs | Copy the actual URL values | Download the list |
| A webpage with several images | Collect the image URLs | Review and download the list |
| A media library you administer | Look for an export or API | Keep asset IDs alongside URLs |
| A recurring image export | Save a URL manifest | Automate downloading and record failures |
For a CMS migration, check the media export first. It may already contain original asset URLs and filenames, saving you the work of collecting resized images from rendered pages.
2. Prepare a small, clean URL list
Use one URL per line. This is easy to inspect, copy from a spreadsheet, and reuse in a script.
Here is a three-image practice list using Lorem Picsum's documented image-ID and size format:
https://picsum.photos/id/10/1200/800.jpg
https://picsum.photos/id/20/1200/800.jpg
https://picsum.photos/id/30/1200/800.jpg
These are sample source images, not screenshots of a completed download. Each URL requests a 1200-by-800 image, which makes it easier to check whether you exported the expected dimensions.
Before processing your real list:
- Remove the column heading and empty rows.
- Check that copied cells contain URLs, rather than hyperlink labels such as “View image.”
- Remove exact duplicate URLs if you only need one copy of each.
- Preserve query parameters. They may control image dimensions or carry a required signature.
- Open a few links to check that they still work.
Keep the original spreadsheet if its rows connect images to product IDs. A folder full of sequential filenames is less useful when you cannot tell which image belongs to which product.
I would start a new workflow with three representative files: a normal photo, a transparent image if the project uses one, and one of the larger assets. Check that small batch before scaling up.
3. Download the list as a ZIP without writing code
Veyvia's bulk image downloader accepts direct image URLs and packages successfully retrieved files into a ZIP. It also offers filename customization, optional conversion to PNG, WebP, or JPG, and proportional width limiting.
The workflow is:
- Paste your URLs, one per line.
- Click Load & Download Images.
- Review the previews and any failed entries.
- Choose your naming and export settings.
- Download the ZIP and inspect its contents.
For the first batch, keep the original format and avoid resizing. That gives you a useful baseline before introducing conversions.
The tool takes an existing list; it does not discover every image on a website. Failed items are excluded from the ZIP, so an archive downloading successfully does not mean every input succeeded.
The page also describes a server-side proxy for retrieving images. That means this is not an entirely local workflow; use your own tooling for private asset URLs you cannot share with another service.
4. Collect image URLs from a webpage with JavaScript
If you have a webpage instead of a spreadsheet, you can collect URLs from the <img> elements currently in its document.
Open the page in Chrome, scroll through the content you need, and open Developer Tools → Console. Read the snippet before running it: it collects image URLs and copies the list to your clipboard. It does not download files or send the list anywhere.
(() => {
const urls = [...new Set(
[...document.images]
.map((img) => img.currentSrc || img.src)
.filter((url) => /^https?:\/\//i.test(url))
)];
console.log(`Found ${urls.length} unique image URLs`);
copy(urls.join('\n'));
})();
Paste the clipboard contents into a text editor, inspect the list, and then use it as the input for your downloader.
currentSrc returns the image URL selected by the browser, including its choice from a responsive image's srcset. It does not guarantee the largest available image or a successful load. See MDN's currentSrc reference.
The copy() helper belongs to Chrome DevTools' Console Utilities API. It is not a standard JavaScript function you can paste into application code.
Understand what the snippet misses
This is a starting list, not a complete site export. It does not recursively inspect iframes or shadow roots, collect CSS background images, or discover images on other pages. It also skips blob: and data: URLs because those are not ordinary HTTP image links.
Scrolling matters because pages can defer image loading or add elements as you move through the content. MDN's lazy-loading guide explains the browser behavior. On virtualized galleries, earlier items may disappear from the document, so scrolling once and collecting at the end may still miss them.
You may also collect logos, avatars, tracking images, and thumbnails. Review the list before downloading. If you control the page, a narrower selector such as document.querySelectorAll('.product-gallery img') can reduce that noise.
For original-resolution assets, prefer your CMS export or the source site's explicit original-download link. A responsive page is optimized for display, which may be much smaller than the source image.
5. Use curl when you want a repeatable local workflow
For a few direct URLs, a terminal can be enough. This example assumes Bash and an installed curl command, such as on macOS, Linux, or WSL.
Create a text file named urls.txt containing your URLs. Then save the following as download-images.sh in the same directory:
#!/usr/bin/env bash
set -u
# A fresh directory keeps previous batches separate.
batch_dir=$(mktemp -d ./image-batch.XXXXXX) || exit 1
index=0
while IFS= read -r url || [[ -n "$url" ]]; do
url=${url%$'\r'}
[[ -z "$url" ]] && continue
case "$url" in
http://*|https://*) ;;
*) printf 'Skipping non-HTTP URL: %s\n' "$url" >&2; continue ;;
esac
index=$((index + 1))
printf -v filename 'image-%04d' "$index"
target="$batch_dir/$filename"
if curl --fail --location --globoff \
--proto '=http,https' --proto-redir '=http,https' \
--connect-timeout 10 --max-time 60 \
--silent --show-error \
--output "$target.part" --url "$url"; then
mv "$target.part" "$target" || exit 1
printf '%s\t%s\n' "$filename" "$url" >> "$batch_dir/manifest.tsv"
else
printf '%s\n' "$url" >> "$batch_dir/failed.txt"
fi
done < urls.txt
printf 'Review downloaded files in %s\n' "$batch_dir"
Run it from that directory:
bash download-images.sh
--location follows redirects, --fail treats HTTP error responses as failures, and --globoff prevents URL characters such as brackets from being interpreted as curl URL patterns. The timeout options bound connection and transfer waits. Consult the official curl manual for their details.
This example deliberately uses sequential, extensionless filenames. Two URLs ending in photo.jpg therefore cannot overwrite each other within the batch. It also avoids pretending that every response is a JPEG.
The manifest maps saved filenames back to their source URLs. Failures go into failed.txt; an interrupted transfer may leave a .part file for inspection. Review those separately from completed files.
Check the response before treating it as an image
An HTTP success response can still contain a login page or another HTML document. This small script downloads response bytes; it does not decode images or validate their format.
On macOS or Linux, inspect a downloaded file with file, substituting your actual output directory:
file ./image-batch.ABC123/image-0001
Then open representative files in an image viewer. Add extensions only after identifying their formats. For a production migration, use an image decoder to validate every file and record dimensions before importing it.
The script processes URLs sequentially and leaves retry decisions to you. That is a manageable starting point for a small batch. If you later add concurrency, keep it bounded and retain a failure log so you can rerun just the missing files.
6. Choose filenames and image settings for the destination
Downloading and preparing images are separate decisions. Decide what the receiving system needs before converting the whole batch.
| Destination | Useful starting choice |
|---|---|
| Asset archive | Preserve downloaded source files and the URL manifest |
| Product import | Use stable product IDs in filenames or a mapping file |
| Web page | Create delivery copies at the required dimensions |
| Design handoff | Use descriptive filenames and retain source versions |
For example, chair-042-front.jpg tells a teammate more than image-0037.jpg. If you need numbered names, use zero padding so files sort predictably: image-0001, image-0002, and so on.
Keep an untouched batch before experimenting with export settings. Compare one converted image with its source at the size where it will actually appear. Check text, edges, transparent areas, and any animation the project needs.
A useful handoff includes both the files and a small record of what happened: source URL, output filename, success or failure, and any resizing or conversion performed. That record saves time when someone later asks where an asset came from.
7. Troubleshoot incomplete batches
Start with one failed URL. Repeating the whole batch makes it harder to see whether you have an input problem, an access problem, or a temporary network failure.
| Symptom | What to check |
|---|---|
| A saved file opens as a webpage | Verify that the URL returns image bytes |
| An image is smaller than expected | Check whether you collected a thumbnail or resized CDN variant |
| Multiple inputs produce fewer distinct files | Review duplicate handling, naming collisions, and failures |
| A URL used to work but now fails | Obtain a fresh link and check whether it expired |
| Downloads become unreliable in larger batches | Reduce batch size and inspect the response errors |
| A file works in your browser but fails elsewhere | Check whether access depends on your signed-in session |
Why can an image display but fail in JavaScript?
Displaying a cross-origin image and reading its bytes with fetch() are different operations. Browser JavaScript needs the appropriate CORS permission to read a cross-origin response. An image appearing on a page is not proof that a download script can access its bytes. See MDN's CORS guide.
Changing a fetch request to mode: 'no-cors' does not give you readable image bytes. A server-side downloader can avoid the browser's CORS restriction, but it still needs the source server to permit the request.
Verify the result, not just the progress bar
Compare the number of unique URLs you intended to download with the number of completed image files. Exclude manifests, failure logs, and partial transfers from the count.
Then check a few images from the beginning, middle, and end of the batch. Confirm dimensions and filenames, and verify that the output opens in its destination application. A successful archive export is only one part of a successful asset transfer.
Frequently asked questions
Can I download images directly from Excel or Google Sheets?
If a column contains direct image URLs, copy those values into a text list. Embedded pictures and hyperlink display labels need a different export step; they are not necessarily usable URLs.
Can I download every image from a website with one URL?
That requires discovery across pages as well as downloading. The console snippet only reads the current document. For a site you administer, start with the media library or an export API.
How do I avoid downloading the same image twice?
Remove exact duplicate URLs first. Different URLs can still return identical images, so identifying duplicate content requires comparing the downloaded files, for example by their hashes.
Does putting images in a ZIP reduce their quality?
ZIP packaging does not change the image bytes. Resizing or re-encoding before packaging can change the image, so keep those settings separate from the decision to create an archive.
Why are some files missing from my batch?
Check the failure list, duplicate rules, and output filenames. A valid ZIP can contain only the successful portion of a job. Record the expected count before starting.
Which method should I start with?
For an occasional URL list, start with the browser workflow above and inspect a small sample. For repeated exports, use a local script with a manifest and failure tracking. Either way, getting the right source URLs makes the rest of the job much easier.
Top comments (0)