I asked the Metropolitan Museum's free API for Rembrandts. It said 182.
I opened the first forty of those 182. Six were Rembrandt.
# runnable, read-only: no key, no signup
curl -s "https://collectionapi.metmuseum.org/public/collection/v1/search?q=Rembrandt&hasImages=true"
{"total":182,"objectIDs":[437398,437394,437396,436543,551786,729644,
435817,472562,438821,437769,329077,310453, ...]}
The fourth ID in that list, 436543, is a Goya. The fifth, 551786, is an Egyptian Book of the Dead written between roughly 332 and 200 B.C. Both came back HTTP 200, valid JSON, counted inside a field named total. The field is not broken. It is telling the exact truth about how many records matched the query. It is lying about what total means to the person who typed q=Rembrandt.
The one idea in this post
A free art API here means a public endpoint that returns museum collection data with no API key, no signup, no credit card. A URL you can paste into a terminal right now. Ten of them clear that bar, and I re-verified every response below with a live curl on July 16, 2026: real HTTP code, real body, trimmed but never reworded. If you want the working list and nothing else, the table is two screens down.
But the list is not why I wrote this. My last few keyless-API posts kept circling one room. A null sails through a schema check. A full, correctly shaped result list hands you the wrong top row. A perfectly current-looking timestamp sits on top of data that froze in 2024. This post moves the problem one more step, into the quietest corner of it:
A field's name is a promise the 200 does not keep. total, hasImages, isPublicDomain. Each returns HTTP 200 with a valid, plausible value. Each answers a narrower or different question than its name implies. And the record wearing that field is authoritative. It is the Met. It is Harvard. That is exactly why the label fools you: the source is real, so you stop reading the field and start trusting the word.
Museums make this visible because their data is messy in an honest, well-documented way. A search index that matches provenance text. A boolean whose real subject is a rights office, not a copyright statute. A count that is secretly a floor. None of it is a bug. All of it will put wrong numbers on your dashboard while returning 200 the whole time.
One scope note, so the numbers stay honest. I have run web scrapers in production: 2,190 runs across 32 published actors, 962 of them on one Trustpilot review scraper. That is where the habit in this post comes from, the reflex to read a field's value instead of its name, because the failures that actually hurt in production are never the crashes. But that is a scraping-and-enrichment domain. I have not run a museum-collection resolver in production, and nothing below is load-bearing on those runs. Read them as the origin of a habit, not a claim about art data.
The 10, at a glance
| # | API | What it returns | Example call | The gotcha |
|---|---|---|---|---|
| 1 | The Met | 490k+ objects, full records | GET collectionapi.metmuseum.org/.../objects/436535 |
A search miss returns objectIDs: null, not []
|
| 2 | Art Institute of Chicago | Artworks, IIIF images | GET api.artic.edu/api/v1/artworks/27992 |
The description field is CC-BY; the rest is CC0 |
| 3 | Cleveland Museum of Art | Open Access collection | GET openaccess-api.clevelandart.org/api/artworks/92937 |
Calls the rights field share_license_status, not isPublicDomain
|
| 4 | Victoria and Albert Museum | 1.4M+ objects | GET api.vam.ac.uk/v2/objects/search?q=painting |
record_count_exact flags whether the count is exact; it stayed true even at 1.3M objects |
| 5 | Yale LUX | Yale collections, Linked Art | GET lux.collections.yale.edu/api/search-estimate/item?q=... |
The endpoint is named search-estimate. The count is an estimate |
| 6 | SMK (Denmark) | Danish national gallery | GET api.smk.dk/api/v1/art/search/?keys=painting |
found counts records, many of which are not paintings |
| 7 | Wellcome Collection | Medical/cultural works | GET api.wellcomecollection.org/catalogue/v2/works?query=painting |
Top hit for "painting" is a photograph filed under Archives |
| 8 | Getty Vocabularies | AAT / ULAN / TGN, Linked Data | GET vocab.getty.edu/aat/300189808.json |
JSON-LD, not flat JSON. _label, broader, equivalent
|
| 9 | Harvard LibraryCloud | Harvard library metadata | GET api.lib.harvard.edu/v2/items.json?q=painting |
It is the library catalog, not the (key-gated) Art Museums |
| 10 | Auckland War Memorial Museum | Collection, Elasticsearch proxy | POST api.aucklandmuseum.com/search/collectionsonline/_search |
total.value: 10000 is a floor with relation: "gte", not a count |
Everything in that table returned HTTP 200 with no key on July 16, 2026. Then, below the ten, the three that ask for a key even though every tutorial calls them free, and the one field that lies not about counting but about the law.
1. The Met: the collection everything else gets compared to
The Metropolitan Museum's Collection API is keyless, no signup, and it is the one most people reach for first. Fetch an object by ID and you get the whole record.
# runnable, read-only
curl -s "https://collectionapi.metmuseum.org/public/collection/v1/objects/436535"
{"objectID":436535,"isPublicDomain":true,
"primaryImage":"https://images.metmuseum.org/CRDImages/ep/original/DP-42549-001.jpg",
"department":"European Paintings",
"constituents":[{"role":"Artist","name":"Vincent van Gogh"}]}
That is Van Gogh's Wheat Field with Cypresses, and it behaves. Public domain, image present, artist named. The trouble starts at the search endpoint, and it has two edges worth knowing before you write a loop.
First, a query that matches nothing does not return an empty list:
# runnable, read-only
curl -s "https://collectionapi.metmuseum.org/public/collection/v1/search?q=zzzxxqqnope123"
{"total":0,"objectIDs":null}
objectIDs is null, not []. Call len() on that and your loop dies at 3am. Second, an object ID that does not exist returns a 404 with a message body, so resp.json() succeeds and your happy-path code walks right into {"message":"ObjectID not found"}. Guard for both. And be gentle: there is no key, but the Met asks for polite pacing, so send a real User-Agent and cache what you can. Docs live at metmuseum.github.io.
2. Art Institute of Chicago: clean JSON with a licensing seam
The Art Institute's API is one of the pleasant ones to build on. Simple GET, sensible fields, IIIF image server. It also does something the others do not: it tells you, in the response, that two parts of the same payload carry two different licenses.
# runnable, read-only
curl -s "https://api.artic.edu/api/v1/artworks/27992?fields=id,title,is_public_domain"
{"data":{"id":27992,"is_public_domain":true},
"info":{"license_text":"The `description` field ... is licensed under a Creative Commons Attribution 4.0 Generic License (CC-By) ... All other data ... is licensed under a Creative Commons Zero (CC0) 1.0 designation ..."}}
That is Seurat's A Sunday on La Grande Jatte. Note the split: the description field is CC-BY, meaning if you show it you owe attribution, while the rest is CC0 and you owe nothing. Most people paste the whole record onto a page and quietly violate half of it. The API told you. Nobody reads info.license_text. Full docs: api.artic.edu/docs.
3. Cleveland Museum of Art: the same question, a different field name
Cleveland's Open Access API is CC0-friendly and returns rich records. It is also exhibit A for the whole thesis, because it asks the exact question the Met's isPublicDomain asks, and names the field something else.
# runnable, read-only
curl -s "https://openaccess-api.clevelandart.org/api/artworks/92937"
{"data":{"id":92937,"accession_number":"1922.1133","share_license_status":"CC0",
"title":"Stag at Sharkey's","type":"Painting","creation_date":"1909",
"department":"American Painting and Sculpture"}}
share_license_status: "CC0". Not a boolean called isPublicDomain. A string describing the sharing license. Cleveland is being more honest about what the field is: a statement about the image's reuse license, not about the copyright age of a George Bellows painting from 1909. Hold that distinction. It is the whole point of the isPublicDomain section further down. Docs: openaccess-api.clevelandart.org.
4. Victoria and Albert Museum: a count that admits when it is not exact
The V&A serves over a million objects, keyless. Search returns a compact record plus an info block, and that block has a field I wish more APIs copied.
# runnable, read-only
curl -s "https://api.vam.ac.uk/v2/objects/search?q=painting&page_size=1"
{"info":{"record_count":146517,"record_count_exact":true,"pages":9970,"image_count":207381},
"records":[{"systemNumber":"O429002","objectType":"Painting",
"_primaryTitle":"Krishna painting Radha","_primaryDate":"1948","_primaryPlace":"Sri Lanka"}]}
146,517 objects matched "painting." See record_count_exact: true. That flag is the whole point: the V&A ships a boolean whose only job is to tell you whether record_count is an exact total or a search-engine estimate. I hammered it with broad queries on July 16, up to the full 1.3-million-object catalog, and it came back true every time. I could not make it flip. But it is named and typed to carry that answer for the day the count is not exact, so you read the flag instead of guessing. That is the opposite of the trap this post is about. Compare that to number 5. Docs: developers.vam.ac.uk.
5. Yale LUX: the count that says "estimate" right in the URL
Yale's LUX is a single search layer over the university's museums, library, and archives, built on Linked Art. Keyless. It is heavier to parse than the flat-JSON museums, because it returns JSON-LD, and that is the price of the linked-data tier. It also names its counting endpoint with unusual honesty.
# runnable, read-only (-g stops curl from globbing the JSON braces into a 400)
curl -g -s 'https://lux.collections.yale.edu/api/search-estimate/item?q={"text":"painting"}'
{"@context":"https://linked.art/ns/v1/search.json",
"type":"OrderedCollection","totalItems":76574,
"first":{"id":"https://lux.collections.yale.edu/api/search/item?q=...&page=1&pageLength=20"}}
The field is called totalItems. The endpoint is called search-estimate. Read those two facts together and LUX has already told you not to trust totalItems as an exact number: it is a fast estimate, which is why there is a whole separate endpoint for it. This is the good version of the failure mode. The name of the route warns you about the meaning of the field. Most APIs do not extend you that courtesy. Docs and the Linked Art model: lux.collections.yale.edu.
6. SMK: Denmark's national gallery, and a found that counts loosely
SMK, Statens Museum for Kunst, publishes a clean keyless search over the Danish national collection, much of it CC0.
# runnable, read-only
curl -s "https://api.smk.dk/api/v1/art/search/?keys=painting&rows=1"
{"offset":0,"rows":1,"found":253,
"items":[{"id":"1170063760_object","modified":"2025-07-11T17:55:43Z"}]}
found: 253 for keys=painting. The first item back is not a painting at all: it is a drawing from the print and drawing collection whose record text happens to contain the phrase "Fundamental Painting." Same disease as the Met's Rembrandt count. keys is a full-text search over the record, and found counts every record where the word turns up, in a title, an inscription, a note. It does not count paintings. It counts the string. Note the modified field, though: SMK stamps every record with when it last changed, which is the honest half of this API. Docs: smk.dk/en/article/smk-api.
7. Wellcome Collection: search "painting", get a photograph
Wellcome holds art, books, archives, and manuscripts about health and human experience. Its catalogue API is keyless and well-built. It also shows you, in one call, why a museum search box is not a filing cabinet.
# runnable, read-only
curl -s "https://api.wellcomecollection.org/catalogue/v2/works?pageSize=1&query=painting"
{"type":"ResultList","totalResults":17584,
"results":[{"id":"sm62qtks","title":"Painting Therapy; (people painting on lawn)",
"workType":{"type":"Format","label":"Archives and manuscripts"},
"physicalDescription":"1 photograph"}]}
The top result for query=painting is a photograph of a painting-therapy session, filed under Archives and manuscripts. It is a completely correct result: the record is about painting. If you assumed query=painting returns paintings, you assumed the API indexes subjects the way you think about them, and it indexes text the way a search engine does. totalResults: 17584 is a text-match count, and its name does not warn you the way Yale's route name does. Docs: developers.wellcomecollection.org.
8. Getty Vocabularies: not a collection, a dictionary of meanings
The Getty publishes its vocabularies as Linked Open Data: the Art and Architecture Thesaurus (AAT), the Union List of Artist Names (ULAN), and the Getty Thesaurus of Geographic Names (TGN). Keyless. This is not artworks. It is the controlled vocabulary the art world uses to describe artworks, and it is how you turn a free-text mess into linked entities.
# runnable, read-only
curl -s "https://vocab.getty.edu/aat/300189808.json"
{"@context":"https://linked.art/ns/v1/linked-art.json",
"_label":"figures (representations)",
"equivalent":[{"id":"http://www.wikidata.org/entity/Q29527347"}]}
Like Yale, this is JSON-LD, so budget for a heavier shape than the flat-JSON museums. What you get for the trouble is real: an equivalent link straight to Wikidata, a broader chain up the concept tree, stable URIs you can join on. If you ever need to reconcile "who is this artist" or "what is this technique" across two museums that spell things differently, this is the linked-data tier that makes it possible. Endpoint and model: vocab.getty.edu.
9. Harvard LibraryCloud: the Harvard art API that is not the Harvard art API
This one is a naming trap before you even read a field. Harvard runs two things. The Harvard Art Museums API at api.harvardartmuseums.org needs a key. It is not on this list, and I will get to it below. LibraryCloud, at api.lib.harvard.edu, is keyless, and it is a different animal entirely.
# runnable, read-only
curl -s "https://api.lib.harvard.edu/v2/items.json?q=painting&limit=1"
{"pagination":{"numFound":515781,"limit":1,"start":0},
"items":{"mods":{"titleInfo":{"title":"conservation of easel paintings"},
"genre":{"#text":"bibliography"}}}}
515,781 hits for "painting," and the first one is a bibliography, a book about the conservation of easel paintings, encoded in MODS library metadata. If you came here expecting Harvard's artworks, you are in the library catalog, and the two are easy to confuse because both live under a Harvard domain and both answer q=painting with a 200. The keyless one is books-and-metadata. The artworks are behind the key. Docs: Harvard LibraryCloud APIs.
10. Auckland War Memorial Museum: a count that is really a floor
Auckland exposes its collection through a keyless Elasticsearch proxy, so instead of a REST search you POST a query body. Get the index name right (collectionsonline) and it answers.
# runnable, read-only
curl -s -X POST "https://api.aucklandmuseum.com/search/collectionsonline/_search" \
-H "Content-Type: application/json" \
-d '{"size":1,"query":{"match_all":{}}}'
{"hits":{"total":{"value":10000,"relation":"gte"},
"hits":[{"_index":"collectionsonline-2022-05-04-1",
"_source":{"type":"ecrm:E21_Person","appellation":{"name":["KVD?"]}}}]}}
Look at total. It is not a number. It is an object: {"value":10000,"relation":"gte"}. That gte means "greater than or equal to," so value: 10000 is Elasticsearch telling you it stopped counting at ten thousand, and the real total is at least that. Read total.value as a count and you will report exactly 10,000 objects for a collection that has far more. The name value, sitting under total, reads like an answer. It is a floor with a footnote in the next field. And the first hit is a Person record, not an object, because the index mixes entity types. Docs: api.aucklandmuseum.com/apidoc.
The field that lies about the law: isPublicDomain
Now the field I actually opened this post to talk about, because it is the one that can cost you money instead of just a wrong dashboard number.
Here is the Met's own documentation, word for word, from metmuseum.github.io:
isPublicDomain(boolean) When "true" indicates an artwork in the Public Domain
Read that as a developer and you hear a legal claim about the artwork: this painting's copyright has expired, you are free to use it. That is what "in the Public Domain" means as English.
That is not what the field tracks. Watch what happens across a single artist. Van Gogh died in 1890. Every painting he made is uncontroversially out of copyright, everywhere on Earth. I pulled 30 objects the Met attributes to "Vincent van Gogh" and checked the flag on each.
Van Gogh-attributed objects sampled: 30
isPublicDomain = true: 29 (all with an open image)
isPublicDomain = false: 1 (a printed book of his letters, no image)
Twenty-nine true, one false. The false one is a printed edition of his letters that the Met has not released as an open image. So the flag did not flip because someone re-adjudicated Van Gogh's copyright between his paintings and his letters. It flipped because the Met has an open, CC0-licensed photograph of the paintings and does not have one of that book. The field's real subject is the Met's image, not the artwork's copyright.
Object 310453 makes it sharp. It came back in that Rembrandt search from the top of the post.
{"objectID":310453,"title":"Nkishi (community power figure)",
"artistDisplayName":"Songye artist and nganga (ritual specialist)",
"department":"The Michael C. Rockefeller Wing",
"isPublicDomain":false,"primaryImage":""}
isPublicDomain: false. I want to be precise, because this is where developers overclaim in both directions. This does not mean the object is under copyright. A Songye community power figure made in the 19th or early 20th century may well be in the public domain as a matter of law. The false here is not a court ruling. It means the Met has not released an open-access image of it, which the empty primaryImage confirms in the same breath. The field answers "did the museum openly license its photo of this thing?" Its name asks "is this artwork's copyright expired?" Those are different questions, and only one of them has a clean answer in the JSON.
Now line up all three museums on the same real question, which is "may I reuse this image without owing anyone anything?":
- The Met:
isPublicDomain(boolean) - Art Institute of Chicago:
is_public_domain(boolean) - Cleveland:
share_license_status(string, e.g."CC0")
Three field names, one underlying decision, made separately by three rights offices, with no shared canonical answer. If your app treats isPublicDomain: true as "safe to reuse commercially," you are trusting each museum's image-licensing office and calling it copyright law. Usually you are fine. The day you are not, the field name is what talked you into it.
The fix: read the value, not the name
The pattern is the same every time. Do not ask the field what it is called. Ask the object what is actually true. Here is a resolver that does the thing the Met's total, hasImages, and isPublicDomain only pretend to do: it verifies each object actually matches the artist you asked for, and actually carries a usable open image, from the values.
# runnable local: pip install requests
import requests
MET = "https://collectionapi.metmuseum.org/public/collection/v1"
S = requests.Session()
S.headers["User-Agent"] = "field-meaning-demo/1.0 (contact you@example.com)"
def usable_open_image(obj):
"""The question a dev MEANS when reading isPublicDomain and hasImages:
can I show an openly-licensed image of this object right now?
Answer from the values, never from the field names."""
return bool(obj.get("primaryImage")) and obj.get("isPublicDomain") is True
def real_matches(query, want, limit=40):
hits = S.get(f"{MET}/search", params={"q": query, "hasImages": "true"}, timeout=20).json()
reported = hits.get("total", 0) # read the field named "total", not len()
ids = hits.get("objectIDs") or [] # a miss returns null, not []
kept = 0
for oid in ids[:limit]:
o = S.get(f"{MET}/objects/{oid}", timeout=20).json()
artist = o.get("artistDisplayName", "")
if want.lower() in artist.lower() and usable_open_image(o):
kept += 1
return reported, min(limit, len(ids)), kept
reported, sampled, kept = real_matches("Rembrandt", "Rembrandt")
print(f"'total' the API reports: {reported}")
print(f"objects I sampled: {sampled}")
print(f"actually Rembrandt + usable: {kept}")
Real output, July 16, 2026:
'total' the API reports: 182
objects I sampled: 40
actually Rembrandt + usable: 6
Six out of the first forty. The 34 it drops include the Goya from the top of the post, the Egyptian Book of the Dead, a Byzantine reliquary, and object 310453, the one whose hasImages=true filter let it through with an empty primaryImage. Two things about this code, said plainly so you do not oversell it.
It only samples the first 40 IDs, because fetching all 182 objects one at a time is slow and rude to a keyless server. That is a real limitation: the true count of usable Rembrandts is somewhere in the collection, and this tells you the rate in the first page, not the final number. If you need the number, page politely and cache. And the want.lower() in artist.lower() check is deliberately loose. It keeps "Rembrandt (workshop)" and "Rembrandt van Rijn," which may or may not be what you want. The point is not that this exact filter is right for your app. The point is that it reads artistDisplayName and primaryImage, the fields whose values are true, instead of trusting total and hasImages, the fields whose names are convenient.
Flagged: three "free" APIs that still want a key
Every listicle, mine included in spirit, calls these free. They are free. They are not keyless, and the difference is a 401 or 403 the moment you forget the key.
# runnable, read-only
curl -s -o /dev/null -w "%{http_code}\n" "https://api.harvardartmuseums.org/object?size=1"
curl -s -o /dev/null -w "%{http_code}\n" "https://api.si.edu/openaccess/api/v1.0/search?q=painting"
curl -s -o /dev/null -w "%{http_code}\n" "https://api.europeana.eu/record/v2/search.json?query=painting"
401
403
401
The Harvard Art Museums API (401) is the one people confuse with keyless LibraryCloud from number 9. Smithsonian Open Access (403) returns API_KEY_MISSING and hands out a free key at api.data.gov. Europeana (401) aggregates thousands of European institutions and is worth the signup, but a signup it is. Free-as-in-beer, not free-as-in-paste-into-a-terminal.
Why not on the list: two that tutorials still recommend
The Rijksmuseum API, still the top result in a lot of old blog posts, is gone:
curl -s -o /dev/null -w "%{http_code}\n" "https://www.rijksmuseum.nl/api/en/collection"
410
HTTP 410 Gone, which is a server saying "not moved, not temporarily down, deliberately removed." The legacy endpoint was decommissioned; the Rijksmuseum moved to a newer data service. Do not build on the 410. And the Brooklyn Museum API returns a 429 with a "Vercel Security Checkpoint" body from a datacenter IP, a bot challenge rather than a real rate limit, so it is unreliable to depend on from a server even though a browser may sail through. (One I will not badmouth: the Science Museum Group returned a clean 200 for me today, though I have seen reports of it blocking datacenter IPs, so test from your own host before you trust it.)
So what do you actually do?
Two habits, and they are cheap.
Read the field's definition, not its name. Before you branch on isPublicDomain, total, hasImages, or found, open the docs and find out what the museum means by it. Ten minutes with metmuseum.github.io tells you isPublicDomain is tied to the open-access image release. Ten minutes with the V&A docs tells you record_count_exact exists. The good APIs in this post, the V&A with its exactness flag, Yale with its search-estimate route, SMK with its modified stamp, are the ones that put the caveat in a field so you can read it. Reward that by actually reading it.
Verify the object, not the count. A count is a promise about a set you have not looked at. When the answer matters, fetch a sample and check that the objects are what the count says they are, from their own values. Thirty lines of real_matches turned "182 Rembrandts" into "6 of the first 40," and the gap between those two numbers is the gap between a demo and a bug report.
I learned the expensive half of this in a different domain. Across 2,190 production scraper runs, the incidents that actually cost me were never the 500s. A crash wakes you up and you fix it by lunch. The response that comes back 200, valid, non-empty, correctly shaped, and quietly answering a different question than you asked, that one sits in a column until a report looks wrong three weeks later, and then you are backfilling. Museum APIs just make it pretty. Your API is probably doing the same thing with a blander field name. Go read what the name actually means.
FAQ
What is the best free art or museum API with no key?
It depends on the job, and several are keyless together. The Met (collectionapi.metmuseum.org) has the broadest collection and the simplest flat JSON. The Art Institute of Chicago (api.artic.edu) is the cleanest to build on and ships IIIF images. Cleveland (openaccess-api.clevelandart.org) and SMK (api.smk.dk) are CC0-friendly. The V&A (api.vam.ac.uk) covers over a million objects. All returned HTTP 200 with no key on July 16, 2026. Whichever you pick, read what its count and rights fields actually mean before you trust them.
Does the Met Museum API require an API key?
No. The Metropolitan Museum Collection API is fully keyless: no signup, no key, no token. It asks only for polite request pacing and a real User-Agent. Two traps to guard for: a search that matches nothing returns {"total":0,"objectIDs":null} with objectIDs as null rather than an empty array, and a request for a nonexistent object ID returns HTTP 404 with {"message":"ObjectID not found"} rather than an empty body.
What does isPublicDomain mean in the Met API?
The Met documents it as "when true, indicates an artwork in the Public Domain," but in practice the flag tracks whether the Met has released an open-access (CC0) image of the object, not a legal ruling on the artwork's copyright. Evidence: of 30 objects attributed to Van Gogh (died 1890, unquestionably out of copyright), 29 returned isPublicDomain: true and all carried an open image, while the one false was a printed book with no released image. So isPublicDomain: false does not mean the work is copyrighted; it can mean the Met simply has no open image of it, which the empty primaryImage confirms.
Why does a museum search return objects that do not match my query?
Because museum search is full-text over the whole record, not a filter on a subject field. The Met's search?q=Rembrandt&hasImages=true returned total: 182, but the keyword also matched text elsewhere in the catalog record, not the artist field, so a Goya (object 436543) and an Egyptian Book of the Dead (object 551786) are counted among the 182. In a sample of the first 40 objects, only 6 were actually Rembrandt with a usable open image. Verify each object's artistDisplayName rather than trusting the count.
Which museum APIs need an API key?
On July 16, 2026, the Harvard Art Museums API (api.harvardartmuseums.org) returned HTTP 401, the Smithsonian Open Access API (api.si.edu) returned HTTP 403 with API_KEY_MISSING, and Europeana (api.europeana.eu) returned HTTP 401. All three offer a free key on signup, so they are free but not keyless. Note that the keyless Harvard endpoint on this list, LibraryCloud at api.lib.harvard.edu, is a different service (library metadata) from the key-gated Harvard Art Museums.
Can I use museum images commercially for free?
Sometimes, and the field that says so answers a narrower question than its name. Fields like the Met's isPublicDomain, the Art Institute's is_public_domain, and Cleveland's share_license_status describe whether the museum released its image under an open license (often CC0), not whether the underlying artwork's copyright has expired. Also watch for split licensing: the Art Institute's info.license_text states that its description field is CC-BY (attribution required) while the rest of the record is CC0. Check the specific field per museum before reusing anything.
Written by Aleksei Spinov. I build web-scraping and data-enrichment tool layers, currently 2,190 runs across 32 actors in production. Every endpoint above was re-verified with a live curl (real HTTP code, real body) on July 16, 2026 before publishing; responses are trimmed, never reworded. I have not run a museum-collection resolver in production; those runs are a scraping-and-enrichment domain, cited only as the origin of the read-the-value habit. I wrote up neighboring versions of this same pattern for free space and astronomy APIs, free fun-facts APIs, and free mock and fake-data APIs. Drafted with an AI assistant, then fact-checked and edited by me against the raw responses.
Follow for the next keyless layer I verify. And tell me: which field name on your favorite API secretly answers a different question than its name promises? I read every comment.
Top comments (0)