The Proximitii Crime Riskmap API adds a crime risk overlay to an existing web map. It returns one PNG tile per request. Your map library selects the visible tiles as visitors pan and zoom; your server requests each tile with your Proximitii API keys and sends the PNG to the browser. Keep the private key on your server.
Show Crime data: CrimeoMeter in the map attribution, retain your basemap provider's attribution, and place the Powered by Proximitii attribution directly below the map.
Example Calls
Step 1: Serve tiles from your server (Node.js / Express)
Add this route to your existing Express application. Replace requireAuthenticatedUser with access control appropriate for your site. The route belongs on the same origin as your map page.
app.get('/your-backend/crime-riskmap/:z/:x/:y.png', requireAuthenticatedUser, async (req, res) => {
const { z, x, y } = req.params;
const params = new URLSearchParams({ z, x, y });
try {
const response = await fetch(
`https://api.proximitii.com/v1/crime-riskmap/?${params}`,
{
method: 'GET',
headers: {
'Public-Key': process.env.PROXIMITII_PUBLIC_KEY,
'Private-Key': process.env.PROXIMITII_PRIVATE_KEY
}
}
);
res.set('Cache-Control', 'no-store');
if (!response.ok) {
const body = await response.json().catch(() => null);
const retryAfter = response.headers.get('Retry-After');
if (retryAfter) res.set('Retry-After', retryAfter);
return res.status(response.status).json(
body || { status: { code: String(response.status), message: 'Riskmap tile failed' } }
);
}
res.type('png').send(Buffer.from(await response.arrayBuffer()));
} catch (error) {
res.status(502).json({ status: { code: '502', message: 'Riskmap tile request failed' } });
}
});Step 2: Add the overlay to an existing Leaflet map (browser)
Use your backend route from Step 1 as the tile URL. Leaflet fills in {z}, {x}, and {y} for each visible tile.
map.setView([40.7788, -73.9810], 14); // [latitude, longitude]
const crimeOverlay = L.tileLayer('/your-backend/crime-riskmap/{z}/{x}/{y}.png', {
maxZoom: 19,
opacity: 0.82,
attribution: 'Crime data: CrimeoMeter'
}).addTo(map);The browser requests tiles from your backend route. Apply your normal access control and rate limiting there; never put the Proximitii private key in browser code.
Keys
Use your existing active Proximitii public and private API keys. Send Public-Key and Private-Key headers with each server-side tile request. No separate CrimeoMeter key is required. This endpoint does not issue a browser tile session.
Values
For a map overlay, request tiles with z, x, and y:
| Name | Description | Default Value | Accepted Values | Variable |
|---|---|---|---|---|
| Tile endpoint | Returns one PNG tile. | N/A | GET /v1/crime-riskmap/?z={z}&x={x}&y={y} | N/A |
| Zoom | Map zoom level. | Required for tile requests | Integer from 0 to 22 | z |
| Tile column | Horizontal tile coordinate at the selected zoom. | Required | Integer from 0 to 2z - 1 | x |
| Tile row | Vertical tile coordinate at the selected zoom. | Required | Integer from 0 to 2z - 1 | y |
To request only the tile containing one point, send lat and lon instead of x and y:
| Name | Description | Default Value | Accepted Values | Variable |
|---|---|---|---|---|
| Latitude | Point within the requested tile. | Required in point mode | Decimal from -85.05112878 to 85.05112878 | lat |
| Longitude | Point within the requested tile. | Required in point mode | Decimal from -180 to 180 | lon |
| Zoom | Zoom level for the point's tile. | 14 | Integer from 0 to 22 | z |
Example single-point request: GET /v1/crime-riskmap/?lat=40.7788&lon=-73.9810&z=14. This returns one tile, so use z/x/y requests for a full map. Send a complete x/y pair or a complete lat/lon pair. The endpoint also accepts POST with these values in a JSON body.
Sample Output
A successful response contains PNG image bytes, not a JSON document:
HTTP/1.1 200 OK
Content-Type: image/png
X-Cache: MISS
[PNG image bytes]X-Cache is HIT or MISS. Errors return JSON; for example, an invalid coordinate returns:
{
"status": { "code": "400", "message": "Bad Request" }
}Other possible errors include 401 for invalid keys, 403 for an inactive account or unauthorized domain, 429 when the rate limit is reached, and 503 when the service is unavailable. A 429 response includes Retry-After. After authentication, the API also sends X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset.