French Buildings API — RNB Building ID, Address, Parcel
Pricing
from $1.00 / 1,000 building returneds
French Buildings API — RNB Building ID, Address, Parcel
Returns French buildings from the national register (RNB) by address, parcel, point or ID: ID-RNB, status, footprint, addresses, parcels, BD TOPO/BDNB ids; failed and unchanged rows are never charged. Not affiliated with or endorsed by the RNB, IGN or the French government.
Pricing
from $1.00 / 1,000 building returneds
Rating
0.0
(0)
Developer
COMPASS DEV
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Returns French building records from the national building register (RNB) — ID-RNB, status, location, footprint, addresses, cadastral parcels and BD TOPO / BDNB ids — by ID-RNB, address, cadastral parcel, point or commune, and is never charged for failed, no-data or unchanged rows.
Give it ID-RNB building ids, French postal addresses, cadastral parcel ids, points (latitude,longitude) or commune INSEE codes; get one flat row per building from the RNB (Référentiel National des Bâtiments), France's public register that gives every building a stable identifier. Built for property, energy and insurance data work, spreadsheets, GIS and AI agents that need "which building is this, and what are its ids?" without handling the API's paging, geocoding or formats. Not affiliated with or endorsed by the RNB, IGN or the French government.
What it does
- Address → building: the address is matched in the BAN (France's national address base) and the buildings at that address are returned, with the match score.
- Parcel → buildings: the buildings on a cadastral parcel, largest share first.
- Point → buildings: the buildings within a radius of a latitude,longitude point, nearest first, with their distance.
- ID-RNB → building: the full record of a known building; BAN key → buildings: the buildings linked to an address key; commune → buildings: a commune's buildings by INSEE code.
- Every building row carries its ID-RNB, status (constructed, notUsable, demolished), point, footprint as GeoJSON, its addresses and BAN keys, its ids in IGN's BD TOPO and in the BDNB and, on request, its cadastral parcels.
- Watch mode (give a watch list name in
stateName): remembers every building and returns only:baseline: the first run of the list;new: a building the list did not have (for a commune: a building added to the register);changed: a tracked field changed (status, addresses, footprint, ids or parcels;changedFieldsandpreviousValuessay what and from what);- unchanged buildings are free and left out (
includeUnchanged: truereturns them as free rows). - A watch run with nothing new or changed returns exactly one free
no_datarow that says so.
- No personal data: the RNB holds buildings, not owners. The users who validated a building (
validated_byin the API) are never read into a row. - You are never charged for failed results: failed, no_data and unchanged rows are free.
Quick start
{ "queries": ["9QX7W3BF6RP6", "11 Allee du Garde, 33360 Cénac", "33118000AH0084"] }
A point (nearest buildings within 30 m) and a commune's buildings, with their cadastral parcels:
{ "queries": ["44.7925,-0.4470"], "inseeCodes": ["33118"], "withPlots": true, "maxBuildingsPerQuery": 50 }
Watch a portfolio of buildings for status, address or footprint changes (the first run is the baseline):
{ "queries": ["9QX7W3BF6RP6", "ZVZJBSDMATWR"], "stateName": "my-buildings" }
Input
| Field | Type | Default | Description |
|---|---|---|---|
queries | list of strings | — (prefilled with an ID-RNB, an address and a parcel) | One entry per line: an ID-RNB (12 characters), a French postal address, a cadastral parcel id (14 characters), latitude,longitude, or a BAN address key. Never a URL. A 5-digit code alone is refused (postal code or INSEE code?): use inseeCodes |
inseeCodes | list of strings | — | Communes by INSEE code (not postal code), e.g. 33118, 2A004 |
withPlots | boolean | false | Also return the cadastral parcels each building intersects (ID-RNB, BAN key and commune entries) |
radiusMeters | integer 0–1,000 | 30 | Point entries: the search radius |
minScore | number 0–1 | 0.8 | Address entries: the lowest BAN match score (the RNB's own default) |
maxBuildingsPerQuery | integer 1–10,000 | 100 | Most buildings returned for one entry |
mode | watch or export | — | Empty: watch when stateName is given, otherwise export. An explicit mode wins |
stateName | string | — | Watch list name. Watch mode without a name uses the list default |
includeUnchanged | boolean | false | Watch: also return unchanged buildings (free) |
maxItems | integer 1–100,000 | 1000 | Most charged buildings per run; in watch mode the rest come in the next run |
Output
{"status": "ok","attempts": 1,"error": null,"input": "16 Avenue de Mons, 33360 Cénac","mode": "export","watchList": null,"dropReason": null,"queryType": "address","rnbId": "9QX7W3BF6RP6","buildingStatus": "constructed","isActive": true,"latitude": 44.79249603125738,"longitude": -0.446996046489425,"shapeType": "MultiPolygon","shapeGeoJson": "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[-0.4471,44.7924],[-0.4469,44.7925],[-0.4468,44.7924],[-0.4471,44.7924]]]]}","addresses": ["16 Avenue de Mons, 33360 Cénac"],"banKeys": ["33118_4999_00016"],"streetNumber": "16","street": "Avenue de Mons","postalCode": "33360","city": "Cénac","inseeCode": "33118","bdtopoIds": ["BATIMENT0000000255605144"],"bdnbIds": ["bdnb-bc-51DW-XJQH-TUAX"],"parcels": null,"mainParcelId": null,"distanceMeters": null,"banScore": 0.9612,"matchedBanKey": "33118_4999_00016","parcelCoverRatio": null,"changeType": null,"changedFields": null,"previousValues": null,"url": "https://rnb.beta.gouv.fr/carte?q=9QX7W3BF6RP6","source": "Référentiel National des Bâtiments (RNB), rnb-api.beta.gouv.fr. Licence Ouverte 2.0 (Etalab): source RNB, retrieved on the scrapedAt date.","license": "Licence Ouverte / Open Licence 2.0 (Etalab)","licenseUrl": "https://www.etalab.gouv.fr/licence-ouverte-open-licence/","scrapedAt": "2026-10-03T10:00:00.000Z"}
| Status | Meaning | Charged? |
|---|---|---|
ok | A building returned | Export: yes. Watch: baseline, new and changed yes; unchanged no |
no_data | No building for the entry (an unknown ID-RNB, an address the BAN didn't match closely, an empty parcel or point), or nothing new since the last run (error says which) | No |
failed | Invalid entry, or no answer after retries (error says why) | No |
The key-value store holds RUN_REPORT (counts, charged and free rows, requests, stop reason), PROGRESS (the export
resume list) and, when something fails, the raw response (SNAPSHOT_*, validators' usernames removed).
Use it from AI agents
One clear main input, queries; every row has status, error, rnbId, url and scrapedAt. Call it through the
Apify API, the Apify MCP server (mouadapi/france-buildings) or x402 agentic payments. Copy-paste call (your Apify token
in APIFY_TOKEN):
curl -s -X POST "https://api.apify.com/v2/acts/mouadapi~france-buildings/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"queries": ["9QX7W3BF6RP6", "16 Avenue de Mons, 33360 Cénac"]}'
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('mouadapi/france-buildings').call({ queries: ['9QX7W3BF6RP6', '16 Avenue de Mons, 33360 Cénac'] });const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
Output fields
| Field | Type | Description |
|---|---|---|
status | string (or null) | ok = a building returned (charged in export mode and for baseline, new and changed rows; free when unchanged); no_data = no building for the entry, or nothing new since the last run (free); failed = invalid entry or no answer (free) |
attempts | integer (or null) | Requests made for this entry's page (retries included) |
error | string (or null) | Why a row is no_data or failed; null on ok rows |
input | string (or null) | The entry that produced this row (an ID-RNB, an address, a parcel, a point, a BAN key or a commune code) |
mode | string (or null) | watch or export |
watchList | string (or null) | Watch list name (watch mode); null in export mode |
dropReason | string (or null) | Kept for the shared row format; always null here (no record of this source is a person) |
queryType | string (or null) | How the entry was read: rnb_id, address, parcel, point, ban_key or commune |
rnbId | string (or null) | The building's national identifier in the RNB (12 characters, stable for the building's whole life) |
buildingStatus | string (or null) | constructed, notUsable or demolished (the RNB's status of the building) |
isActive | boolean (or null) | true when the ID-RNB is a real building (a demolished building stays active); false when the ID was deactivated as not a building |
latitude | number (or null) | The building's point, WGS 84 (EPSG:4326) |
longitude | number (or null) | The building's point, WGS 84 (EPSG:4326) |
shapeType | string (or null) | The footprint's GeoJSON type: Polygon, MultiPolygon or Point |
shapeGeoJson | string (or null) | The RNB's best known outline of the building, as GeoJSON text (WGS 84); not a reference footprint |
addresses | array (or null) | The building's addresses from the BAN (France's national address base), as text |
banKeys | array (or null) | The BAN interoperability key of each address (the same order as addresses) |
streetNumber | string (or null) | First address: the number, with its repetition index (bis, ter…) when there is one |
street | string (or null) | First address: the street |
postalCode | string (or null) | First address: the postal code |
city | string (or null) | First address: the commune |
inseeCode | string (or null) | First address: the commune's INSEE code |
bdtopoIds | array (or null) | The building's ids in IGN's BD TOPO |
bdnbIds | array (or null) | The building's ids in the BDNB (national building database) |
parcels | array (or null) | With "Include cadastral parcels": the parcels the building intersects and the share of the building on each (a geometric link, not a fiscal one); null otherwise |
mainParcelId | string (or null) | With "Include cadastral parcels": the parcel holding the largest share of the building |
distanceMeters | number (or null) | Point entries: the building's distance from the point, in metres |
banScore | number (or null) | Address entries: the BAN geocoding score of the address matched (0 to 1) |
matchedBanKey | string (or null) | Address entries: the BAN address key the address matched |
parcelCoverRatio | number (or null) | Parcel entries: the share of the building on the parcel (0 to 1); buildings come largest share first |
changeType | string (or null) | Watch mode: baseline (first run of the list), new, changed or unchanged (free); null in export mode |
changedFields | string (or null) | Watch mode: tracked fields that changed, comma-separated |
previousValues | string (or null) | Watch mode: the changed fields' previous values, as JSON |
url | string (or null) | The building on the RNB's public map |
source | string (or null) | Source and attribution (Licence Ouverte 2.0 asks reusers to name the source and the date) |
license | string (or null) | Licence of the data |
licenseUrl | string (or null) | Licence URL |
scrapedAt | string (or null) | When the row was made (ISO 8601); the date to cite with the source |
Pricing
Pay per event: one building event per returned building (export: every building; watch: baseline, new and
changed rows). no_data, failed and unchanged rows are free.
| Plan | Price per 1,000 buildings |
|---|---|
| Free | $1.50 |
| Bronze | $1.30 |
| Silver | $1.15 |
| Gold (and higher) | $1.00 |
Apify also charges its small per-run start event. There are no usage fees on top.
Limits
- One request at a time, about 3 a second at most (the RNB publishes a limit of 20 requests a second per IP address). If
the RNB answers HTTP 429, the run pauses 60, 120 and 240 seconds on the same connection, then stops with free
failedrows. No other IP or proxy is ever tried. - At most 1,000 entries per run and 10,000 buildings per entry. For millions of buildings, the RNB's national and departmental export files on data.gouv.fr suit better.
Known issues
- The RNB API is in alpha: its formats may change. The daily canary checks this Actor against the live API.
- A parcel's buildings come from a geometric intersection, not a fiscal link: a building that overlaps two parcels is returned for both, with its share on each.
- An address that the BAN matches with a score under
minScorereturns a freeno_datarow with the score.
FAQ
Is this the official RNB API? No: it is an Apify Actor that calls the RNB's public API and returns its records as flat rows. Not affiliated with or endorsed by the RNB, IGN or the French government.
Are owners' names returned? No. The RNB holds buildings and addresses, not owners, and the users who validated a building are never read into a row.
Why was my 5-digit code refused? It can be a postal code or a commune's INSEE code (Cénac is 33360 by post and 33118
by INSEE). Put an INSEE code in inseeCodes, or write the full address in queries.
Data and licence
- Source: the API of the Référentiel National des Bâtiments (RNB), documented at https://rnb-fr.gitbook.io/documentation/api-et-outils/api-batiments.
- Licence: Licence Ouverte / Open Licence 2.0 (Etalab), as declared on data.gouv.fr's "API RNB" record
(https://www.etalab.gouv.fr/licence-ouverte-open-licence/). Reuse, including commercial reuse, is allowed if you name
the source and the date: every row carries the source and the retrieval date (
scrapedAt). - This Actor is not affiliated with, endorsed by or provided by the RNB, IGN or the French government. It returns the data as published.