Artcurial.com Auction & Artist Scraper
Pricing
from $7.50 / 1,000 results
Artcurial.com Auction & Artist Scraper
Artcurial.com auction scraper — real hammer & buyer-premium prices, upcoming estimates, and a real cross-run artist price rollup, with delta mode.
Pricing
from $7.50 / 1,000 results
Rating
0.0
(0)
Developer
Artsiom Kunitsyn
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
artcurial-scraper
Scrapes auction lots and a real artist rollup from Artcurial.com — France's leading independent auction house. Real, open realized prices — both the hammer price and the all-in final price including buyer's premium — for historical sales, upcoming-sale estimates, and a genuine cross-run artist rollup, all from one Actor.
Contents
- Key features
- Output
- Input
- Input examples
- Incremental (delta) mode
- How to scrape Artcurial.com
- You might also like
- FAQ
🔑 Key features
- Two prices per sold lot, not one.
hammer_price(the auctioneer's declared winning bid) andfinal_price(hammer price plus buyer's premium — the real all-in figure) are both reported — richer than most comparable actors, which only ever expose one realized-price figure. - Three entity types, one Actor.
entityType: currentAuctions(upcoming, not yet resolved),auctionResults(historical, with real realized prices — the default), orartists(a real rollup — see below). - A plain public JSON API under the hood, no scraping tricks. Every lot comes from
/ace/sales/{ref}/items, a clean paginated REST endpoint — no HTML parsing, no embedded JavaScript blob to unpack, no login. - Full historical archive in scope by default.
auctionResultswalks every finished sale (2,595+ confirmed) when unbounded (maxItems: null) — not a recent-years-only sample. - Delta mode, tuned per entity type.
auctionResultsdefaults to the usual auto-incremental behavior (full scan first run, changes only after).currentAuctionsalways fully refreshes every run instead — upcoming-sale estimates change as a sale date approaches, so a full picture beats a delta for that one. - A real artist rollup, not a capped page.
entityType: artistsreports uncapped running stats (lot count, average hammer/final price, latest lot) accumulated from everyauctionResultslot actually crawled — see Output's known gaps for exactly what that means and doesn't mean. - Artcurial Motorcars is out of scope.
robots.txtexplicitly disallows/motorcars— sales run by that department are filtered out of discovery entirely, not just left unlinked.
📋 Output
One dataset item per lot or artist, depending on entityType — see
.actor/dataset_schema.json for the full field list, or the Output
tab's per-entity-type views for a readable table.
Example lot record (historical, sold):
{"source": "artcurial","entity_type": "auctionResults","external_id": "artcurial_bcdf867e-f222-11f0-9027-31ffe29623b3","url": "https://www.artcurial.com/en/sales/6557","title": "PORTE-TORCHÈRE DE STYLE NÉO-POMPÉIEN","sale_ref": "6557","sale_name": "L'œil d'un érudit","currency": "EUR","estimate_low": 1500.0,"estimate_high": 2500.0,"hammer_price": 2600.0,"final_price": 3861.0,"sold": true,"change_type": "new"}
Example artist rollup record:
{"source": "artcurial","entity_type": "artists","external_id": "artcurial_artist_19802f4e-38e1-11f1-bef4-f918d58faf87","name": "Albrecht SCHNIDER","tracked_lot_count": 4,"tracked_avg_hammer_price": 4750.0,"tracked_avg_final_price": 7053.25,"latest_lot_title": "Sans titre - 1998","latest_sale_name": "L'œil d'un érudit"}
Results can be downloaded as JSON, CSV, or Excel from the Console's Output tab, or pulled via the Apify API/dataset endpoint.
Known gaps:
- There is no per-lot URL on Artcurial's own site — every lot lives only inside its sale's page, so
urlalways points at the sale,https://www.artcurial.com/en/sales/{ref}, not an individual lot. hammer_price/final_priceare only set once a lot is actually sold (sold: true).sale_nameis only populated on a discovery-driven run (nostartUrls) — astartUrls-scoped run skips the normal sales-list walk that carries each sale's name, sosale_name(and anentityType: artistsrollup'slatest_sale_namebuilt from it) isnullin that case.entityType: artistsdoes not crawl anything itself — it reads a rollup thatauctionResults/currentAuctionsruns build up over time as they process sold lots. RunningartistsbeforeauctionResultshas ever run pushes nothing (with a clear log message saying so). The rollup's numbers (tracked_lot_countetc.) are real and uncapped, but only as complete as what's actually been crawled so far — not necessarily an artist's true full history at Artcurial. They get more complete the moreauctionResultsruns (especially a full, unbounded one).artist_uuid/artist_nameare only populated when Artcurial's own system links a lot to a named artist or carries free-text attribution — lots catalogued as a school/period/anonymous (e.g. "Ecole suisse vers 1700") carry that text inartist_namewith noartist_uuid, and some lots carry neither at all.
⚙️ Input
See .actor/input_schema.json for the full JSON schema.
| Parameter | Type | Default | Description |
|---|---|---|---|
entityType | String | auctionResults | currentAuctions, auctionResults, or artists. |
startUrls | Array of strings | (none) | Specific Artcurial sale references (e.g. "6557", from .../en/sales/6557) to scrape directly — not URLs, since there's no per-lot URL to accept. Ignored for entityType=artists. Scope is always "custom" — no delisting-detection, no persisted baseline, and sale_name is left null (see Output's known gaps). Leave empty for the full sales-list-driven crawl instead. |
maxItems | Integer | 50 | Stop after pushing this many dataset items (lots or artists). Defaults to a fast, cheap preview (also what keeps an unconfigured run within Apify's automated 5-minute QA check). A full auctionResults crawl covers the entire finished-sales archive — raise this or clear it (set to null) for that. |
mode | String | auto | auto (recommended): the usual full-then-incremental behavior for auctionResults; always full for currentAuctions regardless of an existing baseline (see Key features). full/incremental override this per run. Has no effect for entityType=artists. |
impersonate | String | chrome (internal) | curl_cffi TLS-impersonation target. No bot-management signal was observed anywhere on artcurial.com while building this Actor, so this is set internally by default. |
proxyConfiguration | Object | {"useApifyProxy": false} | Apify Proxy config. Off by default — this Actor clears the site fine without one. |
🧪 Input examples
Quick preview of recent historical results (the default):
{ "entityType": "auctionResults" }
Full historical archive (exhaustive, slow — every finished sale, maxItems: null explicitly
overrides the 50-item default):
{ "entityType": "auctionResults", "maxItems": null }
What's currently up for auction, fully refreshed:
{ "entityType": "currentAuctions", "maxItems": null }
Artist rollup (run auctionResults — ideally a full, unbounded run — at least once first):
{ "entityType": "artists", "maxItems": null }
A specific sale's results:
{ "entityType": "auctionResults", "startUrls": ["6557"] }
Scheduled tracking run — full, uncapped run (maxItems cleared — required for the baseline to
save and delistings to be detected):
{ "entityType": "auctionResults", "mode": "incremental", "maxItems": null }
🔄 Incremental (delta) mode
Every currentAuctions/auctionResults run classifies each lot as new, changed (price/sold
status moved), unchanged, or delisted, using a state baseline persisted in a named Apify
Key-Value Store scoped to entityType. entityType: artists doesn't use delta mode at all — every
run is a full snapshot of the current rollup (see Output's known gaps).
auctionResults:mode: auto(default) — first run for a scope pushes everything (full); later runs push onlynew/changed/delisted(incremental).currentAuctions:mode: autoalways behaves asfull, every run — see Key features for why.- A
startUrls-scoped run is always partial and never updates the baseline or reports delistings.
Full design: ../../docs/incremental-mode.md.
🚀 How to scrape Artcurial.com
- Open the Artcurial Auction Results & Artist Scraper in Apify Console and go to the Input tab.
- Pick
entityType(currentAuctions,auctionResults, orartists). maxItemsdefaults to 50 (a quick preview) — clear it (set tonull) for a full, uncapped run.- Click Start.
- When the run finishes, browse results in the Output tab, or download as JSON/CSV/Excel, or fetch them via the API.
- To track over time instead of scraping once: create a Schedule with
mode: auto.
🔗 You might also like
- Dorotheum Auction Results & Artist Scraper — the first entry in the Auction houses collection, same open-realized-price idea applied to one of Europe's oldest auction houses.
❓ FAQ
Is it legal to scrape Artcurial.com? It's legal to collect publicly available auction-result data such as lot descriptions, prices, and sale information. Scrape it only with a legitimate purpose under GDPR.
How do I get only new/changed items? Use mode: auto (or incremental) on a schedule — see
Incremental mode.
Why is hammer_price/final_price null for a lot that's clearly listed on the results page?
That lot hasn't sold yet (or wasn't sold) — check estimate_low/estimate_high instead.
Why does entityType: artists push nothing? It reads a rollup built up by
entityType: auctionResults runs — it doesn't crawl anything on its own. Run auctionResults (ideally
a full, unbounded run) at least once first.
Search keywords
artcurial scraper, auction house scraper, auction results scraper, art price data, art market analytics, realized price data, hammer price data, auction price index, art collector data feed