Wikimedia Commons Image Search: Free Images with Credit Lines avatar

Wikimedia Commons Image Search: Free Images with Credit Lines

Pricing

from $0.70 / 1,000 media file rows

Go to Apify Store
Wikimedia Commons Image Search: Free Images with Credit Lines

Wikimedia Commons Image Search: Free Images with Credit Lines

One row per Wikimedia Commons file: direct image URL, thumbnail, pixel size, format, license group and terms, whether credit is required, a ready-to-paste credit line, author, description and GPS coordinates. Search by keyword, list a category, look files up by title, or find images near a point.

Pricing

from $0.70 / 1,000 media file rows

Rating

0.0

(0)

Developer

Samat Makatov

Samat Makatov

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

One row per Wikimedia Commons file: direct image URL, thumbnail, pixel size, format, license group and terms, whether credit is required, a ready-to-paste credit line, author, description and GPS coordinates. Search by keyword, list a category, look files up by title, or find images near a point.

Wikimedia Commons is the media repository behind Wikipedia: on 2026-10-09 it held 149,313,708 files, and it only accepts files that anyone may reuse — commercial use and derivative works included. This actor reads its public API, so every row arrives with the license as the file page states it, the obligation that license carries, and a credit line you can paste under the picture. No API key, no account, no browser, no proxy.

Use cases

  • An article illustration you may publish: search your subject, keep photos at least 2000 px wide, and get the image address plus the credit line in one row.
  • Images that need no credit at all: filter the license groups down to public domain and CC0 for print, packaging or a product UI where attribution has no place.
  • The whole contents of a curated category: a museum's collection, a city's buildings, one plant genus — categories are curated by people, which search rankings are not.
  • Vectors for a design system: SVG drawings of flags, icons, coats of arms and diagrams, with the license checked before the asset ships.
  • Pictures of one place: everything geotagged within a radius of a point, for travel guides, property listings or map projects.
  • Licensing documentation for file names you already have: paste a list of file names out of an article, a CMS or an old dataset and get the license, the author and the credit line of each.
  • A scheduled watch on new uploads: order by newest uploads, switch onlyNew on, and each run returns only files it has not given you before — see what a watch returns for what that means on the second run.
  • A balanced image set for model training: sortBy: random draws a different sample every run instead of the same top hits, and every row says what you are allowed to do with the file.

Input

Nothing is required: the prefilled values are a working run. Pick the job with mode, then fill the fields that mode uses.

FieldTypeDefaultAllowed values / notes
modestring (enum)searchsearch, category, files — see Modes. Strict: the platform refuses any other value before the run starts
queriesstring[]empty (prefill ["sunflower"])One search per line, up to 20. Passed to the Commons search engine as typed, with its operators. Mode search
categoriesstring[]empty (prefill ["Sunflowers"])One category per line, up to 20. Category: prefix optional, case, spaces and underscores free, a category page address also works. Mode category
fileTitlesstring[]empty (prefill two real files)Up to 200 file titles, file page addresses or direct image addresses; File: prefix optional. Mode files
mediaTypesstring[] (enum)empty = every kindbitmap, drawing, video, audio, office, 3d — see Kinds of media. Sent to the search engine. Strict enum
fileFormatsstring[] (enum)empty = any formatjpeg, png, gif, svg, tiff, webp, pdf. One format goes into the search; several are filtered on the metadata. Strict enum
minWidthPxintegerempty1–30000. Minimum pixel width; part of the search, so small files never cost a row
minHeightPxintegerempty1–30000. Minimum pixel height
licenseGroupsstring[] (enum)empty = every licensepublic-domain, cc0, cc-by, cc-by-sa, gfdl, other-free — see License groups. Checked on the file page after the metadata arrives. Strict enum
latitudenumberempty-90 to 90, decimal degrees. Needs longitude; one without the other is refused before any request
longitudenumberempty-180 to 180, decimal degrees
radiusKminteger101–500. Used only with both coordinates
sortBystring (enum)relevancerelevance, newest-uploads, oldest-uploads, recently-edited, random — see Order of results. Strict enum
addedSinceHoursintegerempty1–8760. Mode category only: files added to the category in the last N hours (UTC)
onlyNewbooleanfalseSkip files this actor already delivered to you, before it reads or charges for them (page ids remembered in a named key-value store)
thumbnailWidthPxinteger3200–2048. Width of the scaled copy in thumbnailUrl; 0 = no thumbnail
maxItemsinteger501–1000. Hard cap on the rows this run writes, shared between several searches in the order you list them
fieldsstring[]empty = every columnKeep only these columns, in this order. query, fileName, url, fileUrl, licenseShortName, found and fetchedAt are always kept (first, unless you list them yourself)

