# Website Image Extractor (`automation-lab/website-image-extractor`) Actor

Extract normalized image asset URLs, srcset variants, alt text, dimensions, context, and source-page provenance from anonymously reachable public web pages.

- **URL**: https://apify.com/automation-lab/website-image-extractor.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Website Image Extractor

Build a clean inventory of images referenced by public web pages.

Website Image Extractor turns `<img>`, `<picture>`, social preview, preload, and inline CSS image references into normalized dataset records. Each result keeps the source page, original HTML value, absolute asset URL, alt text, dimensions, responsive variants, semantic context, and discovery time.

It is designed for content audits, website migrations, accessibility reviews, media catalogs, and repeatable data pipelines. It extracts references and metadata; it does not download or re-host image files.

### What the website image extractor does

The Actor accepts one or more anonymously reachable HTTP or HTTPS pages.

For every fetched HTML page it can find:

- `<img src>` and common lazy-load attributes;
- `<img srcset>` and lazy-loaded srcset candidates;
- `<picture><source srcset>` candidates;
- Open Graph and Twitter preview images;
- `rel=image_src` and image preload links;
- image URLs in inline `background` and `background-image` styles.

Relative and protocol-relative references become absolute URLs.

Fragments are removed for stable matching.

Repeated references to the same asset on one page produce one record.

The same asset on two pages produces two records so provenance is preserved.

### Who is it for

**Content and SEO teams** can audit missing alt text and locate image assets before a redesign.

**Migration teams** can inventory media references before moving a site or CMS.

**Developers** can feed normalized asset URLs into validation, optimization, or archival workflows.

**Data teams** can schedule bounded crawls and compare exported datasets over time.

**Accessibility reviewers** can identify the HTML alt text and declared dimensions available in the server response.

Choose a search-engine image Actor when you want images discovered by a keyword search rather than assets referenced by supplied pages.

### Why use this Actor

A raw list of URLs loses the evidence needed for review.

This Actor keeps page-level provenance and useful context in every record.

It also:

- handles responsive `srcset` variants;
- distinguishes element sources such as `img`, `meta`, and CSS;
- records nearby semantic context and text;
- supports multiple start pages;
- supports bounded same-domain crawling;
- rejects private and local destinations;
- stops at explicit page and result limits;
- produces CSV, JSON, Excel, XML, RSS, or API output through Apify datasets.

The HTTP-first implementation is lightweight and predictable. It does not start a browser when static server HTML already contains the references.

### Getting started

1. Open the Actor input page.
2. Add one or more public page URLs under **Public page URLs**.
3. Set **Maximum image records**.
4. Leave **Internal crawl depth** at `0` for only the supplied pages.
5. For a small site inventory, set crawl depth to `1` and choose a bounded page limit.
6. Keep **Keep crawls on the start domain** enabled unless cross-domain page crawling is intentional.
7. Run the Actor.
8. Open the **Image inventory** dataset view.
9. Export the results or connect the dataset API to a downstream workflow.

A useful first input is:

```json
{
  "startUrls": [
    { "url": "https://en.wikipedia.org/wiki/Apollo_11" }
  ],
  "maxItems": 25,
  "maxPages": 1,
  "maxCrawlDepth": 0,
  "includeCssBackgrounds": true
}
```

### Input parameters

| Field | Type | Default | Purpose |
|---|---:|---:|---|
| `startUrls` | array | required | Public HTTP/HTTPS pages to inspect |
| `maxItems` | integer | `100` | Maximum image records saved across all pages |
| `maxPages` | integer | `1` | Maximum successfully fetched pages |
| `maxCrawlDepth` | integer | `0` | Internal link depth, from 0 through 5 |
| `sameDomainOnly` | boolean | `true` | Keep followed pages on each start hostname |
| `includeCssBackgrounds` | boolean | `true` | Parse inline CSS background URLs |
| `includeDataUrls` | boolean | `false` | Include large embedded `data:image` values |

Up to 100 start URLs can be supplied in one run.

