Pap.fr $1💰| URL Search | Keyword Filters | Rich Output
Pricing
from $1.00 / 1,000 results
Pap.fr $1💰| URL Search | Keyword Filters | Rich Output
From $1/1k. Extract property listings from pap.fr. Get fully-detailed listings with price, address, rooms, area, photo gallery, description, and arrondissement/department/region geography.
Pricing
from $1.00 / 1,000 results
Rating
5.0
(1)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
35
Total users
6
Monthly active users
14 days ago
Last modified
Categories
Share
PAP.fr Scraper: Owner Listed Property Data for France
PAP.fr, De Particulier a Particulier, is France's largest site for owner to owner property listings, with no estate agencies involved. This scraper turns it into structured data: price, rooms, living area, full address, arrondissement, department and region, energy ratings, and the complete photo gallery for sale and rental listings. Pick a city and property type from the form, or paste a PAP.fr search URL for finer filters, then export to JSON, CSV or Excel, or read the results through the API.
Why This Scraper?
- Owner listed only. PAP.fr does not accept agency listings, so every record is a private seller or landlord, not an agent relisting the same property everywhere.
- Two ways to search. Pick a French city, department and property type from the form, or paste any PAP.fr search URL you already refined in your browser, including price and surface filters the form here does not expose.
- Detail depth on demand. Turn on detail fetching for coordinates, energy and greenhouse gas ratings, street address, seller phone, reference number, bedrooms, floor, charges, property tax and the full photo gallery. Turn it off for a faster run with just the results page fields.
- French geography, resolved. Cities are matched to PAP's own location ids automatically, and the department is derived from the city name when you leave it blank.
- Auto pagination. Walks every result page forward to the limit you set, whether you start from the form or from a pasted URL that already points at page 10.
- Built for monitoring. Incremental mode returns only new, updated and reappeared listings on repeat runs of the same search, and resume support lets a large one time pull continue across separate runs without re collecting anything.
Use Cases
- Buyers and renters: track new owner listed apartments or houses in specific cities without agency markups or duplicate listings.
- Market research: build a dataset of asking prices, living area and rooms across French cities to study pricing trends.
- Investors and analysts: monitor a set of departments for new listings, price drops or delisted properties over time.
- Proptech and data teams: feed owner listed inventory into a search tool, valuation model or lead pipeline.
Data You Get
Sample shape: values are illustrative placeholders, not from a live record.
| Field | Example |
|---|---|
id | "400000001" |
url | "https://www.pap.fr/annonces/vente-appartement-paris-r400000001" |
listingType | "Buy" (also "Rent") |
propertyType | "Apartment" |
title | "Vente appartement 3 pieces 57 m2 Paris 18e" |
priceValue | 590000 |
priceDisplay | "590 000 €" |
rooms | 3 |
livingSpace | 57 |
streetAddress | "Rue Muller, 75018 Paris" |
city | "Paris 18e" |
arrondissement | "Paris 18e" |
postcode | "75018" |
department | "Paris" |
region | "Ile-de-France" |
latitude / longitude | 48.8358 / 2.2899 (when fetchDetails is on) |
energyClass / ghgClass | "D" / "D", A to G (when fetchDetails is on) |
reference | "G20/2718" |
imageCount | 18 |
scrapedAt | "2026-04-22T10:00:00.000Z" |
The same record also carries bedrooms, floor, hoaChargesYearly, propertyTaxYearly and heatingType (parsed from the seller's description, so they can be missing), isActive, sellerPhone and seller (the "Particulier" tag PAP uses for private listings), refusesCommercialSolicitation, the full images array and additionalProperties (PAP's own French key and value pairs, such as "Type de bien"). With incrementalMode on, each record also gets changeType, changedFields, firstSeenAt and lastSeenAt.
How to Use
- Pick a search mode:
filter(city, department and property type) orurl(paste PAP.fr search links). - Fill in the fields for that mode. In filter mode you can leave the department blank for well known cities, it is derived automatically.
- Turn detail fetching on or off, and set Max pages and Max listings to control run size and cost.
- Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.
Search one city:
{"mode": "filter","locations": [{ "city": "Paris", "department": "75" }],"listingType": "Buy","propertyType": "Apartment","maxPages": 10}
Rentals with a rooms and sort filter:
{"mode": "filter","locations": [{ "city": "Lyon", "department": "69" }],"listingType": "Rent","propertyType": "Apartment","roomsMin": 3,"sortBy": "PriceAsc","maxPages": 10}
Several cities at once, department left to auto detect:
{"mode": "filter","locations": [{ "city": "Paris" },{ "city": "Marseille" },{ "city": "Bordeaux" }],"listingType": "Buy","propertyType": "House","maxPages": 5}
A pasted URL with a rooms filter and price sort, resuming from page 3:
{"mode": "url","urls": ["https://www.pap.fr/annonce/vente-appartements-paris-75-g439-3-pieces-tri-prix-asc-3"],"maxPages": 20}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/pap-fr-scraper").call(run_input={"mode": "filter","locations": [{"city": "Paris", "department": "75"}],"listingType": "Buy","propertyType": "Apartment","maxPages": 5,})for listing in client.dataset(run["defaultDatasetId"]).iterate_items():print(listing["title"], listing["priceDisplay"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/pap-fr-scraper').call({mode: 'filter',locations: [{ city: 'Paris', department: '75' }],listingType: 'Buy',propertyType: 'Apartment',maxPages: 5,});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
Filter mode has no price or surface filter
PAP.fr only applies price and surface filters when they are submitted through its own search form, so filter mode cannot build them into a URL. To use them, refine a search in your own browser (property type, location, price, surface), copy the resulting URL, and paste it into urls in url mode. Everything else, including sort order and the page you start from, is read from that URL.
Resume and recurring updates
- Resume (
resumeFromRunId) continues one interrupted, large, one time pull: paste its run or dataset ID and the actor skips every listing id already saved there, so you only pay for the new ones. The actor also checkpoints its own progress automatically, so a platform restart or a manual resurrect of a failed run picks back up without re saving what it already collected. - Incremental mode (
incrementalMode) is for scheduling the same search again and again. Each listing is classifiedNEW,UPDATED(withchangedFields),UNCHANGED,REAPPEARED, orEXPIRED. By default onlyNEW,UPDATEDandREAPPEAREDrows are returned and billed. Turn onemitUnchangedoremitExpiredonly if you also want those rows.EXPIREDrows only appear after a run that scanned the entire tracked search, not one capped bymaxPagesormaxListings, blocked partway through, or run withresumeFromRunId.stateKeynames or deliberately shares the tracked state; left blank, a key is derived from the search itself, so two different searches never mix state.
Send results into your apps (MCP connectors)
Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape, the Apify dataset is never changed.
What gets written to the connector: a condensed, human readable summary of each listing, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify -> Settings -> Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. If the picker is empty, you have not authorized a connector yet.
- For Notion, also set
notionParentPageUrlto the page where items should be created.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third party credentials. Leave the field empty to skip.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | filter | filter for city and department inputs, or url for pasted PAP.fr search URLs. |
locations | array | prefill: Paris | City and department pairs to search (filter mode only). Department is auto derived from the city if left blank. Falls back to Paris, department 75, if the array is left empty. |
urls | array | prefill: one Paris URL | PAP.fr search URLs (url mode only). A trailing -N page number is honored as the starting page. |
listingType | string | Buy | Buy (Vente) or Rent (Location). Filter mode only. |
propertyType | string | Apartment | Apartment, House, Plot, Parking, or CommercialProperty. Filter mode only. |
roomsMin | integer | (none) | Minimum number of rooms (pieces). Values above 5 are treated as 5, PAP's own "5 or more" cap. Filter mode only. |
sortBy | string | Default | Default, PriceAsc, PriceDesc, SurfaceAsc, SurfaceDesc, or DateAsc. Filter mode only, ignored in url mode. |
maxPages | integer | (empty, unlimited) | Maximum result pages to walk per search. Leave empty to walk every result page. |
maxListings | integer | 20 | Hard cap on listings across the whole run. 0 means unlimited, still bounded by maxPages. |
fetchDetails | boolean | true | Visit each listing's page for coordinates, energy ratings, street address, full description, reference number, bedrooms, floor, charges, property tax, heating type and the full photo gallery. |
resumeFromRunId | string | (none) | A previous run ID or dataset ID to continue a large walk across separate runs. Listings already saved there are skipped. |
incrementalMode | boolean | false | Turn on for recurring monitoring of the same search. Later runs return only new, updated and reappeared listings by default. |
stateKey | string | (none) | Optional name for an incremental mode monitoring campaign. Left blank, a key is derived automatically from the search itself. |
emitUnchanged | boolean | false | Incremental mode only. Also return, and bill, listings unchanged since the last run. |
emitExpired | boolean | false | Incremental mode only. Also return, and bill, listings no longer found, after a run that fully scanned the tracked search. |
proxy | object | Apify Proxy, RESIDENTIAL (prefill pins IT) | Connection settings. A residential proxy is needed for this site. |
mcpConnectors | array | (none) | Optional. Send a summary of each listing to apps you authorized under Integrations. |
notionParentPageUrl | string | (none) | Notion connector only. Page under which listing pages are created. |
maxNotifyListings | integer | 50 | Cap on listings exported to each connector per run. Does not affect the dataset. |
Output Example
Sample shape: values are illustrative placeholders, not from a live record.
{"id": "400000001","url": "https://www.pap.fr/annonces/vente-appartement-paris-r400000001","listingType": "Buy","propertyType": "Apartment","title": "Vente appartement 3 pieces 57 m2 Paris 18e","priceValue": 590000,"priceCurrency": "EUR","priceDisplay": "590 000 €","rooms": 3,"livingSpace": 57,"bedrooms": 2,"floor": 4,"hoaChargesYearly": 2766,"propertyTaxYearly": 1450,"heatingType": "individuel gaz","description": "Bel appartement lumineux au 4e etage avec ascenseur, proche commerces et metro.","streetAddress": "Rue Muller, 75018 Paris","city": "Paris 18e","postcode": "75018","arrondissement": "Paris 18e","department": "Paris","region": "Ile-de-France","latitude": 48.8358,"longitude": 2.2899,"energyClass": "D","ghgClass": "D","isActive": true,"reference": "G20/2718","sellerPhone": "01 99 00 12 34","seller": { "@type": "Person", "name": "Particulier" },"refusesCommercialSolicitation": false,"imageCount": 18,"images": ["https://cdn.pap.fr/photos/example-1.jpg", "https://cdn.pap.fr/photos/example-2.jpg"],"additionalProperties": { "Type de bien": "Appartement", "Ascenseur": "Oui" },"scrapedAt": "2026-04-22T10:00:00.000Z"}
With incrementalMode on, each record also carries changeType (NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED), changedFields, firstSeenAt and lastSeenAt. These four fields are absent entirely when incrementalMode is off, the default output shape is unchanged.
Plan Requirement
This site requires a residential proxy to load reliably. Keep the default connection setting, it already points at a residential proxy group. For a run that supplies its own proxy under Connection, use a residential provider; a non residential proxy is likely to be blocked.
FAQ
How much does it cost?
You pay per listing returned. The Pricing tab shows the current rates. Use Max listings and Max pages to cap the cost of any run.
Is it legal to scrape PAP.fr?
This actor collects only publicly available listing data. You are responsible for how you use it: follow PAP.fr's terms and the laws that apply to you, and get legal advice before any commercial redistribution. Seller phone numbers and descriptions are personal data in some jurisdictions, handle exported records accordingly.
Can I get only new or changed listings on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new, updated and reappeared listings, and unchanged ones are not returned or billed unless you turn emitUnchanged on.
Why can't I filter by price or surface in filter mode?
PAP.fr only accepts those filters through its own search form, not in the result page URL. Apply them in your browser, copy the URL, and paste it into urls in url mode instead.
Why did my run fail instead of returning an empty dataset?
The run fails only for a configuration problem, such as a resumeFromRunId that does not match a run or dataset you can read, combining resumeFromRunId with an incremental campaign that already has saved state, or no working proxy being available at all. If the site itself blocks a page or a search returns nothing, the run still finishes normally with whatever it found, an empty dataset there means no listings were found or reachable, not that the run malfunctioned. Check the run log either way, it explains which case happened.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push listing summaries into Notion, Linear or Airtable.
🔗 Want more real estate data?
Pair this actor with these related scrapers from the same team:
| 🏷️ Leboncoin FR Pull public leboncoin.fr listings across cars, property, jobs, electronics, furniture... | 🏠 Immowelt.de Scraper Scrape detailed property listings from Immowelt.de into clean structured data. Extract... |
| 📇 PagesJaunes FR From $0.8/1K. Scrapes business listings from PagesJaunes.fr (French Yellow Pages)... | 🏠 SeLoger Scraper Scrape SeLoger.com properties for sale and rent. Search by location with price, room and... |
| 💼 France Travail Scraper Scrape job offers from France Travail with titles, companies, locations, salaries... | 🥦 Auchan France Scraper Scrape Auchan.fr products: grocery, drinks, household and general merchandise. Real price... |
💬 Support & custom scrapers
- 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- 🛠️ Need another site, extra fields or a private build? Email abotapi@proton.me or message Telegram @abotapi.
- ⭐ Enjoying it? A quick review on the actor page helps other users find it.