Enum fields (mode, mediaTypes, fileFormats, licenseGroups, sortBy) are checked by the platform before the run starts: an off-list value is refused with HTTP 400 and the list of allowed values, so the run never begins. The free-text fields are forgiving instead: categories and fileTitles accept any case, spaces or underscores, the namespace prefix or none, and page addresses; fields accepts any case and the snake_case spelling of a column (file_url means fileUrl), and a name that is no column of this actor is reported in the run status with the closest match ("did you mean licenseGroup?") instead of being dropped in silence. queries is handed to the search engine exactly as typed — the engine does its own stemming, and this actor never rewrites your words.

Modes

modewhat it doesfields it usesfields it ignores
searchSends each entry of queries, and/or a point from the coordinate fields, to the Commons search enginequeries, latitude/longitude/radiusKm, all filters, sortBycategories, fileTitles, addedSinceHours
categoryLists the files that sit directly in each category (subcategories are not followed)categories, addedSinceHours, all filters, sortBy (3 of 5 values)queries, fileTitles, coordinates
filesReads exactly the files you name and marks what Commons does not have with found: falsefileTitles, thumbnailWidthPx, fieldsthe filters, sortBy, queries, categories

An input the current mode does not use is named in the run's status message, so a run never pretends a value had an effect.

Reference

Kinds of media

The repository is not only photographs. mediaTypes keeps only the kinds you want, and every row repeats the value in mediaType.

valuemediaType in the rowwhat falls into it
bitmapBITMAPphotographs and scans: JPEG, PNG, TIFF, GIF, WebP
drawingDRAWINGvector drawings: SVG — flags, icons, coats of arms, diagrams, maps
videoVIDEOvideo files (WebM, OGV)
audioAUDIOrecordings, pronunciations, music (OGG, FLAC, WAV)
officeOFFICEdocuments: PDF, DjVu — scanned books, reports, sheet music
3d3D3D models (STL)

File formats

jpeg (image/jpeg), png (image/png), gif (image/gif), svg (image/svg+xml), tiff (image/tiff), webp (image/webp), pdf (application/pdf). One chosen format is pushed into the search query; the search engine takes only one format at a time, so if you pick several, the actor fetches the page and keeps the matching files — the same rows, a page that can come back thinner.

License groups

Every file on Commons may be reused, commercially included; the groups say what you owe in return. licenseGroup carries the group, licenseShortName the license as the file page names it, licenseCode its machine form, licenseUrl the license text.

