BerkeleyMapper exposes a small same-origin HTTP API used by the browser app. These endpoints can also be called directly from external clients if the deployment allows it.
Yes. You can call /api/spatial-statistics directly without loading the BerkeleyMapper UI first.
The endpoint is stateless. You send grouped point coordinates, BerkeleyMapper runs the polygon intersections on the server, and you poll for the completed result.
your script or app
-> POST /api/spatial-statistics with grouped points
-> 202 Accepted with requestId
-> GET /api/spatial-statistics?id=...
-> complete result with country/state/county counts
You do not need to send a BerkeleyMapper dataset payload or full record rows. For direct use, the important request body is just a points array containing latitude, longitude, and count.
Production:
https://berkeleymapper.berkeley.edu
Local development with the Node server:
http://127.0.0.1:4173
Notes:
- All endpoint paths below are relative to that base URL.
- Direct API use does not require calling the BerkeleyMapper UI first.
/api/spatial-statisticsis stateless. You can call it directly as long as the server has access to GADM boundary data.
GET /api/datasetGET /api/layerGET /api/gadm41POST /api/spatial-statisticsGET /api/spatial-statistics?id=...
Loads a remote tabular data file and optional BerkeleyMapper XML config file, then returns the parsed dataset payload as JSON.
tabfilerequired unlessconfigfileis provided. Use an absolute HTTP(S) URL or a same-origin path. Despite the name,tabfilemay point to either tab-delimited text or CSV.configfileoptional. Use an absolute HTTP(S) URL or a same-origin path to a BerkeleyMapper XML config file.
curl -i "https://berkeleymapper.berkeley.edu/api/dataset?tabfile=https://raw.githubusercontent.com/BNHM/berkeleymapper/master/examples/arctostest.txt&configfile=https://raw.githubusercontent.com/BNHM/berkeleymapper/master/examples/arctostest.xml"Returns parsed dataset JSON including:
sourcemetadatacolumnsrecordsmarkerssummaryrawConfigTextrawTabPreviewText
- Supports
GETandHEAD - Parses TSV and CSV, including quoted CSV fields
- Rejects non-HTTP(S) source URLs
- Returns
400for missing parameters - Returns
502if upstream data cannot be loaded
Fetches a remote GIS layer source and returns it with a usable content type.
urlrequired. Use an absolute HTTP(S) URL or same-origin path to a.kml,.kmz,.geojson, or.jsonresource.
curl -i "https://berkeleymapper.berkeley.edu/api/layer?url=https://raw.githubusercontent.com/BNHM/berkeleymapper/master/examples/Anaxyrus_canorus.kmz"- Supports
GETandHEAD - Infers content type for KML, KMZ, GeoJSON, JSON, and XML sources
- Rejects non-HTTP(S) source URLs
- Returns
400for missing parameters - Returns
502if the upstream layer cannot be loaded
Returns filtered GADM boundary GeoJSON used by polygon joins and spatial statistics.
levelrequired. One of0,1, or2countryoptional. Required for most level1and2requests unlesscountriesis suppliedcountriesoptional. Comma-separated country namesstatesoptional. Comma-separated state or province names
All countries:
curl -i "https://berkeleymapper.berkeley.edu/api/gadm41?level=0"Counties for one country:
curl -i "https://berkeleymapper.berkeley.edu/api/gadm41?level=2&country=United%20States"- Supports
GETandHEAD - Returns GeoJSON
- Requires
GADM41_DIRto be configured on the server - Returns
502if the server cannot read or build the requested boundary data
Queues a spatial-intersection job for grouped record points. This endpoint can be called directly without loading BerkeleyMapper first.
This is the most useful endpoint to call directly if you already have point coordinates and want BerkeleyMapper’s country, state, and county intersection counts.
Yes, you can call this endpoint directly from a script, client, or another application.
You do not need to:
- load a BerkeleyMapper page first
- create a BerkeleyMapper dataset payload
- send full records
You only need to send grouped points in this form:
latitudelongitudecount
Grouping repeated coordinates client-side is recommended because it keeps the request body much smaller.
Content-Type: application/json
Body:
{
"points": [
{ "latitude": 37.85, "longitude": -122.27, "count": 1 },
{ "latitude": 37.86, "longitude": -122.28, "count": 2 }
]
}Notes:
countmeans how many records are represented by that coordinate pair- BerkeleyMapper’s own browser client sends grouped points, not full record rows
- The server also has compatibility support for plain-text CSV request bodies and gzip-compressed request bodies, but plain JSON is the simplest and safest direct-call format
- On
berkeleymapper.berkeley.edu, plain JSON is the recommended format because Apache/ModSecurity may reject compressed request bodies
BASE_URL="https://berkeleymapper.berkeley.edu"
POST_BODY='{"points":[{"latitude":37.85,"longitude":-122.27,"count":1},{"latitude":37.86,"longitude":-122.28,"count":2}]}'
submit_response="$(curl -s "$BASE_URL/api/spatial-statistics" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
--data "$POST_BODY")"
request_id="$(printf '%s' "$submit_response" | python3 -c 'import json,sys; print(json.load(sys.stdin)["requestId"])')"
echo "requestId=$request_id"
while true; do
status_response="$(curl -s "$BASE_URL/api/spatial-statistics?id=$request_id" \
-H 'Accept: application/json')"
status="$(printf '%s' "$status_response" | python3 -c 'import json,sys; print(json.load(sys.stdin)["status"])')"
echo "status=$status"
if [ "$status" = "complete" ] || [ "$status" = "error" ]; then
printf '%s\n' "$status_response" | python3 -m json.tool
break
fi
sleep 1
doneWhat it does:
- submits grouped points to
POST /api/spatial-statistics - extracts the returned
requestId - polls
GET /api/spatial-statistics?id=... - prints the final JSON response when the job finishes
Initial POST response example:
{
"requestId": "movhfusa-b03dfr",
"status": "pending",
"lines": [
"request received groupedPoints=2",
"start rawPoints=2 groupedPoints=2"
]
}- Returns
202 Accepted - Returns a
requestId - Work continues asynchronously
- Requires the Node server and GADM data at runtime
- Uses level
0,1, and2GADM boundaries behind the scenes - Returns
502if spatial data is unavailable or the request body cannot be parsed
Polls the status of a queued spatial-statistics job.
idrequired. TherequestIdreturned byPOST /api/spatial-statistics
curl -i "https://berkeleymapper.berkeley.edu/api/spatial-statistics?id=movhfusa-b03dfr"Completed response example:
{
"requestId": "movhfusa-b03dfr",
"status": "complete",
"lines": [
"request received groupedPoints=2",
"start rawPoints=2 groupedPoints=2",
"response ready countryRows=1 stateRows=1 countyRows=1"
],
"error": "",
"result": {
"country": [
{
"value": "United States",
"count": 3,
"recordIds": [],
"groupIndexes": [0, 1]
}
],
"state": [
{
"value": "California, United States",
"count": 3,
"recordIds": [],
"groupIndexes": [0, 1]
}
],
"county": [
{
"value": "Alameda, California, United States",
"count": 3,
"recordIds": [],
"groupIndexes": [0, 1]
}
]
}
}country,state, andcountyare separate aggregated result setscountis the sum of all grouped-point counts that intersected that boundarygroupIndexesidentify which submitted point groups contributed to the rowrecordIdsmay be empty for direct callers because direct callers typically submit only grouped counts, not BerkeleyMapper-internal record identifiers
If you want to call the spatial-statistics API directly from your own code:
- Group repeated coordinates client-side.
- Build a
pointsarray withlatitude,longitude, andcount. POSTthat JSON to/api/spatial-statistics.- Read the returned
requestId. - Poll
/api/spatial-statistics?id=...untilstatusiscompleteorerror.
Minimal pseudo-flow:
POST /api/spatial-statistics
-> 202 requestId=abc123
GET /api/spatial-statistics?id=abc123
-> pending
GET /api/spatial-statistics?id=abc123
-> complete with country/state/county rows
These endpoints require the production Node server described in the main README. Serving only the built dist/ frontend without forwarding /api/* to the Node server will not work.