Paste a Shopify store URL and this tool reads the public product feed, then lists every product that has no image at all. One field decides it: a product whose images array comes back empty has nothing to show a shopper except whatever placeholder the theme paints in. That is the whole detection, and it is the one product level image fault you can be certain about from outside the store.
Then it does the part that most scanners skip. A large share of the zero image products on a real storefront are not broken listings at all. They are pseudo products, created so a page builder or a merchandising block has something to hang content on, and they were never meant to be bought. Flagging those as faults turns a useful list into noise, so this tool puts them in a separate group and tells you why each one landed there. It only does that on evidence, though. A product is moved out of the fault count when it is actually named as page furniture, never because a field was left blank.
Alongside the empty ones you get two softer signals. Products whose single image has a filename that looks like a stand in, the placeholder, coming-soon, no-image, default and temp family. And products carrying exactly one photo while offering five or more variants, which is a thin gallery worth a look even though it is often perfectly fine.
Everything comes out as a table with a link straight to each product page, plus a CSV of the handles built in your browser so you can paste it into a spreadsheet and work the list. Nothing is uploaded, nothing is written back to the store, and no login or API key is involved anywhere.
Keep one boundary in mind while you read the results. This tool answers does this product have a photo. It says nothing about which variant got which photo. That second question has its own scanner, the Variant Image Coverage Checker, and the two are deliberately kept apart because they lead to completely different work.
We build image apps, so we read a lot of other people's public catalogues. Sorting the genuine gaps from the page furniture by hand is the tedious bit, and on the store we measured below it was the difference between a list of 58 and a list of 3. That is what this automates. Paste any store URL above and you can reproduce the same split yourself.
| Detail | What this tool does |
|---|---|
| Data source | The public products.json feed on the storefront, no login and no API key |
| Field checked | The product level images array. Empty means no image on the product at all |
| Products per request | 250, which is what one page of this scan reads. If the first page comes back too large it retries once at 100 |
| Scan depth | Up to 2,500 products per run, or one collection at a time if you paste a collection URL |
| Bucket 1 | Zero images, and nothing names the product as a page building block |
| Bucket 2 | Exactly one image whose filename reads like a stand in |
| Bucket 3 | Exactly one image while the product offers five or more variants |
| Separate group | Zero images and named as page furniture by handle prefix or product type. Not counted as a fault |
| Flagged group | Zero images with no product type set. Listed apart so you can check it, but still counted as missing an image |
| Level of analysis | Product level only. Per variant image assignment is a different tool |
| Export | CSV of every flagged handle, built in your browser |
| Changes made to the store | Zero. The scan only reads. The request is normally made by our server as CraftshiftToolsBot, and falls back to a public CORS proxy when that path is unavailable |
What an empty images array actually means
Every product in the public feed carries an images array. Normally it holds one entry per uploaded photo, with a CDN source URL, a position, and the variant IDs the photo is attached to. When the array is empty, nothing has ever been uploaded against that product.
There is no partial state and no ambiguity here, which is what makes this check different from most storefront audits. Alt text can be missing on some images and present on others. Variant assignment can be half done. A product either has photos or it does not, and the feed says which without any interpretation from us.
What the shopper sees depends on the theme. Most themes fall back to a grey Shopify placeholder tile, some render an empty box that collapses the layout, and a few show the collection card with nothing in it at all. On a search results page or a Google Shopping feed the same product usually just disappears, because a feed entry with no image link gets rejected at validation.
So the cost of a genuinely imageless product is not subtle. It cannot be merchandised, it cannot be advertised through a product feed, and a shopper who lands on it has nothing to look at. If it is real and it is for sale, it needs a photo. If it is not for sale, it should not be published to the online store in the first place, and that is a different fix entirely.
The false alarm this tool refuses to raise
Here is the finding that changed how this scanner works, and you can reproduce it yourself in about thirty seconds.
On 8 August 2026 we read the first 250 products from the public feed on brooklinen.com. Fifty of them came back with an empty images array. A tool that stops at the detection would report fifty broken products on a well run catalogue and be wrong about forty nine of them, because forty nine of those fifty have a handle that starts with content-. Forty five of those forty nine also carry a product type of Content, and four leave the product type blank. That is exactly why either signal counts on its own here: requiring both would have missed four of them, including content-bath-mats. They are page building blocks: content-back-to-campus-plp, content-tencel-towels, content-bath-mats. Every one of them is a container for a merchandising block, published on purpose, with no photo because a photo would make no sense on it.
The fiftieth had the handle shop-the-color, no content- prefix, and a product type of Content. Same class of object, different naming. That single leftover is why the tool checks the product type as well as the handle rather than the prefix alone.
Reading two pages of that same catalogue, 461 products, gives the ratio the whole tool turns on. Fifty eight products came back with no image. Fifty five were page building blocks. Three were real: ordinary listings with ordinary product types, published back in 2018, that simply have no photo on them. Three is a list somebody can act on before lunch. Fifty eight is a list nobody opens twice.
So the scan sorts zero image products into three groups and prints the reason on every row. Two of the three signals are strong enough to move a product out of the fault count. The third is not, and it is treated differently for that reason:
- Handle begins with
content-. The strongest of the three. This is the naming we have seen on stores that use a page builder, and it is what all 54 of brooklinen's content blocks carry, while not one of the 403 products on that store that do have photos carries it. That is one store, so treat it as a convention worth checking rather than a law. - Product type is literally Content. Same idea, expressed in a different field. Added after the prefix rule left an obvious pseudo product behind on the very store the rule came from.
- No product type at all. Far too weak to clear a product, so it does not. Plenty of ordinary merchants never fill in product type, which means an imageless product with a blank type is just as likely to be a broken listing as a page block. These get their own group, they are still counted in the headline as products missing an image, and the group carries its own warning. This one is a sorting aid, not a verdict.
That last distinction is the one worth being pedantic about, because getting it wrong produces the single worst output an image scanner can produce: a green all clear over a catalogue that really is missing photos. A store that leaves product type blank as a matter of habit would get exactly that if a blank type were treated as proof of anything. So it is not. Only the handle prefix and a product type of Content move a product out of the fault count, and the headline says so when the blank type group is not empty.
Two more things follow. First, none of these rules touch products that do have images, because an empty product type is far too common to use as a filter anywhere else. Second, if your store uses a different naming convention for its page furniture, the tool will not know, and those products will show up in bucket 1. Look at the handles before you conclude anything. A column of near identical handles with a shared prefix is your own convention staring back at you.
The three buckets, and what each one costs you
The buckets are ordered by how confident the scan is, not by how many products land in them. Bucket 1 is a fact. Buckets 2 and 3 are prompts.
| Bucket | What fired | Confidence | What it costs |
|---|---|---|---|
| 1. No image at all | The images array is empty and nothing names the product as page furniture | Certain, as a fact about the data | Nothing to show anywhere. Rejected by product feeds, blank on collection pages |
| 2. Placeholder filename | The single image is named like a stand in | A guess from a filename | Usually a photo that was uploaded to make an import pass and never replaced |
| 3. Thin gallery | One image, five or more variants | Often perfectly fine | Depends entirely on what the options are. Read the next paragraph |
| No product type set | The images array is empty and product type is blank | A sorting aid, not a verdict | Counted with bucket 1, listed apart so you can scan the handles |
| Probably intentional | Zero images plus a handle starting content-, or a product type of Content | Strong, and the only signal that clears a product | Nothing. These are working as designed |
Bucket 3 needs the honest caveat, and it is the same caveat that applies to every variant image audit ever written. If the only option on the product is Size, one photo carrying nine variants is the correct setup, because a medium shirt looks exactly like a small one and nobody expects nine photographs of the same garment. If the option is Colour, one photo carrying nine variants means eight colours are showing a picture of the ninth. Identical numbers, opposite verdicts. The table prints the option names next to each row so you can tell the two apart at a glance, and that is as far as this tool goes into variant territory.
Bucket 2 has its own weakness worth stating plainly. The word temp also appears inside template, temperature and contemporary, and default shows up in perfectly deliberate filenames. The scan prints the actual filename in the row for exactly that reason. If it flagged contemporary-oak-frame.jpg, you can see the mistake and dismiss it in a second, which beats a scanner that hides its reasoning behind a confidence score.
Fix, hide, or delete: three honest paths
Once you have a list of genuinely imageless products, there are only three things you can do with each one, and choosing badly is expensive in different directions.
Fix it. Upload a photo. This is the right answer whenever the product is real and still sells. If the missing photos exist somewhere already, on a shared drive, in a supplier pack, sitting in a folder from the last shoot, the job is transfer rather than photography.
Doing that one product at a time in the admin is fine for a handful. At two hundred it stops being realistic, which is what CS Smart Bulk Image Upload takes hundreds of images into Shopify in one pass is built for: drag and drop, a Google Drive folder import, and SKU based matching that reads the filename and routes each image to the product carrying that SKU. That last part matters more than the bulk upload itself, because renaming files to match SKUs is a job you can hand to anybody, while clicking through two hundred admin pages is not.
Hide it. If the product is not ready, unpublish it from the Online Store sales channel or set it to draft. It leaves the public feed immediately and it stops appearing in collections and search. The part people miss is that this is reversible: the product record is untouched, so the handle, the history, the inventory and the reviews all stay, and everything comes back the moment you publish it again.
What is not preserved while it is hidden is the public URL. A product that is not published to the Online Store is not served on the storefront, so inbound links, ad destinations and bookmarks pointing at that handle stop landing on a product page for exactly as long as it is hidden, which is the same thing a delete does to them. Reversible in the admin does not mean invisible to the outside world. Hiding is still the right holding move when you are unsure, but a hide you never come back to should be treated the way you would treat a removal.
Delete it. Sometimes the right call. A discontinued line, a test product from three migrations ago, a batch that was imported twice. But read this before you touch it: deleting a Shopify product is not reversible. There is no undo and no trash you can fish it back out of. The product record goes, and with it the variant IDs, the inventory records and the metafields. Reviews may go too, because review apps generally key on the product ID, so check with your review app before you delete rather than assuming either way. Any order that contained the product keeps its line item, but the link back to the product breaks. Shopify does not create a redirect for you either, so the old URL starts returning a 404 and every inbound link, ad destination and bookmark pointing at it is wasted until you write one.
Now the sequence, which is the opposite of what most people assume. Shopify's own documentation says you can redirect only from broken URLs, and that if the URL still loads a valid webpage then the redirect will not work. A redirect written against a live product URL sits there doing nothing, which is worse than having no redirect at all, because you think you are covered. So: confirm the product is really dead, export a copy of the product data, save the handle, delete or unpublish so the URL actually breaks, and write the redirect after that.
The handle is the thing you have to capture in advance, not the redirect. Build the file up front with the Redirect CSV Generator while the handles are still in front of you, then upload it once the products are gone. Once you have made those decisions for a long list, CS Bulk Delete Products removes a reviewed list in one run, with filters for collection, vendor, tag, date and inventory level, a preview screen before anything happens, scheduled deletes, and a soft delete option so the destructive version is not the default. It still cannot undo a permanent delete, because nothing can.
Three paths, and the ranking between them is not close. Hide when unsure. Fix when it sells. Delete only when you have already decided, and only with the handles saved for the redirects you will write afterwards.
This tool is product level. Its sibling is variant level.
Two different questions get muddled together constantly, so here is the split in one table.
| Missing Product Images Finder | Variant Image Coverage Checker | |
|---|---|---|
| Question it answers | Which products have no photo at all? | Which variants have no photo of their own? |
| Field it reads | The product level images array | featured_image on each variant |
| Unit of the answer | One row per product | Coverage per option and per option value |
| Typical fix | Upload a photo, unpublish, or delete | Assign photos you already have to the right variants |
| What it never says | Anything about which variant got which image | Anything about a product having no images at all |
Run this one first. A product with zero images cannot have a variant image problem, because there is nothing to assign, so fixing the product level gap has to come before the variant level one. Once every product has photos, the Variant Image Coverage Checker is the natural next step and it will tell you whether those photos actually reach the right colours. For a single product with the full per variant table laid out, use the Variant Image Checker instead.
One more distinction that saves people a wasted afternoon. If your colours are separate products rather than variants of one product, neither of those two tools is the lever. Separate colour listings are a grouping question, and the Product Grouping Planner works out how they should be joined up for the shopper.
How to work the CSV
The export button appears with the results and builds the file in your browser. Nothing is sent anywhere. The nine columns are bucket, handle, title, product_type, images, variants, options, storefront_url and why_it_was_flagged, and every group on the page is in the file, page building blocks included, so nothing is quietly dropped between the screen and the spreadsheet.
Handle is the column that matters, because it is the key Shopify itself uses. A product CSV import matches on handle, a URL redirect is written against a handle, and the admin search finds a product by handle faster than by title. Sort by bucket, add a decision column with fix, hide or delete in it, and you have a work order that somebody else can execute without needing to understand the scan.
Two small mechanical notes. The file is written with a UTF-8 byte order mark so Excel opens accented product titles correctly instead of mangling them. And any cell that starts with an equals sign, a plus, a minus or an at sign gets a leading apostrophe, because spreadsheets treat those as formulas and a product genuinely titled +1 Sizing Kit should not execute when the file is opened.
If you are about to re-upload photos in bulk, pull your existing image library down first so you know what you already own. CS Export Product Images exports the library as a ZIP, filtered by collection, vendor or tag, with a metadata CSV alongside it. Comparing that export against this scan usually shows that a good share of the missing photos already exist and were simply never attached.
What the scan can and cannot see
Being straight about the boundary is more useful than overselling the coverage.
- Published products only. The public feed returns what the Online Store sales channel serves. Drafts, archived products and anything unpublished are invisible, so a product you already hid will correctly not appear here.
- It stops at 2,500 products. That ceiling is ours, not the platform's. The feed keeps paging well past it. We cap the run because each request is fired at a store that never opted into being scanned, and 2,500 products is ten requests at the normal page size, twenty five if the feed is heavy enough that the scan has to drop to smaller pages. When the ceiling is reached the results say so at the top, and print the page size actually used, rather than quietly reporting a partial catalogue as a whole one.
- Paste a collection URL to get past the cap. Shopify publishes the same feed per collection, so
example.com/collections/knitwearscans that collection only and you can work a big catalogue in slices. - It cannot see a password protected store. If the storefront is locked there is no public feed to read and the scan fails with an error rather than a fabricated result.
- Headless storefronts are hit and miss. A custom frontend may not serve the endpoint on the domain you typed. The underlying myshopify.com domain usually still does.
- It does not judge photo quality. A product with one blurry, badly cropped, wrongly coloured photo counts as having an image. Presence is all this checks. For quality, alt text and filenames, use the Product Image Audit.
- It reads the default market. The feed returns products as your primary storefront serves them, so region specific catalogue differences will not show up.
Fetched pages are also cached for a few minutes on our side to stay polite to the store being scanned. Fix something and re-run within that window and you may see the previous result, so give it a moment before concluding the fix did not work.
If the product count this scan reports does not match what your admin shows, unpublished items are almost always the explanation. The Store Analyzer gives you the same public catalogue total alongside the theme and collection counts, which is a quick way to confirm the number rather than assume the scan missed something.
Common mistakes when auditing product images
- Treating the raw zero image count as a bug count. This is the big one, and the brooklinen numbers above show how far off it can be. Read the page building block group before you panic, and read the no product type group before you relax, because only the first of those two is left out of the headline.
- Deleting first and thinking second. Hiding is reversible and delete is not. If the only thing wrong with a product is that nobody photographed it, deleting is the most expensive possible response to a missing JPEG.
- Fixing in catalogue order. Your traffic is concentrated in a small number of products. Cross reference this list against your analytics and fix what people actually land on first. A product with no photo and no visitors costs you nothing today.
- Shooting new photography before checking what exists. A surprising share of missing images are uploaded somewhere already and were never attached to the product. Export your library and check before you book a studio.
- Assuming a thin gallery is a defect. One photo across nine sizes is correct. One photo across nine colours is not. Same number, and the option name is the only thing that separates them.
- Running the audit once. Image gaps come back with every bulk import, every supplier feed sync and every product duplicated from a template. Put it on a monthly reminder and the number stays small. Checking the import file before it goes in helps too, and the Product CSV Validator reads a Shopify product CSV and reports the row level problems it finds.
- Writing the redirect before the delete. It will not take. Shopify only applies a redirect to a URL that is already broken, so a redirect created while the product is still live does nothing at all. Save the handles first, delete, then write the redirects.
- Losing the handles. That is the part you genuinely cannot recover after a delete. Export this scan's CSV before you remove anything, because the handle column is what every redirect is written against.
Related Tools
- Variant Image Coverage Checker: the variant level version of this question, showing which option values have no photo of their own.
- Product Image Audit: a checklist covering alt text, filenames, dimensions and file weight on the images you do have.
- Bulk Image Renamer: rename a folder of photos to a consistent product, colour and angle pattern before a bulk upload.
- Redirect CSV Generator: build the redirect file from the handles while you still have them, ready to upload once the products are gone.
- Variant Image Checker: the single product view, with every variant and its assigned image listed out.
Our Shopify Apps
Rubik Variant Images Rubik Combined ListingsSmart Bulk Image Upload Export Product Images Bulk Delete Products
How does this tool find products with no images?
It reads the public products.json feed that every Shopify storefront serves, then checks the product level images array on each record. An empty array means no photo has ever been uploaded against that product. There is no interpretation involved and no login, API key or app install is needed, because the feed is the same data any visitor's browser can request.
Why are some zero image products listed as probably intentional?
Because a large share of them are not broken listings. Page builders and merchandising apps create pseudo products purely as containers for content blocks, and those are published on purpose with no photo. Only two signals move a product into that group: a handle starting with content-, or a product type set literally to Content. The reason is printed on every row so you can overrule it. A blank product type is not enough on its own and does not clear a product.
How accurate is the probably intentional filter?
On 8 August 2026 we read 461 products from the public feed on brooklinen.com. Fifty eight came back with an empty images array. Fifty five were page building blocks, identified by a handle starting with content- or a product type of Content. Three were genuine: ordinary listings with ordinary product types, published in 2018, that have no photo attached. So the filter took a list of 58 down to a list of 3 that somebody can actually work. On a store that names its page blocks differently, the filter will miss them and they will show up in bucket 1, which is why the tool prints the handles rather than just a count.
Does an empty product type mean a product is not real?
No, and that is exactly why a blank product type never clears a product here. Plenty of merchants never fill the field in at all, so an imageless product with a blank type is just as likely to be a broken listing as a page block. Those products get their own group so you can scan the handles, and they are still counted in the headline as missing an image. Only the content- handle prefix and a product type of Content move a product out of the fault count.
What does the placeholder filename check look for?
Products with exactly one image whose filename contains placeholder, coming-soon, no-image, default or temp. Those are the names a stand in file picks up when somebody needs an import to validate. The check has a known weakness: temp also appears inside template, temperature and contemporary, and default shows up in deliberate filenames too. The actual filename is printed in the row so a false positive is obvious at a glance.
Why flag products with one image and five or more variants?
Because a single photo carrying a lot of variants is worth a second look, not because it is automatically wrong. If the only option is Size, one photo is the correct setup and there is nothing to fix. If the option is Colour, one photo means every colour is showing the same picture. The table prints the option names next to each row so you can tell those two situations apart, and that is as far as this tool goes into variant territory.
What is the difference between this and the Variant Image Coverage Checker?
This tool is product level and answers whether a product has any photo at all, by reading the product images array. The coverage checker is variant level and answers whether each variant has a photo of its own, by reading featured_image on every variant. Run this one first, because a product with zero images cannot have a variant image problem, and there is nothing to assign until a photo exists.
Should I delete a product with no images?
Usually not, and definitely not as a first move. Deleting a Shopify product is not reversible. There is no undo and no trash to recover it from, and the variant IDs, inventory records and metafields go with it. Reviews may go too, because review apps generally key on the product ID, so check with your review app before you delete. If the only thing wrong is that nobody photographed it, unpublishing is the right response. The product record is reversible, a delete is not.
What happens to the URL when I delete a product?
It starts returning a 404, and Shopify does not create a redirect for you, so any inbound link, ad destination, email campaign or bookmark pointing at that handle is wasted until you write one. The order surprises people: Shopify's documentation says you can redirect only from broken URLs, and that if the URL still loads a valid webpage then the redirect will not work. So the redirect goes in after the delete, not before. What you do need in advance is the handle, because that is what the redirect is written against and it is much harder to find once the product is gone. Save the handles, or build the redirect file from them first, then upload it once the products are deleted.
How do I fix a lot of missing images at once?
Get the photos into one folder, name each file after the SKU or the handle it belongs to, then bulk upload. CS Smart Bulk Image Upload handles drag and drop of hundreds of images, imports straight from a Google Drive folder, and matches filenames to SKUs so each image routes to the right product. The renaming step is the part worth being careful about, because matching only works when the filenames line up.
How many products can this tool scan?
Up to 2,500 per run, read 250 products at a time, or 100 at a time if the first response comes back too large to read in one go and the scan retries at a smaller page size. The 2,500 ceiling is ours rather than the platform's, and it exists because each request is fired at a store that never opted into being scanned. The feed itself keeps paging well past 2,500. If the scan stops at that ceiling the results say so at the top, and print the page size actually used, instead of presenting a partial scan as a complete one. You can paste a collection URL such as example.com/collections/knitwear to scan one collection at a time.
Does it see draft, archived or hidden products?
No. The public feed only returns products published to the Online Store sales channel. Drafts, archived products and anything published only to a different channel are invisible to the scan. That works in your favour here: a product you have already unpublished because it has no photo will correctly not show up as a problem.
Why did the scan return nothing on a store I know has gaps?
A few possibilities. The imageless products are unpublished, so the public feed hides them. The catalogue is larger than the scan ceiling and they sit past the cut off. The store is password protected or served headless, in which case nothing was read at all. Or the products do have images and the real problem is variant level, which is a different tool. Check the product count the scan reports against what your admin shows before drawing a conclusion.
Does the CSV get uploaded anywhere?
No. The file is assembled in your browser from the scan results and saved straight to your machine. Nothing is stored on our side and nothing is written back to the store being scanned. The fetch itself is normally made by our server, which identifies itself as CraftshiftToolsBot, so it appears in the target store's logs like any other crawler. If our own endpoint is unavailable or rate limited, the request may be routed through a public CORS proxy instead, which means the store URL you typed is handed to a third party service, so do not paste a URL you would not want seen.
How often should I run this check?
Monthly for an active catalogue, and always after a bulk import, a supplier feed sync or a migration. Those three are where imageless products come from. A product duplicated from a template, a CSV row with an empty image column, a feed that timed out halfway through: each one leaves a listing with nothing to show, and nobody notices until a shopper does.