`maxItems` can be from 1 to 100,000.

`maxPages` can be from 1 to 1,000.

Page crawling follows ordinary anchor links found in fetched HTML.

Image assets can still live on a CDN when same-domain page crawling is enabled.

### Extracted data

| Field | Meaning |
|---|---|
| `imageUrl` | Absolute normalized image asset URL |
| `originalUrl` | Reference exactly as found in HTML |
| `sourcePageUrl` | Page where the reference was found |
| `sourceElement` | `img`, `picture-source`, `meta`, `link`, or `css-background` |
| `altText` | Alt attribute, or `null` |
| `titleText` | Title attribute, or `null` |
| `width` / `height` | Integer HTML dimensions, or `null` |
| `srcsetVariants` | Responsive candidate URLs and descriptors |
| `linkUrl` | Nearest wrapping link, or `null` |
| `contextType` | Nearest semantic container |
| `contextText` | Nearby normalized text, truncated to 300 characters |
| `loading` | Loading attribute, or `null` |
| `fileName` | Decoded final URL path segment |
| `extension` | Lowercase extension inferred from the path |
| `isDataUrl` | Whether the value is an embedded data image |
| `discoveredAt` | ISO 8601 extraction timestamp |

Fields may be `null` when the source page does not declare that metadata.

The Actor does not request each image file, so dimensions are HTML declarations rather than measured binary dimensions.

### Output example

A current result has this shape:

```json
{
  "imageUrl": "https://upload.wikimedia.org/example/mission-photo.jpg",
  "originalUrl": "//upload.wikimedia.org/example/mission-photo.jpg",
  "sourcePageUrl": "https://en.wikipedia.org/wiki/Apollo_11",
  "sourceElement": "img",
  "altText": "Mission crew photograph",
  "titleText": null,
  "width": 220,
  "height": 174,
  "srcsetVariants": [
    {
      "url": "https://upload.wikimedia.org/example/mission-photo-440.jpg",
      "descriptor": "2x"
    }
  ],
  "linkUrl": "https://en.wikipedia.org/wiki/File:Mission_photo.jpg",
  "contextType": "figure",
  "contextText": "Mission crew photograph",
  "loading": "lazy",
  "fileName": "mission-photo.jpg",
  "extension": "jpg",
  "isDataUrl": false,
  "discoveredAt": "2026-01-15T12:00:00.000Z"
}
```

The example values are anonymized; actual records contain the source page's public values.

### How much does it cost to extract website images?

Pricing uses one start event plus one item event for each saved image record.

The current start fee is **$0.005 per run**.

At the BRONZE tier, each saved image record is **$0.001336**.

Approximate BRONZE totals are:

| Saved images | Approximate total |
|---:|---:|
| 25 | $0.0384 |
| 100 | $0.1386 |
| 1,000 | $1.3410 |

Higher usage tiers receive lower per-item prices.

Failed or duplicate image candidates are not charged as item events.

Page count affects platform runtime but is not a separate charge event.

Always check the live pricing panel for the tier applied to your account.

### Website migration workflow

1. Start with the most important landing pages.
2. Run a one-page inventory to verify the source HTML exposes expected assets.
3. Increase `maxCrawlDepth` to `1`.
4. Set a conservative `maxPages` such as 25.
5. Export the dataset as CSV or JSON.
6. Group by `sourcePageUrl` for page ownership.
7. Group by `imageUrl` to identify assets reused across pages.
8. Validate or copy assets in a separate authorized system.
9. Rerun after migration and compare normalized URLs.

Because provenance is retained, one shared image can be traced back to every page that references it.

### Accessibility and content audit workflow

Filter records where `sourceElement` is `img` and `altText` is `null`.

Review decorative images separately from meaningful content images.

Use `contextType` and `contextText` to prioritize records without opening every page first.

A missing alt attribute and an empty alt attribute both appear as `null`; verify decorative intent against the source page before changing content.

The Actor reports declarations, not accessibility conformance.

### Recurring inventory and monitoring

