DigitalSF APIdigitalsf.org ↗
Search and retrieve catalogue metadata from the San Francisco Public Library's DigitalSF digital collections, including titles, dates, creators, and image URLs.
What is the DigitalSF API?
The DigitalSF API provides 2 endpoints for searching and retrieving public catalogue records from the San Francisco Public Library's DigitalSF digital collections. Use search_photos to query by street address, street name, or any keyword and receive paginated results with stable item IDs, titles, photographer attributions, and image URLs. Use get_photo to fetch the full record for any individual item, including verbatim notes, genre terms, series data, and preferred citation text.
curl -X GET 'https://api.parse.bot/scraper/5ac4f6ed-b7af-43b3-80a2-9ae093bd877c/search_photos?page=2&limit=3&query=Cortland+Avenue&still_images_only=true' \ -H 'X-API-Key: $PARSE_API_KEY'
Searches the DigitalSF catalogue with a free-text query (a street address such as '439 Cortland Avenue', a street name such as 'Goettingen Street', or any keyword; wrap the query in double quotes for an exact phrase) and returns one page of catalogue records in the site's default relevance/date order. Each item is one catalogue record with its stable item_id, item_url (pass unchanged to get_photo), title, verbatim notes and address/parcel note when catalogued, catalogued creation and capture date text with a stated meaning and a format-derived precision (null when not catalogued), creators/photographers, dimensions (null when not given), rights statement/label/URL, a public thumbnail URL and the public image file URLs listed by the site. heading and location are always null: the catalogue does not publish camera heading or coordinates. A search hit only means the record text matched the query; it is not a claim that the photograph depicts the requested building. Rights URL: the catalogue's metadata export carries the rights label but not the link; the site's public item page renders that label as a rightsstatements.org link. search_photos reads that link from one item page per distinct rights label on the returned page (at most 4 extra round trips) and applies it to every item on the page carrying the identical label; rights_url_source is then 'site_item_page_same_label'. If the item page gives no link, or more than 4 distinct labels occur on one page, rights_url stays null with rights_url_source null — a null never implies permission; call get_photo for the item's own page link. Pagination: page (1-based) and limit (1-100, clamped) drive a true offset over the site's result stream; total_count is the site's own reported record count (null only if the site omits it); has_more/next_page say whether a further page exists. An empty items array with total_count 0 means the site found no records for the query (a valid empty result); site outages or challenges surface as non-success envelopes instead. Two site round trips per call plus one per distinct rights label.
| Param | Type | Description |
|---|---|---|
| page | integer | 1-based result page over the site's result stream. |
| limit | integer | Records per page; values above 100 are clamped to 100. |
| queryrequired | string | Free-text search string, e.g. a street address or street name. Double-quote it for an exact phrase match. |
| still_images_only | boolean | When true, applies the site's own 'Type: Still image' facet so text records (newspapers, documents) are excluded. The facet is the site's; its counts can differ from the content_type field on individual records. |
{
"type": "object",
"fields": {
"page": "integer page requested",
"items": "array of catalogue records; each has item_id (stable string record id), local_identifier (library accession number or null), item_url (public item page URL, input to get_photo), title, alternative_titles (array), description (string or null), notes (array of verbatim catalogue notes), address_or_parcel_verbatim (verbatim address/parcel note or null), date_created_text/date_created_meaning/date_created_precision (verbatim catalogued creation date, its meaning, and precision one of day|month|year|range|approximate_or_text; all null when unknown), date_captured_text/date_captured_meaning/date_captured_precision (same for a catalogued capture date; null when not catalogued), date_sort_year (string or null), creators (array of {name, role, dates}), photographers (array of creator names whose role is photographer), physical_description, dimensions (string or null), content_type, subjects/place_subjects/genres (arrays), collection, series, call_number, citation, rights_statement, rights_label, rights_url (rightsstatements.org link as rendered on the site's item page for this label, or null when the site shows none), rights_url_source ('catalogue_record' when the metadata export itself carried the link, 'site_item_page_same_label' when read from a DigitalSF item page bearing the identical rights label, null when rights_url is null), heading (always null), location (always null), thumbnail_url, image_urls (array of {url, size_bytes}), external_links (array of {url, label})",
"limit": "integer page size applied after clamping",
"query": "the search string as sent",
"has_more": "boolean, whether another page exists",
"next_page": "integer next page number, or null when has_more is false",
"total_count": "integer total records the site reports for the query, or null if the site did not report one",
"still_images_only": "boolean, whether the still-image facet was applied"
},
"sample": {
"data": {
"page": 1,
"items": [
{
"notes": [
"Address. Box 1, Cortland Avenue, 439."
],
"title": "439 Cortland Avenue, Arrow Pharmacy",
"genres": [
"Photographs"
],
"series": "San Francisco Historical Photograph Collection",
"heading": null,
"item_id": "54740",
"citation": "[Identification of item], San Francisco Office of Assessor-Recorder Photographs (SFP 23), San Francisco History Center, San Francisco Public Library.",
"creators": [],
"item_url": "https://digitalsf.org/record/54740",
"location": null,
"subjects": [
"Streets--Cortland Avenue."
],
"collection": "San Francisco Office of Assessor-Recorder Photographs",
"dimensions": "4 x 5 in.",
"image_urls": [
{
"url": "https://digitalsf.org/record/54740/files/AAM-1192.tiff",
"size_bytes": 18093224
}
],
"rights_url": "https://rightsstatements.org/page/NoC-US/1.0/",
"call_number": "SFP 23",
"description": null,
"content_type": "Still image",
"rights_label": "No Copyright – United States",
"photographers": [],
"thumbnail_url": "https://digitalsf.org/nanna/thumbnail/v2/54740?redirect=1",
"date_sort_year": "1951",
"external_links": [],
"place_subjects": [
"San Francisco (Calif.)"
],
"local_identifier": "AAM-1192",
"rights_statement": "No copyright restrictions under U.S. law.",
"date_created_text": "1951-05-08",
"rights_url_source": "site_item_page_same_label",
"alternative_titles": [
"Cortland Avenue"
],
"date_captured_text": null,
"date_created_meaning": "date of creation/publication as catalogued (MARC 260/264 $c), verbatim",
"physical_description": "1 negative : b&w",
"date_captured_meaning": null,
"date_created_precision": "day",
"date_captured_precision": null,
"address_or_parcel_verbatim": "Address. Box 1, Cortland Avenue, 439."
},
{
"notes": [
"Folder: S.F. Streets-Cortland.",
"Negative #4187"
],
"title": "Cortland between Anderson and Ellsworth street",
"genres": [
"Photographs"
],
"series": "San Francisco Historical Photograph Collection",
"heading": null,
"item_id": "52268",
"citation": "[Identification of item], San Francisco Subjects Photograph Collection (SFP 162), San Francisco History Center, San Francisco Public Library.",
"creators": [],
"item_url": "https://digitalsf.org/record/52268",
"location": null,
"subjects": [
"Streets--Cortland Avenue."
],
"collection": "San Francisco Subjects Photograph Collection",
"dimensions": null,
"image_urls": [
{
"url": "https://digitalsf.org/record/52268/files/AAB-3366.tiff",
"size_bytes": 19686112
}
],
"rights_url": "https://rightsstatements.org/page/NoC-US/1.0/",
"call_number": "SFP 162",
"description": null,
"content_type": "Still image",
"rights_label": "No Copyright – United States",
"photographers": [],
"thumbnail_url": "https://digitalsf.org/nanna/thumbnail/v2/52268?redirect=1",
"date_sort_year": "1926",
"external_links": [
{
"url": "https://oac.cdlib.org/findaid/ark:/13030/c8xg9zwc",
"label": "Link to finding aid"
}
],
"place_subjects": [
"San Francisco (Calif.)"
],
"local_identifier": "AAB-3366",
"rights_statement": "No copyright restrictions under U.S. law.",
"date_created_text": "1926",
"rights_url_source": "site_item_page_same_label",
"alternative_titles": [],
"date_captured_text": null,
"date_created_meaning": "date of creation/publication as catalogued (MARC 260/264 $c), verbatim",
"physical_description": "1 photographic print : b&w",
"date_captured_meaning": null,
"date_created_precision": "year",
"date_captured_precision": null,
"address_or_parcel_verbatim": null
}
],
"limit": 2,
"query": "439 Cortland Avenue",
"has_more": true,
"next_page": 2,
"total_count": 38,
"still_images_only": false
},
"status": "success"
}
}About the DigitalSF API
Endpoints and What They Return
The search_photos endpoint accepts a required query string — a street address like 439 Cortland Avenue, a street name, or any keyword — and returns a page of catalogue records. Each record includes a stable item_id, a local_identifier (library accession number when available), verbatim title, and public item_url and image/thumbnail URLs. A total_count field indicates how many records the catalogue reports for the query, and has_more plus next_page support pagination through result sets. The optional still_images_only boolean applies the catalogue's own 'Type: Still image' facet to exclude documents and newspapers from results.
Filtering and Pagination
Pagination is controlled by page (1-based) and limit (capped at 100 records per request). Wrapping the query value in double quotes requests an exact phrase match from the catalogue's own search index. This is useful when a street name appears as a substring of many unrelated records. The still_images_only filter is particularly useful for photography research workflows where document-type records would add noise.
Full Record Lookup
get_photo accepts the item_url from any search_photos result — a URL of the form https://digitalsf.org/record/<id> — and returns the complete catalogue record. Beyond the search-result fields, this payload includes an array of verbatim notes, genres, series title, citation text, and a creators array with name, role, and dates for each attributed photographer or creator. The location and heading fields are present in the schema but not published by the source; both return null.
The DigitalSF API is a managed, monitored endpoint for digitalsf.org — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when digitalsf.org 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 digitalsf.org 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?+
- Map historical San Francisco street addresses to archival photographs using the
queryparameter ofsearch_photos. - Build a photographer attribution index by aggregating the
creatorsarray (name, role, dates) across multipleget_photoresults. - Enumerate all digitised items in a named series by searching for the series title and checking the
seriesfield in each full record. - Compile preferred citation strings for academic use via the
citationfield returned byget_photo. - Filter catalogue results to still images only (setting
still_images_onlyto true) before embedding public thumbnail URLs in a web application. - Track accession numbers across a digitisation project by collecting
local_identifiervalues fromsearch_photosresults. - Generate a rights-reviewed image list by coupling the
item_urlwith verbatimnotesthat contain rights statements.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 200 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
| Team | $300/mo | 20,000 | 300 req/min |
| Company | $1,000/mo | 100,000 | 500 req/min |
Each endpoint has a fixed posted price per successful call — most fall between 1 and 10 credits — shown on this API's page before you run it. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does DigitalSF have an official developer API?+
What does get_photo return beyond what search_photos already includes?+
get_photo returns the full catalogue record: a notes array of verbatim catalogue notes (which often contain address or rights information), a genres array, a series title, a citation string, and a creators array with name, role, and dates for each attributed creator. The search result includes the item's title, item_id, and URLs but does not include these deeper fields.Are there fields that are always null in responses?+
location field (structured geographic coordinates or place name) and heading field (subject heading) are present in the response schema for both endpoints but consistently return null because the source catalogue does not publish that data in a retrievable form. Rights and address information, when available, appears inside the notes array as verbatim text rather than in a dedicated structured field.Does the API support browsing by collection, subject heading, or date range?+
How large can a single page of search results be, and is there a total result count?+
limit parameter controls page size and is clamped to a maximum of 100 records per request. The total_count field in the response reports the total number of matching records the catalogue returns for the query, though it may be null if the catalogue does not report one. Use has_more and next_page to walk through all pages.