Skip to main content

Search

Introduction

This tutorial walks you through how to search the Rijksmuseum collection using the Search API.

The documentation page explains the available endpoints, parameters, and technical specifications. This tutorial focuses on something different:

How do you actually use the Search API in a real workflow?

After completing this tutorial, you will understand:

  • when the Search API is the right choice
  • how to make your first request
  • how to interpret JSON responses
  • how pagination works with pageToken
  • how to resolve identifiers into full object records
  • how to build a simple search workflow

When should you use the Search API?

The Search API is designed for querying the collection based on specific characteristics.

Use the Search API when you want to:

  • search for objects by creator, type, material, technique, ...
  • find objects created in a specific period
  • filter objects by title, description, or subject
  • check whether a digital image is available
  • look up an object by its object number

The Search API is not the best choice when you need to:

  • download complete datasets
  • synchronize metadata regularly
  • build a local copy of collection data

In those cases, OAI-PMH may be more appropriate.

How the Search API works

The Search API works differently from OAI-PMH. You do not harvest batches of records. Instead, you send a query and receive a list of matching identifiers.

A typical workflow looks like this:

  1. Build a query → combine one or more search parameters
  2. Send a request → retrieve a page of matching identifiers
  3. Paginate → follow next to retrieve additional pages
  4. Resolve → use the identifiers to retrieve full object records

Think of the Search API as a discovery layer: it tells you what exists, not what it contains. It returns identifiers, which you then resolve separately to retrieve complete records.

Step-by-step tutorial

Step 1 — Make your first request

The API is available at:

https://data.rijksmuseum.nl/search/collection

No API key is required. Requesting this URL without parameters returns the first 100 items of the entire collection. The response is raw JSON, intended for programmatic use — opening it directly in a browser may look overwhelming at first.

A simple search looks like this:

https://data.rijksmuseum.nl/search/collection?type=painting&creator=Rembrandt

This returns paintings associated with Rembrandt. Parameters are partial keyword matches, so Rembrandt also matches Rembrandt van Rijn.

Step 2 — Explore the available parameters

The API supports a range of query parameters. All parameters are optional and can be combined using &. Multiple parameters are treated as AND — for example, type=painting&material=oil+paint returns only objects that are both a painting and made with oil paint.

To search for multiple values within the same parameter, repeat the parameter. For example, material=oil+paint&material=canvas returns objects that contain both oil paint and canvas . This is also treated as AND.

ParameterDescription
creatorCreator name, such as Rembrandt van Rijn
typeObject type, such as painting
materialMaterial, such as canvas
techniqueTechnique, such as etching
titleTitle keyword, such as Night Watch
descriptionKeyword in the object description
creationDateYear or period, such as 1642 or 16??
aboutActorPerson or group depicted in the object
objectNumberObject number, such as SK-C-5
memberOfSetIdSet identifier
imageAvailabletrue or false

Dutch terms are always supported. English terms are supported where translations are available, but coverage is partial — many thesaurus terms do not have an English equivalent. If a query doesn’t return expected results, switch to Dutch terms — coverage is significantly better.

For objectNumber and creationDate, wildcard characters are supported:

  • * matches any number of characters: SK-C-5* matches SK-C-5, SK-C-50, and SK-C-501
  • ? matches exactly one character: 16?? matches 1642 and 1600, but not 167

Step 3 — Interpret the response

The API returns a JSON response based on the Linked Art Search specification:

