France Property Sales & Prices (DVF)
Pricing
from $3.00 / 1,000 property transaction returneds
France Property Sales & Prices (DVF)
Every French property sale, straight from the official DVF register: price, address, surface, date and price per m2. Filter by department, commune, postal code, price, surface, year and property type. Multi-lot sales merged into one clean JSON row.
Pricing
from $3.00 / 1,000 property transaction returneds
Rating
0.0
(0)
Developer
Dmitry Melikhov
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 minutes ago
Last modified
Categories
Share
Every French property sale, as clean JSON. This Actor queries the official Demandes de valeurs foncières (DVF) register — the sales database published by the French tax administration (DGFiP) — and returns transactions filtered by department, commune, postal code, price, surface, date range and property type, each with a computed price per square metre.
The raw source is public and free, but it ships as large pipe-delimited text files per year, documented only in French, and with no filtering API. This Actor downloads the Etalab-cleaned per-department CSVs, applies your filters, and returns clean JSON — no file wrangling required.
Use cases
- Valuation and comparables — pull every sale in a commune for a given year and surface range, then read
prixM2to price a property against real transactions rather than asking prices. - Price-per-m² trends — track how €/m² moves across departments, communes or years for market research and reporting.
- Off-plan and new-build tracking —
salesOnlykeeps genuine sales, including VEFA (off-plan), while dropping expropriations, adjudications and exchanges. - Geospatial and mapping — every row carries latitude and longitude, so results drop straight into a map or a spatial analysis.
- Multi-lot and portfolio analysis — a sale bundling an apartment, a cellar and a parking space is three raw rows; with
oneRowPerTransaction(default) they merge into one sale-level record with summed surface and a correct €/m². - Data pipelines — clean JSON out, so results feed straight into a warehouse or dashboard without parsing French fixed-width files.
Output
With oneRowPerTransaction (default), one row per real-world sale:
{"idMutation": "2024-1193218","dateMutation": "2024-01-04","natureMutation": "Vente","valeurFonciere": 1042000.0,"prixM2": 12116.28,"adresse": "4 VLA PERREUR","codePostal": "75020","codeCommune": "75120","nomCommune": "Paris 20e Arrondissement","codeDepartement": "75","typesLocal": ["Appartement", "Dépendance"],"surfaceReelleBati": 86.0,"surfaceDependance": null,"nombrePiecesPrincipales": 4,"surfaceTerrain": null,"longitude": 2.405228,"latitude": 48.868216}
surfaceReelleBati is the residential / main built surface — annexes such as
cellars, garages, parking and sheds (type Dépendance) are excluded and reported
separately as surfaceDependance (which is null when the source reports no
surface for them). prixM2 is valeurFonciere divided by surfaceReelleBati
(the living area), so a sale that bundles a cellar no longer drags the €/m² down.
nombrePiecesPrincipales and surfaceTerrain are summed across every lot. With
oneRowPerTransaction: false, you get the raw per-lot rows instead — typesLocal
becomes a single typeLocal, and a multi-lot sale produces one row per distinct
type it contains (the raw file doesn't separate surface per lot, so each of those
rows repeats the same summed surface/price — if you need true per-lot surface,
query one small commune and reconcile the raw file yourself for that case).
Input
| Field | Type | Notes |
|---|---|---|
departments | array of strings | Required. French department codes, e.g. ["75", "92"]. Corsica is 2A/2B; overseas departments are 971-976. |
year | string | One of 2019-2026. Defaults to 2024. (The latest year is partial until the publisher's next update.) |
communeName | string | Case-insensitive substring match. |
postalCode | string | Exact match. |
propertyType | string | Maison, Appartement, Dépendance, or the industrial/commercial category. |
minPrice / maxPrice | integer | Filters on the declared transaction price (EUR). |
minSurface / maxSurface | integer | Filters on the living built surface (sqm), excluding Dépendance annexes. |
dateFrom / dateTo | string | YYYY-MM-DD. |
salesOnly | boolean | Default true. Excludes expropriations, adjudications and exchanges — keeps actual sales (including off-plan/VEFA). |
oneRowPerTransaction | boolean | Default true. The raw source has one row per lot — a sale bundling an apartment, a cellar and a parking space is 3 raw rows. With this on, rows sharing the same idMutation are merged: living surface (surfaceReelleBati) and room counts are summed, annex surface goes to surfaceDependance, prixM2 is computed on the living surface, and every property type involved is listed in typesLocal. Set to false to get the raw per-lot rows instead (see below). |
maxResults | integer | Hard cap on rows returned, applied department by department in the order given. Default 1000. |
Note: the official DVF source currently publishes 2019–2025. 2026 is selectable in advance and will return results once the publisher releases it.
Data source and license
Source: data.gouv.fr — Demandes de valeurs foncières géolocalisées,
redistributed per-department by Etalab at files.data.gouv.fr/geo-dvf.
Published under Licence Ouverte / Open Licence 2.0.
Updated by the publisher roughly twice a year (April and October); the most
recent full year is usually only complete by the following spring.