groupwhat it means for youtypical licenseShortName
public-domainNo permission and no credit needed (expired copyright, work of a government that releases it, author's dedication)Public domain, PD-US
cc0The author waived everything; a credit is welcome but not requiredCC0
cc-byUse it anywhere, including commercially, but name the author and the licenseCC BY 4.0
cc-by-saSame, and anything you build on it must stay under a compatible free licenseCC BY-SA 4.0, CC BY-SA 3.0
gfdlThe GNU Free Documentation License: credit plus the license text travels with the fileGFDL 1.2
other-freeAnother free license (attribution-only licenses, open government licenses, free software licenses used for diagrams)Attribution, OGL 3
unknownThe file page states no machine-readable license. Rows keep it; licenseGroups never selects it—

attributionRequired says whether a credit line is obligatory, and attributionText is one already composed: author, license, "via Wikimedia Commons" and the file page address. The license covers copyright only — people shown in a photograph, trademarks, and buildings in countries without freedom of panorama stay your responsibility.

Order of results

valuesearch modecategory mode
relevancethe ranking of the Commons search boxthe category's own order (its sort keys)
newest-uploadsfile pages created most recently firstfiles added to the category most recently first
oldest-uploadsoldest file pages firstfiles added to the category earliest first
recently-editedfile pages edited most recently firstnot available: falls back to the category order (the status says so)
randoma different sample each runnot available: falls back to the category order (the status says so)

Search operators

queries reaches the engine behind the Commons search box, so its operators work:

  • "solar eclipse" — the phrase, not the two words apart
  • cat -drawing — exclude a word
  • incategory:"Sunflowers" — only files in that category
  • insource:helianthus — look inside the file description page
  • coat of arms -france — combine them freely

The actor adds the keywords for your filters itself (filetype:, filemime:, filew:, fileh:, nearcoord:), so you do not have to.

Examples

Large, freely licensed photographs for an article

{ "mode": "search", "queries": ["sunflower"], "mediaTypes": ["bitmap"], "minWidthPx": 2000, "maxItems": 15 }

Public domain and CC0 only, where no credit line is possible

{ "mode": "search", "queries": ["antique map"], "mediaTypes": ["bitmap"], "licenseGroups": ["public-domain", "cc0"], "minWidthPx": 1200, "maxItems": 15 }

Everything in one curated category

{ "mode": "category", "categories": ["Sunflowers"], "mediaTypes": ["bitmap"], "maxItems": 15 }

Geotagged pictures within 5 km of the Eiffel Tower

{ "mode": "search", "latitude": 48.8584, "longitude": 2.2945, "radiusKm": 5, "mediaTypes": ["bitmap"], "maxItems": 15 }

Free SVG vectors with the license checked

{ "mode": "search", "queries": ["coat of arms"], "mediaTypes": ["drawing"], "fileFormats": ["svg"], "maxItems": 15 }

License lookup for file names you already have, three columns only

{ "mode": "files", "fileTitles": ["File:Tour Eiffel Wikimedia Commons.jpg", "Suncokret 22.jpg", "https://commons.wikimedia.org/wiki/File:World_Map_1689.JPG"], "fields": ["licenseShortName", "attributionText", "widthPx"] }

Watch a topic on a schedule (only new files each run)

{ "mode": "search", "queries": ["landscape photograph"], "mediaTypes": ["bitmap"], "sortBy": "newest-uploads", "onlyNew": true, "maxItems": 50 }

Output

One row per file. A real row, the first one of cloud run 4bR9e8u1cdadSQZxq on 2026-10-10 (long lists trimmed with "…"):

{
"query": "sunflower",
"fileName": "Sunflower head 2026 G1.jpg",
"pageId": 196721727,
"url": "https://commons.wikimedia.org/wiki/File:Sunflower_head_2026_G1.jpg",
"fileUrl": "https://upload.wikimedia.org/wikipedia/commons/3/3f/Sunflower_head_2026_G1.jpg",
"thumbnailUrl": "https://thumb.wikimedia.org/wikipedia/commons/thumb/3/3f/Sunflower_head_2026_G1.jpg/330px-Sunflower_head_2026_G1.jpg",
"thumbnailWidthPx": 320,
"thumbnailHeightPx": 213,
"widthPx": 6000,
"heightPx": 4000,
"fileSizeBytes": 5667006,
"mediaType": "BITMAP",
"mimeType": "image/jpeg",
"licenseShortName": "CC BY 4.0",
"licenseCode": "cc-by-4.0",
"licenseGroup": "cc-by",
"licenseUrl": "https://creativecommons.org/licenses/by/4.0",
"usageTerms": "Creative Commons Attribution 4.0",
"restrictions": null,
"attributionRequired": true,
"attributionText": "George Chernilevsky, CC BY 4.0, via Wikimedia Commons (https://commons.wikimedia.org/wiki/File:Sunflower_head_2026_G1.jpg)",
"author": "George Chernilevsky",
"credit": "Own work",
"description": "Sunflower head. Ukraine, Vinnytsia Rajon.",
"dateCreated": "2026-07-21 08:55:25",
"fileVersionAt": "2026-08-03T11:18:48.000Z",
"uploadedBy": "George Chernilevsky",
"categories": ["Helianthus annuus", "Featured pictures of flowers", "Sunflowers in Ukraine", "…"],
"latitude": null,
"longitude": null,
"matchSnippet": "org/licenses/by/4.0CC BY 4.0 Creative Commons Attribution 4.0 truetrue English Sunflower head. Ukraine, Vinnytsia Rajon. …",
"found": true,
"fetchedAt": "2026-10-10T00:14:13.561Z"
}
FieldTypeMeaning
querystringThe search words, category name or file title this row came from. Always filled
fileNamestringFile name without the File: prefix. Always filled
pageIdnumberPermanent file page id on Commons. Filled when the file was found
urlstringThe file page, where license and description are shown. Always filled
fileUrlstringThe file itself, on the repository upload host. Filled when found
thumbnailUrl, thumbnailWidthPx, thumbnailHeightPxstring, numberA scaled copy and its real size. Filled when thumbnailWidthPx > 0
widthPx, heightPx, fileSizeBytesnumberPixel size and byte size. Filled when found
mediaTypestringBITMAP, DRAWING, VIDEO, AUDIO, OFFICE, 3D. Filled when found
mimeTypestringFormat as a mime type, e.g. image/jpeg. Filled when found
licenseShortNamestringThe license as the file page names it. Filled for almost every file
licenseCodestringMachine form of the license (cc-by-sa-4.0, pd, cc0); null on files whose page gives only a name
licenseGroupstringThe obligation group, normalised by this actor. Filled when found
licenseUrlstringAddress of the license text, where the file page gives one
usageTermsstringThe full license name as the file page writes it
restrictionsstringNon-copyright warnings (trademark, personality rights); usually empty
attributionRequiredbooleanWhether a credit line is obligatory. False for public domain and CC0
attributionTextstringA credit line ready to paste: author, license, repository, file page
authorstringAuthor as the file page states it, markup removed
creditstringWhere the file came from ("Own work", a museum, another site)
descriptionstringThe file description, markup removed, cut at 1000 characters
dateCreatedstringWhen the work was made, as the file page states it — often a date, sometimes free text
fileVersionAtstringWhen the current version was uploaded, ISO 8601 UTC
uploadedBystringCommons account that uploaded the current version
categoriesstring[]Categories the file page is in
latitude, longitudenumberCoordinates the uploader geotagged the file with; null when it has none
matchSnippetstringThe search engine's highlight for this file. Keyword searches only
foundbooleanFalse only on the marker row an unknown file title or category produces. Always filled
fetchedAtstringWhen this run read the file, ISO 8601 UTC. Always filled

Dataset views: Images (preview, file, description, size, format, license, credit required, author, links), License and credit (license name, group, code, text address, usage terms, credit required, credit line, author, source, restrictions), File and place (search, kind, format, size, bytes, created, file version, coordinates, fetched).

Every run also writes a SUMMARY record into its default key-value store: rows delivered, files read, matching files the engine reported, category file counts, what each filter dropped, requests made, deferred and failed requests, and the inputs the mode ignored.

With onlyNew on, the SUMMARY.onlyNew object holds the whole bookkeeping of the watch in one place, so you can check the run against itself: which store and record hold the memory, filesRememberedBeforeThisRun and filesRememberedNow, skippedAsAlreadyDelivered (the figure the run status quotes) split into skippedBeforeReadingMetadata and skippedWhenStoring, plus filesRead and delivered. Two counters next to it, skippedAsSeen and skippedAsAlreadyStored, belong to the shared run machinery and count only rows stopped at the moment of writing; because this actor recognises an already delivered file from its listing entry and drops it before reading it, those two normally stay at 0 on a healthy watch while skippedAsAlreadyDelivered carries the count. The note field inside onlyNew says the same thing in the record itself.

Use it from code / agents

curl -X POST "https://api.apify.com/v2/acts/yadroo~wikimedia-commons-images/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"mode":"search","queries":["sunflower"],"mediaTypes":["bitmap"],"minWidthPx":2000,"maxItems":15}'
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('yadroo/wikimedia-commons-images').call({
mode: 'files',
fileTitles: ['File:Tour Eiffel Wikimedia Commons.jpg'],
fields: ['licenseShortName', 'attributionText'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("yadroo/wikimedia-commons-images").call(run_input={
"mode": "category", "categories": ["Sunflowers"], "maxItems": 50,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items

MCP: add https://mcp.apify.com to Claude / Cursor / any MCP client and call the yadroo/wikimedia-commons-images tool with the same JSON input. The input schema describes every field and its allowed values, so an agent can fill it without further documentation, and each run's SUMMARY record tells the agent what the run did.

Pricing

Pay per event: $0.001 per run start + $0.001 per file row. Every run pays the start event, also a run that returns nothing.

RunCost
15 rows (one search, the examples above)0.001 + 15 × 0.001 = $0.016
50 rows (the default maxItems)0.001 + 50 × 0.001 = $0.051
1000 rows (the maximum one run writes)0.001 + 1000 × 0.001 = $1.001

Lower tiers pay less per row automatically (Bronze $0.0009, Silver $0.0008, Gold and above $0.0007 per row); the start event is flat.

A found: false marker row — a file title or a category Commons does not have — is a dataset row and is charged like any other, because it carries the answer to that part of your input. Files the filters drop are not rows and cost nothing. The run also stops at the "Maximum cost per run" you set when you start it: it keeps every row you paid for, writes them to the dataset and says so in its status message ("Stopped at your spending limit: N rows delivered").

Limits & FAQ

What Commons does not hold. It is not a stock library. There is hardly any current product photography, press imagery, celebrity or model photography, and almost no logos in current use. What it does hold in depth: landscapes, plants and animals, buildings and streets, maps and historical scans, portraits of public figures, flags and coats of arms, diagrams, and public-sector imagery. Its relevance ranking is also weaker than a web search engine's — a broad word can return a map or a diagram where you expected a photograph, which is what mediaTypes, fileFormats, minWidthPx and matchSnippet are there for.

Speed and what fits in one run. Measured in the Apify cloud at 256 MB on 2026-10-10: a 50-row run takes 2 requests and 4–6 seconds end to end; a 15-row run takes 5 seconds; a run that read 1 050 files' metadata used 42 requests and 44 seconds, with no request throttled or deferred. So one page of 50 files costs 2 requests (the listing and the metadata), and the sustained pace is one request per second to commons.wikimedia.org, retries included — the pace Wikimedia's API etiquette asks of automated clients. maxlag=5 lets the API defer us while its databases lag; a deferred request is waited out and repeated rather than pushed harder. At that pace the largest input the schema allows (1 000 rows) needs about 45 seconds and sits comfortably inside the default 900-second run timeout. If a run does come close to its timeout — a license filter that drops most of what it reads, say — it stops early, keeps every row it had already read and says so: "Stopped before the run timeout: N rows saved." Verified on 2026-10-10 with a 60-second run that read 1 050 files, kept the 4 matching ones and ended SUCCEEDED with that status.

Rate limits. The API publishes no quota and we have seen no 429 from it. A run that asks for much more than it can read in one go stops after 160 requests with a status telling you to narrow the search or lower maxItems.

Subcategories are not followed. category mode lists what sits directly in the category; the status message says how many files the category holds and how many subcategories it has, so you can list those too if you want them. Some categories — Eiffel Tower, for one — hold no file of their own at all and only group subcategories; a run on one of those writes no row and says exactly that, so you know to name the subcategory you meant.

No upload-date filter in keyword search. The search engine has none, so addedSinceHours works in category mode only. To watch a topic, use sortBy: newest-uploads with onlyNew.

What a watch with onlyNew returns, run after run. onlyNew remembers the page id of every file it has written for you and skips that file in later runs — before the run reads its metadata, so you are never charged for it twice. What it does not mean is "only files uploaded since the last run": the memory is of what you were given, not of a point in time. So a watch of sortBy: newest-uploads with maxItems: 50 gives you the 50 newest files on the first run; on the second run those 50 are skipped and you get the next 50 you have not been given — older uploads, deeper in the same result list — and so on until the watch has worked through everything the search matches, after which a run returns only what has been uploaded since. That is what you want for building up a collection; if instead you only ever want the last few hours, watch a category with addedSinceHours (which is a real time window) or keep maxItems at the number of new files you expect per run. Every run says how many files it skipped in its status message and in SUMMARY.onlyNew.skippedAsAlreadyDelivered, next to how many files the memory held before the run and holds now — see Output for the full record and for why the run-wide skippedAsSeen counter reads 0 while a watch is working normally.

dateCreated is not always a date. It is whatever the uploader wrote on the file page: 2009-06-01, 2008-11, 19th century, sometimes a sentence. fileVersionAt is always a real UTC timestamp.

Geotags exist only where an uploader added them. Coordinate search finds the files that carry coordinates, which is a minority of the repository, and the coordinates may describe where the camera stood or what it pointed at.

The license covers copyright only. People depicted, trademarks, and freedom of panorama in the country where a building stands are not covered by the file's license and remain yours to judge. restrictions repeats any warning the file page carries.

Empty results are never silent. A search that matches nothing, a category that does not exist, a file title Commons has never had: the run says which input it was, and files mode writes a found: false row for it instead of dropping it.

Questions or problems: open an issue on the Issues tab of this actor.


Made by Yadroo. Sibling actors: wikipedia-search, openlibrary-books, openalex-works, nasa-eonet-events, data-gov-datasets.