# Unsplash Image Search Scraper with Attribution (`khadinakbar/unsplash-image-scraper`) Actor

Search public Unsplash photos by keyword and export source-attributed image metadata for visual research and asset catalogs.

- **URL**: https://apify.com/khadinakbar/unsplash-image-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 unsplash image founds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Unsplash Image Search Scraper

Search public Unsplash photos by keyword and save one normalized, source-attributed record per photo. Use it for visual research, content planning, and asset catalogs when you need public photo-page URLs, delivery URLs, photographer attribution, dimensions, tags, source query, and collection time.

### Choose this Actor when

- You have one to ten descriptive image-search phrases, such as `minimal home office` or `mountain lake`.
- You need structured metadata for each result rather than manually browsing a results page.
- You need provenance fields (`photoUrl`, `sourceUrl`, `scrapedAt`) and a clear Unsplash licensing reference alongside every record.

Do not use it to download image files, to obtain rights to an image, or to fetch a known photo by URL or ID. It searches public Unsplash result pages and returns metadata and image delivery URLs; review the [Unsplash License](https://unsplash.com/license) before using any image.

### What one result means

Each dataset row represents one unique public Unsplash photo found for a submitted query. The Actor deduplicates photo IDs across all queries in the run and records the query that produced the item.

| Field                                         | Meaning                                                                           |
| --------------------------------------------- | --------------------------------------------------------------------------------- |
| `photoUrl`                                    | Canonical public Unsplash photo page.                                             |
| `imageUrlRegular`                             | Image delivery URL suitable for a regular-size preview when provided by Unsplash. |
| `photographerName` / `photographerProfileUrl` | Public attribution supplied by Unsplash.                                          |
| `width` / `height`                            | Source dimensions in pixels when available.                                       |
| `tags`                                        | Public Unsplash tags, if supplied.                                                |
| `sourceUrl` / `scrapedAt`                     | Requested search page and ISO-8601 collection time.                               |
| `license` / `licenseUrl`                      | Source licensing context, not a grant of rights from this Actor.                  |

Here is a real normalized record from a canary search on 2026-07-15 (some nullable fields omitted only for readability):

```json
{
    "id": "7VotVatHM7Q",
    "title": "a lake surrounded by trees with mountains in the background",
    "photoUrl": "https://unsplash.com/photos/a-lake-surrounded-by-trees-with-mountains-in-the-background-7VotVatHM7Q",
    "imageUrlRegular": "https://plus.unsplash.com/premium_photo-1673240367277-e1d394465b56?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXxzZWFyY2h8MXx8bW91bnRhaW4lMjBsYWtlfGVufDB8fHx8MTc4NDEzODY0N3ww&ixlib=rb-4.1.0&q=80&w=1080",
    "width": 4240,
    "height": 2832,
    "photographerName": "Davey Gravy",
    "photographerProfileUrl": "https://unsplash.com/@davey_gravy",
    "query": "mountain lake",
    "rank": 1,
    "sourceUrl": "https://unsplash.com/s/photos/mountain%20lake?orientation=landscape&color=blue",
    "scrapedAt": "2026-07-15T18:04:07.739Z",
    "license": "Unsplash License",
    "licenseUrl": "https://unsplash.com/license"
}
```

### Quick start

The default run searches `mountains`, saves up to 10 results for that query, and never saves more than 20 rows in total. Use a smaller cap for the lowest-cost test.

```json
{
    "queries": ["mountain lake", "minimal home office"],
    "maxItemsPerQuery": 5,
    "maxTotalItems": 8,
    "orientation": "landscape",
    "color": "blue",
    "orderBy": "relevant"
}
```

The Actor accepts plain-language search phrases only. `orientation`, `color`, and `orderBy` filter Unsplash's result feed; they do not alter image pixels or re-sort the saved dataset.

#### API example

```bash
curl -sS -X POST \
  "https://api.apify.com/v2/acts/khadinakbar~unsplash-image-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "queries": ["mountain lake"],
    "maxItemsPerQuery": 3,
    "maxTotalItems": 3,
    "orientation": "landscape",
    "color": "blue",
    "orderBy": "relevant"
  }'
```

When the run finishes, read its default dataset from the run response's `defaultDatasetId`, or open the **Images** view in the Console.

### Pricing and cost cap

This Actor uses Pay per event + usage:

- `apify-actor-start`: $0.00005 once per valid run.
- `image-found`: $0.003 for each complete, validated image record the Actor charges immediately before persisting it to the default dataset.
- Apify platform usage (browser compute and residential proxy usage) is additional and reported separately by Apify.

For example, saving 8 rows costs `$0.00005 + (8 × $0.003) = $0.02405` in event charges, plus platform usage. Before collection begins, the Actor displays the event-charge ceiling implied by your result cap. It stops saving rows when either `maxTotalItems` or the Apify event-charge limit is reached. Invalid and duplicate candidates are never charged. If Apify storage fails after a charge is accepted, the run is marked `PARTIAL` with an explicit reconciliation warning.

### A practical workflow

A content strategist preparing a brand mood board searches `warm cafe interior` and `handmade ceramics`, then exports the dataset to a spreadsheet. `photographerName`, `photoUrl`, and `licenseUrl` keep the candidate list attributable, while `width`, `height`, and `color` make it easy to filter options before the team reviews the original Unsplash pages. The Actor is read-only: it does not modify Unsplash or download assets.

If the team starts with a reference website rather than search terms, use the public [Website Content Crawler](https://apify.com/apify/website-content-crawler) first to extract its brand language, then pass the resulting themes here as `queries` for image discovery.

### For AI agents and MCP clients

> Search Unsplash for up to 10 landscape photos matching "mountain lake". Return each photo's title, regular image URL, photographer, dimensions, source page, and collection timestamp. Stop at 10, preserve source attribution, and report whether the run was complete, partial, or empty.

Give the Actor `queries` as an array of ordinary descriptive phrases. Read the default dataset for records and `OUTPUT` / `RUN_SUMMARY` in the default key-value store for the terminal outcome. The Actor exposes `COMPLETE`, `PARTIAL`, `VALID_EMPTY`, `INVALID_INPUT`, `UPSTREAM_FAILED`, or `CONFIG_ERROR`; only complete, validated rows are billable image events.

### Limits and recovery

| Outcome or symptom | Meaning                                                               | Next step                                                                               |
| ------------------ | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| `VALID_EMPTY`      | The query and filters were valid but produced no matching photos.     | Broaden the phrase or remove a filter.                                                  |
| `INVALID_INPUT`    | A query was blank or a result limit was outside the documented range. | Use the Quick start input shape and retry.                                              |
| `PARTIAL`          | Some useful records were saved, but a query or write failed.          | Keep the saved rows; inspect `RUN_SUMMARY.warnings` and retry only the affected search. |
| `UPSTREAM_FAILED`  | The browser could not complete a usable public Unsplash search.       | Retry later with a smaller input; no image rows are invented after a failure.           |

Unsplash can change its public site, available fields, filters, delivery URLs, and anti-bot behavior without notice. The DOM fallback intentionally returns only verified public fields and uses explicit `null` values where rich metadata is unavailable.

### Verification evidence and legal boundary

The previous deployed Chrome build `0.1.3` was canary-tested on 2026-07-15 with a `mountain lake` query and returned 3 complete rich records. The current release is verified again after deployment; target-site content and availability remain independently variable.

Use this Actor only with public or otherwise authorized data, in compliance with applicable law, the Unsplash Terms, the Unsplash License, and your own privacy and intellectual-property obligations. Metadata and URLs are not a license grant, legal advice, or a substitute for checking the original source page.

# Actor input Schema

## `queries` (type: `array`):

One to ten phrases searched independently on Unsplash, such as 'minimal home office' or 'mountain lake'. Enter plain descriptive phrases, not Unsplash URLs. If omitted, the Actor searches for 'mountains'. This field is not for image IDs or photographer usernames.

## `maxItemsPerQuery` (type: `integer`):

Maximum validated images to save from each query. Use an integer from 1 to 100; 10 is the default. Lower values make a quick, cheaper test run. This is not a page count because the Actor handles the result feed.

## `maxTotalItems` (type: `integer`):

Hard run-wide cap on images saved and billed across every query. Use an integer from 1 to 500; 20 is the default. The Actor stops when this cap or your Apify billing cap is reached. This is not a guarantee that every query will return that many matches.

## `orientation` (type: `string`):

Optional shape filter applied to the Unsplash search page. Choose landscape, portrait, squarish, or any; the default is any. Use 'squarish' for near-square photo results. This filter does not resize images.

## `color` (type: `string`):

Optional Unsplash dominant-color filter for the search results. Choose a named color such as blue or red, black\_and\_white, or any; the default is any. It filters the platform's matching results rather than changing pixels. This is not a hex-color input.

## `orderBy` (type: `string`):

Select whether Unsplash ranks matching photos by relevance or latest uploads. The default is relevant, which suits broad image discovery. Choose latest for a freshness-oriented research run. This option does not sort the dataset after collection.

## Actor input object example

```json
{
  "queries": [
    "minimal home office"
  ],
  "maxItemsPerQuery": 10,
  "maxTotalItems": 20,
  "orientation": "landscape",
  "color": "blue",
  "orderBy": "latest"
}
```

# Actor output Schema

## `images` (type: `string`):

No description

## `output` (type: `string`):

No description

## `runSummary` (type: `string`):

No description

# 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 = {
    "queries": [
        "mountains",
        "minimal home office"
    ],
    "maxItemsPerQuery": 10,
    "maxTotalItems": 20,
    "orientation": "any",
    "color": "any",
    "orderBy": "relevant"
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/unsplash-image-scraper").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 = {
    "queries": [
        "mountains",
        "minimal home office",
    ],
    "maxItemsPerQuery": 10,
    "maxTotalItems": 20,
    "orientation": "any",
    "color": "any",
    "orderBy": "relevant",
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/unsplash-image-scraper").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 '{
  "queries": [
    "mountains",
    "minimal home office"
  ],
  "maxItemsPerQuery": 10,
  "maxTotalItems": 20,
  "orientation": "any",
  "color": "any",
  "orderBy": "relevant"
}' |
apify call khadinakbar/unsplash-image-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,khadinakbar/unsplash-image-scraper"
        }
    }
}

```

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/znFBqd8AOxyNtSoiQ/builds/7HvulaLP197CwrdDK/openapi.json
