Use Pexels Stock Media Scraper with Python
Scrape free stock photos and videos from Pexels. Search by keyword, browse curated/popular media, a photographer's portfolio, or a curated collection. Get direct image and video file URLs, photographer credit, tags, colors, and more.
1. Choose the data you need
Review the published README for supported collection modes, examples, and limits. The recipe below uses the current published input definition.
2. Prepare a source-based input
This JSON contains published prefills and required-field defaults. Review every value for your task before running it; it is not a promise of successful collection.
{
"collectionSlug": "aquatic-aesthetic-bw7dkse",
"color": "all",
"colorHex": "",
"dedupe": true,
"includeDetails": false,
"locale": "en-US",
"maxDuration": 0,
"maxItems": 3,
"mediaIds": [
"18872916"
],
"mediaType": "photos",
"minDuration": 0,
"minFps": 0,
"minHeight": 0,
"minWidth": 0,
"mode": "search",
"orientation": "all",
"peopleAge": "all",
"peopleCount": "all",
"proxyConfiguration": {
"useApifyProxy": false
},
"publishedAfter": "",
"publishedBefore": "",
"searchQueries": [
"nature"
],
"size": "all",
"username": "alex-ivanov-773258579"
}
Download input.example.json and save your reviewed copy as input.json.
| Field | Type | Required | Description |
|---|---|---|---|
mode | string | required | What to fetch from Pexels. Use Search by keyword for discovery, Look up media by ID/URL for exact assets, Photographer portfolio or Collection for a catalog, Similar media for related assets, Curated feed for Pexels' editorial selection, or Paste URLs to route any Pexels link automatically. |
searchQueries | array | optional | One or more keywords for mode=search, one per line. Each query is searched separately and duplicates are removed. Example: `nature`, `city skyline`, `coffee`. |
mediaType | string | optional | Photos, videos, or both. `all` searches photos and videos and merges the results. Exact ID/URL lookups return the requested media type regardless of this setting. |
startUrls | array | optional | Pexels search, photo, video, photographer, collection, image-file, or video-file URLs for mode=byUrl. Search URLs keep their orientation, size, color, people, and page filters. |
orientation | string | optional | Filter by media orientation. Applies to search, profile, and collection modes. |
size | string | optional | Pexels minimum-size filter. Photos: large is 24 MP, medium is 12 MP, small is 4 MP. Videos: large is 4K, medium is Full HD, small is HD. |
color | string | optional | Filter photos by dominant color. Use Color hex instead for an exact hex value. Photos only. |
colorHex | string | optional | Optional hex color such as `#2563eb` or `#fff`. Overrides the Color dropdown when set. Photos only. |
peopleCount | string | optional | Filter by how many people appear in the media. Applies to photos and videos. |
peopleAge | string | optional | Filter by the age of people in the media. Applies to photos and videos. |
locale | string | optional | Pexels locale for titles, descriptions, and search results. Search terms are used as typed. |
minWidth | integer | optional | Only return media at least this wide. 0 disables the filter. Enforced on each returned record. |
minHeight | integer | optional | Only return media at least this tall. 0 disables the filter. Enforced on each returned record. |
minFps | integer | optional | Only return videos with at least this many frames per second (for example 60). 0 disables the filter. Photos always pass. |
minDuration | integer | optional | Only return videos at least this many seconds long. 0 disables the filter. |
maxDuration | integer | optional | Only return videos at most this many seconds long. 0 disables the filter. |
publishedAfter | string | optional | Optional YYYY-MM-DD date. Only return media published on or after this date. Applied to the records returned by the current search/all listing. |
publishedBefore | string | optional | Optional YYYY-MM-DD date. Only return media published on or before this date. Applied to the records returned by the current search/all listing. |
mediaIds | array | optional | Pexels photo or video IDs, or full photo/video/image-file URLs. Used by Look up media by ID/URL and Similar media modes. |
username | string | optional | Pexels photographer handle, ID, or profile URL for mode=byUser. Example: `alex-ivanov-773258579` or `https://www.pexels.com/@alex-ivanov-773258579/`. |
collectionSlug | string | optional | Pexels collection slug or full collection URL for mode=byCollection. Example: `aquatic-aesthetic-bw7dkse`. |
maxItems | integer | optional | Maximum number of media records to return across all queries, IDs, and URLs. Pexels search serves at most about 480 records per query (20 pages of 24); a single search query cannot exceed that even with a higher value. |
includeDetails | boolean | optional | Open each media's detail page to add views, downloads, likes, camera/EXIF data, and the photographer's full profile. Adds one request per item and can be slow on large runs. Mode=byMediaId always enriches. |
dedupe | boolean | optional | Keep only the first occurrence of each photo or video across queries, IDs, and URLs. |
proxyConfiguration | object | optional | Optional Apify proxy override. The actor works directly without a proxy and escalates automatically only if Pexels blocks the run. |
3. Start an Actor run
Set APIFY_TOKEN in your environment. Python 3.10 or newer is sufficient; this recipe uses no third-party packages.
Execution may incur charges. Review current pricing on Apify. The request asks for a 120-second timeout and a charge limit; these settings are subject to Apify’s pricing and do not guarantee an all-inclusive spending cap.
import json
import os
import urllib.request
# Save the schema-derived example as input.json; review and edit it first.
with open("input.json", encoding="utf-8") as stream:
actor_input = json.load(stream)
token = os.environ["APIFY_TOKEN"]
request = urllib.request.Request(
"https://api.apify.com/v2/acts/b6anw2Kxq3xyPpgNC/runs?timeout=120&maxTotalChargeUsd=0.50",
data=json.dumps(actor_input).encode("utf-8"),
headers={"Authorization": "Bearer " + token, "Content-Type": "application/json"},
method="POST",
)
# This starts a potentially billable run. Do not automatically retry this POST.
with urllib.request.urlopen(request, timeout=40) as response:
run = json.load(response)["data"]
print("Run ID:", run["id"])
print("Status:", run["status"])
# Inspect and download results in Apify Console once the run succeeds.
4. Inspect the actual results
Open the run in Apify Console and wait for a successful completion. Use the published output schema to locate results and the dataset schema to understand declared views. Missing or optional record fields must not be treated as guaranteed values.
Free stock photos and videos from Pexels — titles, photographer credit, dimensions, tags, colors, and direct image/video file URLs.
Questions before you run
Which inputs are required?
The published required fields are mode
What does this guide verify?
The fields, prefills, and schema links are rendered from the published build. This is a usage recipe, not a paid live extraction test. Source availability and collection results can vary.
What if the run request times out?
Check Apify Console before retrying. The first request may already have created a run. Do not automatically repeat a run-creation POST.
Generated from source build rSmmuRgL2b2u0iqFa and its README and schemas. Source changes regenerate this guide; no third-party editorial claims are inferred.