David Rumsey APIdavidrumsey.com ↗
Search and retrieve metadata from the David Rumsey Map Collection. Access IIIF URLs, georeferencing status, image dimensions, and map details via 2 endpoints.
What is the David Rumsey API?
The David Rumsey Historical Map Collection API provides access to one of the largest digitized historical map archives through 2 endpoints. Use search_maps to query the collection by keyword and retrieve paginated results including IIIF image service URLs, full-resolution image URLs, and georeferencing status. Use get_map_details to pull comprehensive metadata for a specific map by its unique item ID, including publisher, scale, physical dimensions, and IIIF manifest URL.
curl -X GET 'https://api.parse.bot/scraper/e62c82ea-9333-413b-9115-6db7e68e5acf/search_maps' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace davidrumsey-com-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""
David Rumsey Map Collection API Client
Search and retrieve detailed metadata from the David Rumsey Historical Map Collection.
Get your API key from: https://parse.bot/settings
"""
import os
import requests
from typing import Optional
class ParseClient:
"""Client for David Rumsey Map Collection API"""
def __init__(self, api_key: Optional[str] = None):
"""Initialize the Parse API client"""
self.base_url = "https://api.parse.bot"
self.scraper_id = "e62c82ea-9333-413b-9115-6db7e68e5acf"
self.api_key = api_key or os.getenv("PARSE_API_KEY")
if not self.api_key:
raise ValueError("API key must be provided or set in PARSE_API_KEY environment variable")
def _call(self, endpoint: str, method: str = "POST", **params) -> dict:
"""Make an API call to the Parse endpoint"""
url = f"{self.base_url}/scraper/{self.scraper_id}/{endpoint}"
headers = {
"X-API-Key": self.api_key,
"Content-Type": "application/json"
}
if method == "GET":
response = requests.get(url, headers=headers, params=params)
elif method == "POST":
response = requests.post(url, headers=headers, json=params)
else:
raise ValueError(f"Unsupported HTTP method: {method}")
response.raise_for_status()
return response.json()
def search_maps(
self,
keyword: str = "San Francisco",
page: int = 1,
page_size: int = 20
) -> dict:
"""
Search the David Rumsey Historical Map Collection by keyword.
Args:
keyword: Search keyword to query the map collection
page: Page number for pagination (starts at 1)
page_size: Number of results per page (1-100)
Returns:
Dictionary containing total_results, page, page_size, and results array
"""
return self._call(
"search_maps",
method="GET",
keyword=keyword,
page=page,
page_size=page_size
)
def get_map_details(self, item_id: str) -> dict:
"""
Get detailed metadata for a specific map item by its unique ID.
Args:
item_id: Unique item identifier in format RUMSEY~8~1~XXXXXX~XXXXXXXX
Returns:
Dictionary containing comprehensive map metadata including IIIF URLs
"""
return self._call("get_map_details", method="GET", item_id=item_id)
def main():
"""Practical workflow example: search for maps and get details on georeferenced ones"""
client = ParseClient()
print("=" * 60)
print("David Rumsey Map Collection - Search and Details Example")
print("=" * 60)
# Step 1: Search for maps about California
print("\n1. Searching for maps about 'California Gold Rush'...")
search_results = client.search_maps(
keyword="California Gold Rush",
page=1,
page_size=5
)
print(f" Found {search_results['total_results']} total maps")
print(f" Showing {len(search_results['results'])} results on page {search_results['page']}\n")
# Step 2: Process each search result
georeferenced_count = 0
maps_to_examine = []
for idx, map_item in enumerate(search_results['results'], 1):
print(f"\n Result {idx}: {map_item['title']}")
print(f" - Date: {map_item['date']}")
print(f" - Author: {map_item['author']}")
print(f" - Type: {map_item['type']}")
print(f" - Image Size: {map_item['image_width']}x{map_item['image_height']}")
print(f" - Georeferenced: {map_item['georeferenced']}")
if map_item['georeferenced']:
georeferenced_count += 1
maps_to_examine.append(map_item['item_id'])
print(f"\n2. Found {georeferenced_count} georeferenced maps from search results")
# Step 3: Get detailed information for georeferenced maps
if maps_to_examine:
print("\n3. Fetching detailed information for georeferenced maps...\n")
for item_id in maps_to_examine[:3]: # Limit to first 3 for demo
print(f" Fetching details for: {item_id}")
details = client.get_map_details(item_id)
print(f" Full Title: {details['full_title']}")
if details.get('obj_width_cm') and details.get('obj_height_cm'):
print(f" Physical Size: {details['obj_width_cm']}cm × {details['obj_height_cm']}cm")
if details.get('scale'):
print(f" Scale: {details['scale']}")
print(f" IIIF Manifest: {details['iiif_manifest_url']}")
print(f" Full Resolution: {details['full_resolution_image_url']}")
print(f" Status: {details['georeferencer_status']}")
print()
print("=" * 60)
print("Example workflow completed successfully!")
print("=" * 60)
if __name__ == "__main__":
main()Search the David Rumsey Historical Map Collection by keyword. Returns paginated results with metadata including title, date, author, item ID, IIIF image service URL, full-resolution image URL, download URL, image dimensions, and georeferencing status for each map.
| Param | Type | Description |
|---|---|---|
| page | integer | Page number for pagination (starts at 1). |
| keyword | string | Search keyword to query the map collection. |
| page_size | integer | Number of results per page (1-100). |
{
"type": "object",
"fields": {
"page": "integer",
"results": "array of map result objects",
"page_size": "integer",
"total_results": "integer"
},
"sample": {
"page": 1,
"results": [
{
"date": "1876",
"type": "Atlas Map",
"title": "New railroad map of the United States and Dominion of Canada.",
"author": "Andreas, A. T. (Alfred Theodore), 1839-1900; Baskin, Forster and Company",
"item_id": "RUMSEY~8~1~22982~790006",
"list_no": "0019.006",
"image_width": 11043,
"download_url": "https://www.davidrumsey.com/rumsey/download.pl?image=/D0079/0019006.sid",
"image_height": 6624,
"georeferenced": true,
"iiif_manifest_url": "https://www.davidrumsey.com/luna/servlet/iiif/m/RUMSEY~8~1~22982~790006/manifest",
"georeferencer_status": "georeferenced",
"iiif_image_service_url": "https://www.davidrumsey.com/luna/servlet/iiif/RUMSEY~8~1~22982~790006",
"full_resolution_image_url": "https://www.davidrumsey.com/luna/servlet/iiif/RUMSEY~8~1~22982~790006/full/full/0/default.jpg"
}
],
"page_size": 3,
"total_results": 7413
}
}About the David Rumsey API
Searching the Collection
The search_maps endpoint accepts a keyword string and returns paginated results controlled by page and page_size (1–100 items per page). Each result object includes the map's title, author, date, item_id, iiif_image_service_url, full_resolution_image_url, download_url, image dimensions, and georeferencing status. The item_id follows the format RUMSEY~8~1~XXXXXX~XXXXXXXX and serves as the key to fetch deeper metadata.
Retrieving Map Details
The get_map_details endpoint takes a required item_id and returns a richer metadata record. Fields include title, author, date, publisher, scale, type, list_no, image_no, note, image dimensions, iiif_image_service_url, iiif_manifest_url, full_resolution_image_url, download_url, and georeferencing data. The IIIF manifest URL is particularly useful for integrating the map into viewers like OpenSeadragon or Universal Viewer.
IIIF and Georeferencing
Every map result exposes a iiif_image_service_url, enabling tile-based rendering at arbitrary zoom levels through any IIIF-compliant image viewer. The get_map_details response additionally provides a iiif_manifest_url for full presentation metadata. Georeferencing status indicates whether a map has been spatially registered, which is relevant for overlaying historical maps onto modern basemaps in GIS applications.
Coverage and Scope
The collection spans several centuries of cartographic history with global geographic coverage. Keyword search surfaces maps by place name, cartographer, date, or subject. Pagination via page and total_results lets you iterate the full result set for a given query. Physical dimension fields (scale, image width/height) support research workflows that need to reason about map resolution or reproduction quality.
The David Rumsey API is a managed, monitored endpoint for davidrumsey.com — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when davidrumsey.com changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official davidrumsey.com API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Overlay georeferenced historical maps onto modern web maps using the IIIF image service URL for tile rendering
- Build a research tool that surfaces David Rumsey maps by place name keyword and displays full-resolution images
- Filter maps by georeferencing status to identify candidates for spatial analysis in a GIS pipeline
- Populate a digital humanities database with structured map metadata including author, date, publisher, and scale
- Integrate IIIF manifest URLs into deep-zoom viewers like Universal Viewer or Mirador for scholarly annotation
- Compare physical and digital image dimensions across maps to assess scan resolution for reproduction projects
- Enumerate a cartographer's full output by searching their name and paginating through all matching results
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does David Rumsey provide an official developer API?+
What does the `get_map_details` endpoint return beyond what `search_maps` provides?+
get_map_details adds fields not present in search results: publisher, scale, type, list_no, image_no, note, and a iiif_manifest_url. The manifest URL is absent from search_maps results, making get_map_details the right call when you need to feed a IIIF-compliant viewer or need bibliographic detail beyond title, author, and date.Can I retrieve a list of all maps in the collection without a keyword?+
search_maps endpoint accepts an optional keyword parameter, so you can call it without a keyword to browse the collection. Pagination is controlled via page and page_size, and total_results tells you the full set size. Iterating all results without a keyword will surface the entire indexed collection across pages.Does the API expose collection-level browse categories, curator notes, or user annotations?+
note field of get_map_details, but collection folders, curator-defined categories, and any user annotation layers are not exposed. You can fork this API on Parse and revise it to add an endpoint targeting those browse structures.Is there a known limitation on how many results a single search query can return?+
page_size is capped at 100 per request. For queries with large result sets, you need to paginate using the page parameter and total_results to determine how many pages exist. There is no single-call method to retrieve more than 100 maps at once.