Apify schedules can run the same bounded input daily, weekly, or monthly.

Export each run's dataset to your warehouse or spreadsheet.

Compare stable keys built from `sourcePageUrl` and `imageUrl`.

This can reveal:

- newly referenced assets;
- removed references;
- URL changes after CDN or CMS migrations;
- changes to declared alt text;
- changes to declared dimensions;
- new responsive variants.

The Actor does not itself send alerts or compare past runs.

Use an Apify integration, webhook, or your own pipeline for that step.

### JavaScript and rendered-page limitations

The Actor parses the HTML returned by an HTTP request.

It does not execute JavaScript.

Images inserted only after client-side rendering will not appear.

Lazy references already present in `data-src`, `data-original`, `data-lazy-src`, or `data-srcset` are supported.

Images discovered only through external stylesheets are not included.

Inline CSS backgrounds are optional and enabled by default.

Shadow DOM, canvas content, video poster extraction, and authenticated pages are outside the current scope.

For JavaScript-only pages, supply a server-rendered public URL when the site offers one.

### Crawling behavior and limits

Depth `0` processes only supplied pages.

Depth `1` can follow links found on those pages.

The queue stops when `maxPages` or `maxItems` is reached.

Redirects are followed up to five times and each destination is checked again.

Transient 408, 425, 429, and selected 5xx responses can be retried twice.

Responses must be successful HTML and no larger than 10 MB.

A failed page is logged and other queued pages continue.

The run fails if none of the supplied pages can be fetched successfully.

A successfully fetched page with no image references is a valid empty result.

### Legality and responsible use

Only anonymously reachable public HTTP and HTTPS pages are supported.

The Actor rejects URL credentials, localhost names, private IP space, link-local addresses, and reserved addresses.

Redirect destinations receive the same validation.

Only process pages and asset references you are authorized to access.

Respect website terms, robots guidance, copyright, privacy, and database rights.

An image URL in a public page does not grant permission to copy, redistribute, or train on the image.

This Actor extracts references and metadata; users remain responsible for downstream use.

### Export and integrations

The default Apify dataset can be downloaded as JSON, CSV, Excel, XML, or RSS.

Common integrations include:

- Google Sheets for a content-owner review queue;
- cloud storage for dated inventory snapshots;
- webhooks for pipeline completion;
- Make or Zapier for no-code routing;
- Python or JavaScript jobs for diffing datasets;
- a media validator that checks status, content type, or binary dimensions.

Use `imageUrl` as the asset identifier and `sourcePageUrl` as the provenance dimension.

### API usage with cURL

Start a run and wait for its dataset items:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~website-image-extractor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": [{"url": "https://www.python.org/"}],
    "maxItems": 50,
    "maxPages": 1,
    "maxCrawlDepth": 0
  }'
```

Keep your token in an environment variable rather than source code.

### API usage with JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor('automation-lab/website-image-extractor').call({
  startUrls: [{ url: 'https://www.python.org/' }],
  maxItems: 50,
  maxPages: 1,
  maxCrawlDepth: 0,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### API usage with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/website-image-extractor').call(run_input={
    'startUrls': [{'url': 'https://www.python.org/'}],
    'maxItems': 50,
    'maxPages': 1,
    'maxCrawlDepth': 0,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use with Apify MCP

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/website-image-extractor"
```

