Shopify Product Image & Alt Text Inventory avatar

Shopify Product Image & Alt Text Inventory

Pricing

from $2.00 / 1,000 image records

Go to Apify Store
Shopify Product Image & Alt Text Inventory

Shopify Product Image & Alt Text Inventory

Audit image records and alt attributes from product exports before catalog migration. For Shopify media QA and accessibility teams. Check the live Pricing tab and input limits.

Pricing

from $2.00 / 1,000 image records

Rating

0.0

(0)

Developer

Practical AI Lab

Practical AI Lab

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

Export every product image from a store's public Shopify product feed, together with the product it belongs to, the variants it is linked to, its alt text, its reported size, and a list of quality flags. Use it to find missing images, missing or weak alt text, variants without their own picture, and images reused across products.

This Actor is built for catalog clean-up and migration prep. It is not a general product scraper: it does not export prices, descriptions or inventory, and it never downloads the image files.

What you get

One dataset, several record types (field recordType):

recordTypeMeaning
imageOne row per product image: product ID/handle/title/URL, image ID, position, image URL, filename, width, height, alt text, linked variant IDs/titles/SKUs, associationScope (variant or product), flags
missing-imageA product that has no image at all (NO_IMAGES)
variant-gapA variant without its own image while other variants of the same product have one
shop-summaryPer-store counts, flag totals, pages read, truncation status and a sample caveat
errorA store that could not be read, with the reason

Quality flags

FlagRule
MISSING_ALTAlt text is empty
SHORT_ALTAlt text is shorter than minAltTextLength
ALT_LOOKS_LIKE_FILENAMEAlt ends with an image extension or equals the file name (size suffixes like _800x ignored)
DUPLICATE_ALT_IN_PRODUCTSame alt text (case/punctuation-insensitive) on more than one image of a product
DUPLICATE_IMAGE_IN_PRODUCTSame image file listed twice in one product (cache query strings ignored)
SHARED_IMAGE_ACROSS_PRODUCTSSame image file used by several products in the sample
MISSING_DIMENSIONSThe feed gives no width or height
LOW_RESOLUTIONShorter side reported by the feed is below minImageDimension
INSECURE_URLImage URL is not HTTPS
TOO_FEW_IMAGESProduct has fewer than minImagesPerProduct images
NO_IMAGESProduct has no image
VARIANT_WITHOUT_IMAGESee variant-gap above

Flags are heuristics to build a work list, not verdicts. Your own accessibility or SEO guidelines decide what counts as a problem.

Input

Copy-and-run example:

{
"shopUrls": ["https://www.allbirds.com"],
"maxProductsPerShop": 50,
"minImagesPerProduct": 3,
"minImageDimension": 800,
"minAltTextLength": 10,
"includeProductsWithoutImages": true,
"includeVariantGaps": true,
"onlyFlagged": false,
"requestDelayMs": 1000
}

Replace the store with one you are allowed to analyse. The example store is only a placeholder; whether its feed is enabled and permitted by its robots.txt can change at any time, in which case you get an error record instead of data.

Accepted addresses: a store domain (https://example.com) or a collection (https://example.com/collections/sale). Product pages, IP addresses, custom ports, credentials and non-HTTPS URLs are rejected.

Example image record (illustrative, not a real result)

{
"recordType": "image",
"shop": "shop.example.com",
"productId": 1,
"productTitle": "Tee",
"imageId": 11,
"position": 1,
"imageUrl": "https://cdn.shopify.com/s/files/img11.jpg",
"imageWidth": 1200,
"imageHeight": 1200,
"altText": "",
"associationScope": "variant",
"variantIds": [101],
"variantTitles": ["Red"],
"variantSkus": ["R1"],
"flags": ["MISSING_ALT"]
}

Limitations and sample-size caveats

  • Default is a sample. maxProductsPerShop defaults to 50 and products come in the feed's own order, which is not random. Percentages from a sample must not be generalised to the whole catalog. The summary says when more products were available (truncatedByProductLimit). The hard maximum is 5,000 products per store.
  • Only stores with an enabled, robots-permitted /products.json feed can be read. Password-protected stores, stores that disabled the feed, or stores that block the request return an error record. No proxies or workarounds are used.
  • Feed data, not the rendered page. Alt text, image order and variant links come from the feed. A theme may render different alt text or hide images, and some stores assign images to variants in ways the feed does not expose.
  • Variant gaps are reported only when at least one variant has its own image. If no variant is linked to any image, all variants share the product gallery and no gap is reported.
  • Resolution is the width/height the feed reports. Images are not downloaded, so blur, watermarks, wrong crops or duplicate pictures with different file names are not detected.
  • Shared/duplicate image checks only compare products inside the same run and sample.
  • Collection feeds list the products of that collection only.
  • DNS is checked before every request, but a host that changes its DNS answer between the check and the connection cannot be fully excluded.
  • robots.txt is evaluated with a built-in parser (user-agent groups, Allow/Disallow, * and $); unusual files may be interpreted differently by other tools. A robots.txt that cannot be read (other than 404/410) skips the store.
  • Requests are sequential, one at a time, with a configurable delay (500 ms minimum), at most 21 feed pages per store and no retries. A 429 response stops that store.
  • Public product data may still be subject to a store's terms and to copyright of the images themselves. This Actor lists image URLs; it does not grant any right to reuse the images.

Billing note

The code tags each image, missing-image and variant-gap row with the pay-per-event name image-record. No payable plan or price is configured in this project. shop-summary and error records carry no event, and a store is analysed only after it was read completely, so a store that fails is never charged for rows. Pricing must be decided and configured separately after cost checks.

Project layout

  • src/urlsafety.py – URL validation, public-IP check, same-host redirects
  • src/robots.py – robots.txt policy
  • src/feed.py – bounded HTTP reader and pagination
  • src/analysis.py – compaction, association and flag logic
  • src/pipeline.py – one-store fetch without Apify dependencies
  • src/main.py – Apify entrypoint
  • tests/ – offline unit tests (fake transport and DNS, no network)

Run the offline tests from the project folder with python -m unittest discover -s tests -t ..