DEV Community

SteadyScrape
SteadyScrape

Posted on

Get Google Images Results as JSON in Python, With Real Image Sizes, for $0.012 a Search

Product teams often need one question answered: which images show up when shoppers search this product phrase, and from which sites? Building that yourself means wiring up a search source, handling country and language codes, removing duplicate URLs, and deciding what to do when a search comes back empty.

Usually you don't need the image files. For assortment research, marketplace checks or a creative brief, the useful output is metadata: the image URL, the page it came from, the site, the title, the rank, and the pixel size.

This walkthrough uses SteadyScrape's Google Images API Actor on Apify. It returns that metadata as JSON for public, non-personal keywords. It does not download full files, rehost or license images. A result row grants no reuse, training or copyright rights.

What a run returns

Each keyword writes one status row and one image row per result, up to 100.

Field What it means
rank Position in the image results
imageUrl, thumbnailUrl Source image URL and Google's thumbnail
sourcePageUrl, sourceDomain, sourceName The page that shows the image, its domain, and the site name Google shows
title, altText Result title and alt text
width, height Pixel size, read from the image file header. Null when it couldn't be read
queryStatus success, partial, empty, timeout, failed, blocked_operator, not_run, and more
relatedSearches, googleImagesUrl On status rows: related searches and a link to the same Google Images page

Where width and height come from

The search results don't include pixel sizes. So the Actor asks each image host for only the first bytes of the file (an HTTP range request) and stops reading as soon as the size is in the header. It reads PNG, JPEG, GIF, WebP, BMP and AVIF, contacts public hosts only, and spends about 12 seconds per keyword on this step.

Some hosts refuse range requests or answer slowly, so expect a share of nulls. In my test run for blue ceramic bowl, 51 of 100 images got a size, reading about 165 KB in total. You can turn the step off with "fillDimensions": false for the fastest runs. It never changes the status or the price.

Run it from Python

import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

run = client.actor("steady-scrape/google-images-api").call(
    run_input={
        "keywords": ["red ceramic mug", "blue ceramic bowl"],
        "country": "us",
        "language": "en",
        "depth": 100,
    }
)

for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["recordType"] == "image":
        print(row["rank"], row["sourceName"], row["width"], row["height"], row["imageUrl"])
    else:
        print("STATUS", row["keyword"], row["queryStatus"], row["imageCount"])
Enter fullscreen mode Exit fullscreen mode

Need a different country per keyword? Use the advanced form:

{
  "queries": [
    { "keyword": "red ceramic mug", "country": "us", "language": "en" },
    { "keyword": "rote Keramiktasse", "country": "de", "language": "de" }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Want to try it with no search? "dryRun": true returns labeled sample rows and nothing is charged.

A real run

A single keyword (blue ceramic bowl, US, English, depth 100):

  • 100 image rows plus a status row with 20 related searches
  • search took about 28 seconds, then about 13 seconds of size fill-in
  • 51 of the 100 images got a width and height
  • the same run included site:example.com mug, which was rejected as blocked_operator and not charged
  • charged: one $0.010 query event plus the $0.002 run event = $0.012

What it costs

  • $0.010 per keyword that returns at least one image (including a partial result with at least one image)
  • $0.002 once per run, only if at least one keyword returned images
  • Empty, failed and timed-out searches are free, and so is test mode
What you run Cost
1 keyword with images $0.012
10 keywords with images in one run $0.102
10 keywords, 2 of them find nothing $0.082
a run where nothing is found $0.000

Apify also adds its standard apify-actor-start event ($0.00005 per run at the default 256 MB). You can set a maximum cost per run, and the Actor stops sending new searches before it would go over.

Limits worth knowing

  • Up to 10 keywords per run, up to 100 images each, one search at a time.
  • Each search can take up to about 95 seconds. A search that may already have been answered is never sent twice, so you aren't charged twice.
  • Advanced operators (site:, a leading minus and similar) are rejected for free. Don't submit person or face lookups. Emails, phone numbers and profile links are rejected.
  • Live search needs a paid Apify plan.
  • Chinese must be zh-CN or zh-TW.

FAQ

Does this download the images? No. It returns links. With size fill-in on, it reads only the first bytes of each file.

Can I use the images in my store or for training? Not based on this output. Rows are search metadata, so check each source page for rights.

What does partial mean? The search returned images, but a few results were incomplete and were left out. It's charged like a success because you got images.

Can I schedule it? Yes. It's a normal Apify Actor, so you can use Apify schedules, the API, webhooks, Make, Zapier, n8n, or the Apify MCP server for AI agents.


Try it here: Google Images API on Apify. Results come from Google Images via the DataForSEO API. The Actor is not affiliated with Google.

Top comments (0)