The same endpoint works in **Claude Desktop**, **Cursor**, and **VS Code** MCP configuration panels. Add this HTTP server configuration in the client you use:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/website-image-extractor"
    }
  }
}
```

Example prompts:

- "Extract up to 50 image records from the Python.org homepage and show items without alt text."
- "Build an image inventory from three public pages and group results by source page."
- "Crawl at most five internal pages from this homepage and export normalized image URLs."

### Troubleshooting

#### The run returned no records

Open the page source rather than only the rendered browser view.

If image references are inserted solely by JavaScript, this HTTP Actor will not see them.

Also verify that the response is public HTML and that `maxItems` is at least 1.

#### A page failed with HTTP 403 or 429

The website may disallow automated anonymous requests or rate-limit traffic.

Reduce the page count and retry later.

The current Actor does not expose a residential proxy or browser fallback.

#### Some dimensions are null

The HTML did not provide integer `width` or `height` attributes.

The Actor does not download image binaries to measure intrinsic dimensions.

#### CSS images are missing

Only inline style declarations are parsed.

Images found exclusively in external CSS files are outside the current scope.

#### A crawl did not follow an external link

`sameDomainOnly` defaults to true.

Disable it only when cross-domain page crawling is intentional and authorized.

### FAQ

#### Does this website image downloader save image files?

No. It extracts image URLs and metadata into a dataset. Use a separate authorized downloader if you need the binary files.

#### Does it extract responsive images?

Yes. It normalizes `srcset` and `<picture><source>` candidates with width or density descriptors.

#### Can it crawl a complete website?

It supports bounded link crawling, not an unlimited whole-site guarantee. Set explicit depth, page, and item limits.

#### Does it use a browser?

No. It uses lightweight HTTP requests and parses server-returned HTML.

#### Can it access logged-in pages?

No. The supported scope is anonymously reachable public pages.

#### Are duplicate images removed?

Duplicate asset URLs on one source page are collapsed. The same asset on different pages remains in each page's inventory.

#### Can I schedule it?

Yes. Use Apify schedules and send each run's dataset to your preferred integration.

### Related Automation Lab Actors

- [Link Extractor](https://apify.com/automation-lab/link-extractor) for page-link inventories.
- [Structured Data Extractor](https://apify.com/automation-lab/structured-data-extractor) for JSON-LD and metadata.
- [Webpage Text Extractor](https://apify.com/automation-lab/webpage-text-extractor) for clean page text.

These tools complement the image inventory without changing this Actor's output contract.

# Actor input Schema

## `startUrls` (type: `array`):

One or more public HTTP/HTTPS pages to inspect. Private, local, authenticated, and credential-bearing URLs are rejected.

## `maxItems` (type: `integer`):

Stop after saving this many unique image records across all processed pages.

## `maxPages` (type: `integer`):

Maximum number of successfully fetched pages. Increase this only when crawl depth is greater than zero or multiple start URLs are supplied.

## `maxCrawlDepth` (type: `integer`):

Follow links from each start page up to this depth. Zero inspects only the supplied URLs; the maximum is 5.

## `sameDomainOnly` (type: `boolean`):

When crawling links, follow only pages on the same hostname as each start URL. Image assets may still point to CDNs.

## `includeCssBackgrounds` (type: `boolean`):

Extract image URLs from inline style background and background-image declarations. External stylesheets are not fetched.

## `includeDataUrls` (type: `boolean`):

Include data:image URLs embedded directly in HTML. Disabled by default because these records can be very large.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://en.wikipedia.org/wiki/Apollo_11"
    }
  ],
  "maxItems": 20,
  "maxPages": 1,
  "maxCrawlDepth": 0,
  "sameDomainOnly": true,
  "includeCssBackgrounds": true,
  "includeDataUrls": false
}
```

# Actor output Schema

## `dataset` (type: `string`):

Default dataset containing all extracted image records.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        {
            "url": "https://en.wikipedia.org/wiki/Apollo_11"
        }
    ],
    "maxItems": 20,
    "maxPages": 1,
    "maxCrawlDepth": 0
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/website-image-extractor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": [{ "url": "https://en.wikipedia.org/wiki/Apollo_11" }],
    "maxItems": 20,
    "maxPages": 1,
    "maxCrawlDepth": 0,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/website-image-extractor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://en.wikipedia.org/wiki/Apollo_11"
    }
  ],
  "maxItems": 20,
  "maxPages": 1,
  "maxCrawlDepth": 0
}' |
apify call automation-lab/website-image-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/website-image-extractor"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Gu9YRP9jSlAou8cFv/builds/ThEKJDjjCvlDeVYub/openapi.json
