Step by step
1. Get a key and the tile template
Create a key (see docs), then call `get_tile_endpoints` (free) over MCP, REST or GraphQL. Each layer comes back with a `urlTemplate`, `layerName` (the `source-layer`), `minZoom` and `maxZoom`.
2. Add the source and layers
map.on('load', () => {
map.addSource('parcels', {
type: 'vector',
// Your server proxies /tiles/parcels/{z}/{x}/{y} to Parceled with the key.
tiles: ['https://your-app.example.com/tiles/parcels/{z}/{x}/{y}'],
minzoom: 0,
maxzoom: 14,
})
map.addLayer({
id: 'parcel-fill',
type: 'fill',
source: 'parcels',
'source-layer': 'parcels_a',
paint: { 'fill-color': '#dc4a5a', 'fill-opacity': 0.08 },
})
map.addLayer({
id: 'parcel-lines',
type: 'line',
source: 'parcels',
'source-layer': 'parcels_a',
paint: { 'line-color': '#dc4a5a', 'line-width': 0.8 },
})
})3. Proxy tiles to protect your key
// Next.js route: app/tiles/parcels/[z]/[x]/[y]/route.ts
export async function GET(_req: Request, { params }) {
const { z, x, y } = await params
const upstream = `https://www.parceled.ai/api/parceled/tiles/${process.env.PARCELED_LAYER_ID}/${z}/${x}/${y}?key=${process.env.PARCELED_KEY}`
const res = await fetch(upstream)
return new Response(res.body, {
status: res.status,
headers: { 'Content-Type': 'application/x-protobuf', 'Cache-Control': 'public, max-age=86400' },
})
}4. Filter and interact
Call `get_layer_sources` for the list of filterable fields, then use normal Mapbox expressions, for example `map.setFilter('parcel-lines', ['==', ['get', 'zip5'], '80202'])`. Use `queryRenderedFeatures` on click to read a parcel's ID, then fetch its full record with `search_parcels`.
Does it work with MapLibre?
Yes. The tiles are standard Mapbox Vector Tiles (pbf), and the same `addSource`/`addLayer` code works in MapLibre GL JS, as well as in deck.gl's MVTLayer, OpenLayers and QGIS.
What does it cost?
5,000 tile requests a month are free; after that, 1 credit ($0.01) per 1,000 tiles. Caching tiles at your proxy (as above) cuts repeat requests.
Frequently asked questions
Why do parcels disappear when I zoom out?
Parcel layers are only drawn from a minimum zoom level, because millions of tiny polygons at country scale are unreadable and heavy. Check `minZoom` from `get_tile_endpoints`.