{
"@context": "https://linked.art/ns/v1/search.json",
"id": "https://data.rijksmuseum.nl/search/collection?type=painting&material=oil+paint",
"type": "OrderedCollectionPage",
"partOf": {
"id": "https://data.rijksmuseum.nl/search/collection?type=painting&material=oil+paint",
"type": "OrderedCollection",
"totalItems": 4819,
"first": {
"id": "https://data.rijksmuseum.nl/search/collection?type=painting&material=oil+paint",
"type": "OrderedCollectionPage"
},
"last": {
"id": "https://data.rijksmuseum.nl/search/collection?type=painting&material=oil+paint&pageToken=eyJ0b2tlbiI6ICJodHRwczovL2lkLnJpamtzbXVzZXVtLm5sLzIwMDkwNTYwIn0",
"type": "OrderedCollectionPage"
}
},
"next": {
"id": "https://data.rijksmuseum.nl/search/collection?type=painting&material=oil+paint&pageToken=eyJ0b2tlbiI6ICJodHRwczovL2lkLnJpamtzbXVzZXVtLm5sLzIwMDEwNzg2MCJ9",
"type": "OrderedCollectionPage"
},
"orderedItems": [
{ "id": "https://id.rijksmuseum.nl/200100988", "type": "HumanMadeObject" },
{ "id": "https://id.rijksmuseum.nl/200104600", "type": "HumanMadeObject" },
{ "id": "https://id.rijksmuseum.nl/200105887", "type": "HumanMadeObject"},
]
}

The orderedItems array contains up to 100 results per page.

The key fields are:

  • id — the full search request URL for the current page of results
  • partOf.totalItems — total number of matching objects
  • partOf.first.id and partOf.last.id — URLs for the first and last pages of results
  • next.id — URL for the next page of results, including the pageToken for pagination
  • orderedItems — list of matching objects, each with a Linked Open Data identifier (id) and type

The identifiers in orderedItems are not full object records. These identifiers must be resolved separately to retrieve full metadata (see Step 5).

Step 4 — Pagination

Each response page contains up to 100 results. If more results are available, a next.id field is included.

To retrieve the next page, request the URL in next.id:

https://data.rijksmuseum.nl/search/collection?type=painting&material=oil+paint&pageToken=eyJ0b2tlbiI6ICJodHRwczovL2lkLnJpamtzbXVzZXVtLm5sLzIwMDEwNzg2MCJ9

Continue following the next.id field until it is no longer present in the response to paginate through results.

Step 5 — Resolve identifiers

The identifiers returned in orderedItems[].id point to full object records. To resolve an identifier, open or request the URI. The response will contain complete metadata such as title, creator, date, and description.

The Search API always returns responses in Linked Art format, but when resolving identifiers you can request different metadata formats by adding ?_profile= followed by the token to the URI. For example, the following URL returns the record in EDM format:

https://data.rijksmuseum.nl/200100988?_profile=edm

The following formats are available:

FormatToken
Dublin Coredc
Europeana Data Modeledm
OAI Dublin Coreoai_dc
Linked Artla
Linked Art (framed)la-framed
EDM (framed)edm-framed

See the Resolving identifiers example in Step 6 for a practical example.

Alternatively, content negotiation can also be performed using HTTP headers. See the Linked Data Resolver documentation for details.

Step 6 — Python examples

Basic example

Before running this script, make sure the required library is installed:

pip install requests

The example below searches for paintings made with oil paint that have a digital image available, and prints their identifiers.

import requests

# Define the search endpoint and parameters
url = "https://data.rijksmuseum.nl/search/collection"
params = {
"imageAvailable": "true",
"type": "painting",
"material": "oil paint"
}

# Fetch and parse the response
response = requests.get(url, params=params)
data = response.json()

# Print the total number of results and the identifiers
print(f"Total results: {data['partOf']['totalItems']}")
print()

for item in data['orderedItems']:
print(item['id'])

This will produce output like:

Total results: 4432

https://id.rijksmuseum.nl/200100988
https://id.rijksmuseum.nl/200105887
// ... more results ...

Retrieving all results

To retrieve all results across multiple pages, follow the next field until it is no longer present.

The example below retrieves all results across multiple pages, printing the number of items per page and the total number of items at the end.

import requests

# Define the search endpoint and parameters
url = "https://data.rijksmuseum.nl/search/collection"
params = {
"imageAvailable": "true",
"type": "painting",
"material": "oil paint"
}

all_items = []
page = 1

# Continue fetching until no next page is returned
while url:
response = requests.get(url, params=params)
data = response.json()

# Add the results to the list and print the page number
all_items.extend(data['orderedItems'])
print(f"Page {page}: {len(data['orderedItems'])} items")
page += 1

# Get the next page URL if available
next_page = data.get('next')
url = next_page['id'] if next_page else None
params = {} # Clear params: next URL already includes pageToken

print(f"\nRetrieved {len(all_items)} items in total")

This will produce output like:

Page 1: 100 items
Page 2: 100 items
...
Page 44: 100 items
Page 45: 32 items

Retrieved 4432 items in total

Resolving identifiers

Once you have a list of identifiers, you can resolve each one to retrieve full object metadata. The example below uses the la-framed profile to retrieve records in Linked Art format, and prints the full record for the first 5 results.

import requests

# Resolve a single identifier by requesting its URI with a profile parameter
def resolve_identifier(uri, profile="la-framed"):
response = requests.get(f"{uri}?_profile={profile}")
return response.json()

# Define the search endpoint and parameters
url = "https://data.rijksmuseum.nl/search/collection"
params = {
"imageAvailable": "true",
"type": "painting",
"material": "oil paint"
}

# Fetch the first page of results
response = requests.get(url, params=params)
data = response.json()

# Resolve the first 5 identifiers and print the result
for item in data['orderedItems'][:5]:
record = resolve_identifier(item['id'])
print(record)

This prints the full Linked Art record for each identifier. In the next step, we extract specific fields from this response.

Note: each identifier requires a separate request. For large result sets, this can significantly impact performance.

Extracting fields from the response

Rather than printing the full record, this example extracts specific fields — object number, title, creator, and identifier — and prints them in a readable format for the first 5 results.

import requests

def resolve_identifier(uri, profile="la-framed"):
response = requests.get(f"{uri}?_profile={profile}")
return response.json()

def extract_fields(record):
# Extract object number
object_number = None
for item in record.get('identified_by', []):
if item.get('type') == 'Identifier':
for classification in item.get('classified_as', []):
if classification.get('id') == 'https://id.rijksmuseum.nl/22015218':
object_number = item.get('content')
break

# Extract title
title = None
for item in record.get('identified_by', []):
if item.get('type') == 'Name':
for classification in item.get('classified_as', []):
if classification.get('id') == 'http://vocab.getty.edu/aat/300417200':
title = item.get('content')
break

# Extract creator name
creator = None
for part in record.get('produced_by', {}).get('part', []):
for actor in part.get('carried_out_by', []):
for notation in actor.get('notation', []):
if notation.get('@language') == 'en':
creator = notation.get('@value')
break

return object_number, title, creator

# Define the search endpoint and parameters
url = "https://data.rijksmuseum.nl/search/collection"
params = {
"imageAvailable": "true",
"type": "painting",
"material": "oil paint"
}

# Fetch the first page of results
response = requests.get(url, params=params)
data = response.json()

# Resolve the first 5 identifiers and extract key fields
for item in data['orderedItems'][:5]:
record = resolve_identifier(item['id'])
object_number, title, creator = extract_fields(record)

print(f"{object_number}")
print(f" Title: {title}")
print(f" Creator: {creator}")
print(f" Identifier: {item['id']}")
print()

This will produce output like:

SK-C-1535
Title: The Raampoortje in Amsterdam
Creator: Wouter Johannes van Troostwijk
Identifier: https://id.rijksmuseum.nl/200106078

SK-A-1453
Title: Willem Bilderdijk (1756-1831), dichter en geschiedschrijver
Creator: Charles Howard Hodges
Identifier: https://id.rijksmuseum.nl/200106079

// ... more results ...

Common pitfalls

  • Parameters are combined using AND, not OR
  • English terms are not always supported — Dutch terms have better coverage
  • The orderedItems field contains identifiers, not full object data
  • Retrieving many records requires resolving each identifier separately (N+1 requests), which can significantly impact performance
  • Pagination must be handled using the next field — there is no page number parameter

Summary

In this tutorial, you learned how to query the Rijksmuseum collection using the Search API. You explored the available parameters, how to interpret JSON responses, and how pagination works using pageToken.

You also learned how to retrieve all results programmatically, how to resolve Linked Open Data identifiers into full object records using the la-framed profile, and how to extract specific fields from the Linked Art response.