# Chrono24 Scraper · All-in-One Watch Listings · $1.50/1k (`memo23/chrono24-scraper`) Actor

Chrono24 all-in-one scraper — auto-classifies detail, brand-index, model-index, and search URLs in one run. 35+ fields per listing: reference, year, movement, caliber, materials, dealer country, shipping policy, full image array. JSON-LD product data. Pure HTTP, no browser

- **URL**: https://apify.com/memo23/chrono24-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Agents, Lead generation, Automation
- **Stats:** 81 total users, 28 monthly users, 97.8% runs succeeded, 2 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.50 / 1,000 output records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Chrono24 Scraper — Watch Listings, Brand & Model Search, Full Detail Specs

Paste any chrono24.com URL — a single listing, a brand page, a model page, or a search — and get a clean structured dataset with **40+ fields per watch**: reference number, year, movement, caliber, power reserve, jewels, case diameter, materials, dial, bracelet, seller, country, shipping, and the full image gallery. Talks to Chrono24's own mobile JSON API. **No Cloudflare wall, no headless browser, works on any proxy.**

***

### Why use this scraper

- **All Chrono24 URL kinds in one input** — paste a brand page, a model page, a search query, and individual listing URLs in the same array. Each is auto-classified and routed to the right API call. No separate actors per URL shape.
- **40+ fields per listing** — far beyond price + condition. Every detail row carries: brand, model, reference number, production year, condition, movement type, caliber name, power reserve, jewel count, case diameter + thickness + material, bezel material, crystal/glass, dial color + markers, bracelet material + color + length, clasp, lug width, gender, water resistance, functions, scope of delivery, seller type + country + member-since, plus the full description and image gallery.
- **Official mobile JSON API, not HTML scraping** — the actor speaks the same signed JSON API the Chrono24 iOS/Android apps use. That means structured, type-stable data (no brittle HTML parsing) and resilience to website redesigns.
- **No Cloudflare, no browser** — the mobile API endpoint isn't behind Cloudflare's challenge wall, so there's no CAPTCHA solver, no headless Chromium, and **no need for premium residential proxies** — datacenter or any residential pool works. Memory footprint ~512 MB.
- **Full filter control** — narrow by price, year, condition, movement, case material, dial color, bracelet, gender, seller type, country and sort order. Paste a filtered chrono24.com URL *or* set `searchParams` in plain words (`"steel"`, `"automatic"`, `"price descending"`) — they're resolved to Chrono24's ids for you.
- **Fast card mode** — set `fetchListingDetails: false` to emit ~15 fields per listing straight from the search response (id, title, subtitle, price, shipping, country, seller type, image gallery) at 50 listings per request — ideal for price-tracking dashboards.
- **CSV-friendly flatten** — every watch spec is flattened to a `specs_*` column (`specs_caliber`, `specs_casediameter`, `specs_year`…) for instant spreadsheet use.

***

### Overview

Chrono24 is the world's largest luxury watch marketplace — 500,000+ active listings (114,000+ Rolex alone), ~3 million users, ~10,000 watch brands. Whether you're a dealer monitoring inventory, an analyst tracking model price drifts, an arbitrage operator hunting cross-market spreads, or a collector building a database, you eventually need this data structured.

The actor authenticates to Chrono24's mobile API (`chrono24.app`) exactly like the official app — a one-time session handshake plus a per-request HMAC signature — then pages through search results and pulls full detail JSON per listing. Four URL shapes are auto-classified, so you don't tell the actor "what kind of URL this is"; you just paste URLs.

***

### Supported inputs

| Input | Pattern | What you get |
|---|---|---|
| **Detail page** — single listing | `/{brand}/{slug}--id{LISTING_ID}.htm` | 1 row with the full 40+ field spec sheet |
| **Brand page** — all of a brand | `/{brand}/index.htm` | every listing of the brand (e.g. 114k+ Rolex), 50/page, paginated |
| **Model page** — one model | `/{brand}/{model-slug}--mod{MODEL_ID}.htm` | every listing of one model (Daytona, Speedmaster, Nautilus…) |
| **Search** — keyword query | `/search/index.htm?query=…` | every match for the query (e.g. `patek nautilus`), paginated |

Mix any of these in the same `startUrls[]` array. JSON or CSV output.

**Filters are fully supported** — either paste a filtered/sorted chrono24.com URL (price, year, condition, movement, materials, location, sort are read straight from the query string), or set them once in `searchParams` using plain words (`"steel"`, `"automatic"`, `"new"`, `"price descending"`). See [Filters](#filters) below.

> Speaks Chrono24's mobile JSON API. No Cloudflare challenge, no browser, no CAPTCHA solver.

***

### Use cases

| Audience | Use it to… |
|---|---|
| **Watch dealers** | Monitor competitor inventory + price changes across brands daily. Alert when a target reference (`116610LN`, `5711/1A`, `15510ST`) appears under a threshold. |
| **Investment analysts** | Track average ask for blue-chip references over time. The `referenceNumber` + `specs_year` + `price` triple builds a per-cohort index. |
| **Arbitrage operators** | Cross-market spread mining — pull Chrono24 + other marketplaces in parallel, find >15% deltas after shipping normalisation. |
| **Insurance / appraisal** | Replacement-value lookups by reference + condition + year, with a defensible full spec sheet. |
| **Collectors** | Build a private database of every Submariner / Speedmaster / Royal Oak with movement, caliber, year, condition, seller country, photos. |

***

### How it works

<p align="center">
  <img src="https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-chrono24.png" alt="How Chrono24 Scraper works" width="100%" />
</p>

Three stages, all pure HTTP JSON:

1. **Classify & authenticate** — each input URL is matched against a deterministic regex set (detail / brand / model / search). The actor performs the mobile app's one-time session handshake to obtain a session cookie, and resolves brand slugs to their numeric manufacturer IDs from the API's brand catalogue.
2. **Signed API calls** — every request carries the mobile app's `app-tag` HMAC signature (computed per request over the URL, method, timestamp, nonce, and session), so the API returns clean JSON. A fresh proxy IP rotates in per request.
3. **Map & emit** — search responses page 50 listings at a time; in detail mode each listing's full spec JSON is fetched (concurrency-capped) and every attribute is flattened into `specs_*` columns. One row per listing, deduped by `listingId` across all inputs.

End-to-end live smoke test: a `patek nautilus` search (3,904 matches) returned 6 full detail rows in ~4 s through a datacenter proxy, 0 failures; an Omega brand page (55,770 listings) streamed 50 cards per request.

***

### Input configuration

Field | Type | Required | Notes
\--- | --- | --- | ---
`startUrls` | `string[]` | yes | Any mix of detail / brand / model / search chrono24.com URLs. Auto-classified. Filters embedded in the URL (e.g. `?priceFrom=5000&sortorder=1`) are honoured.
`priceFrom`, `priceTo` | `integer` | no | Price range in USD, applied to every brand/model/search URL.
`year` | `integer` | no | Only listings produced in this exact year.
`usedOrNew` | `string` | no | `"new"` or `"used"`.
`condition` | `string[]` | no | Condition grades — `"new"`, `"like new & unworn"`, `"very good"`, `"good"`, `"fair"`, `"incomplete"`.
`movementTypes` | `string[]` | no | `"automatic"`, `"manual winding"`, `"quartz"`.
`caseMaterials` | `string[]` | no | `"steel"`, `"yellow gold"`, `"titanium"`, `"ceramic"`, …
`dialColor` | `string[]` | no | `"black"`, `"blue"`, `"green"`, `"meteorite"`, …
`gender` | `string` | no | `"men"` or `"women"`.
`sellerType` | `string[]` | no | `"professional dealer"`, `"private sellers"`, `"chrono24 direct"`.
`countryIds` | `string[]` | no | Seller countries — names (`"Germany"`) or ISO codes (`"DE"`).
`sortorder` | `string` | no | `"relevance"`, `"price ascending"`, `"price descending"`, `"newest"`, `"popularity"`.
`searchParams` | `object` | no | Advanced passthrough for any Chrono24 search param not covered above (`braceletMaterial`, `waterproof`, `functions`, `caseDiameter`, …). Accepts plain words (resolved to Chrono24 ids) or raw ids. Wins over the fields above on conflict. See [Filters](#filters).
`fetchListingDetails` | `boolean` | no | Default `true`. After each search card, fetch the full detail JSON (40+ fields incl. caliber, materials, seller). Disable for fast card mode (~15 fields, 50/request, no per-listing fetch).
`maxIndexPages` | `integer` | no | Default `10`. Max pages of search pagination per brand/model/search URL (50 listings per page).
`flatten` | `boolean` | no | Default `true`. Flatten the nested `specs` object to `specs_*` top-level columns for CSV. Disable to keep nested JSON.
`includeRaw` | `boolean` | no | Default `false`. Attach the raw detail API payload as `rawJson` on each detail row.
`maxItems` | `integer` | no | Hard cap on rows emitted. Default `1000`. Free-tier users capped at `100`.
`maxConcurrency` | `integer` | no | Parallel detail fetches. Default `6`.
`proxy` | `object` | no | Any proxy works — the mobile API isn't behind Cloudflare. Datacenter is cheapest; residential is the safe default. You can also supply your own proxy URLs.

#### Example input

```json
{
  "startUrls": [
    "https://www.chrono24.com/rolex/daytona--mod2.htm",
    "https://www.chrono24.com/omega/index.htm",
    "https://www.chrono24.com/rolex/rolex-lady-datejust--id45070783.htm",
    "https://www.chrono24.com/search/index.htm?query=patek+nautilus"
  ],
  "fetchListingDetails": true,
  "maxIndexPages": 5,
  "maxItems": 500,
  "proxy": { "useApifyProxy": true }
}
```

#### Filters

Three ways to filter — they stack (URL filters → form filters → `searchParams`, later wins on conflict):

**1. Use the form fields** (easiest) — price range, year, new/used, condition, movement, case material, dial color, gender, seller type, country and sort order are all first-class inputs with dropdowns. Applied to every brand/model/search URL:

```json
{
  "startUrls": ["https://www.chrono24.com/omega/index.htm"],
  "priceFrom": 2000,
  "priceTo": 8000,
  "caseMaterials": ["steel"],
  "movementTypes": ["automatic"],
  "condition": ["new"],
  "sortorder": "price descending"
}
```

**2. Paste a filtered browser URL.** Filter and sort on chrono24.com, copy the URL, drop it in `startUrls`. Price, year, condition, movement, materials, location and sort are read straight from the query string:

```
https://www.chrono24.com/rolex/index.htm?priceFrom=5000&priceTo=15000&sortorder=1
```

**3. Advanced: `searchParams`** — a JSON passthrough for any Chrono24 search param not covered by the form fields. Values accept **plain words** (resolved to Chrono24 ids automatically) or raw ids:

```json
{
  "startUrls": ["https://www.chrono24.com/omega/index.htm"],
  "searchParams": {
    "braceletMaterial": "leather",
    "functions": ["chronograph", "date"],
    "waterproof": "10 atm",
    "specials": "watch with original box and original papers"
  }
}
```

Common filters (friendly values shown):

| Param | Accepts |
|---|---|
| `priceFrom`, `priceTo` | numbers (in `SETCURR`, default USD) |
| `year` | production year, e.g. `2020` |
| `usedOrNew` | `"new"`, `"used"` |
| `condition` | `"new"`, `"like new & unworn"`, `"very good"`, `"good"`, … |
| `movementTypes` | `"automatic"`, `"manual winding"`, `"quartz"` |
| `caseMaterials` | `"steel"`, `"yellow gold"`, `"rose gold"`, `"platinum"`, `"titanium"`, `"ceramic"`, … |
| `dialColor` | `"black"`, `"blue"`, `"green"`, `"meteorite"`, … |
| `braceletMaterial` | `"steel"`, `"leather"`, `"rubber"`, … |
| `gender` | `"men"`, `"women"` |
| `sellerType` | `"professional dealer"`, `"private sellers"`, `"chrono24 direct"` |
| `countryIds` | `"Germany"`, `"United States of America"`, … (or ISO codes `DE`, `US`) |
| `sortorder` | `"relevance"`, `"price ascending"`, `"price descending"`, `"newest"`, `"popularity"` |

Unrecognised labels are passed through unchanged and logged, so you can always use a raw Chrono24 id directly.

***

### Output overview

Two row shapes, set by the `rowType` field:

- **`detail`** — emitted for detail URLs and (when `fetchListingDetails: true`) for every listing found via brand/model/search. Carries the full spec sheet.
- **`card`** — emitted for listings on brand/model/search pages when `fetchListingDetails: false`. ~15 fields straight from the search response.

All rows include `listingId`, `listingUrl`, `price`, `currency`, `images[]`, and `scrapedAt`.

***

### Output samples

#### `rowType: "detail"` (real sample, abridged)

```jsonc
{
  "rowType":          "detail",
  "listingId":        "45070783",
  "productId":        1122,
  "listingUrl":       "https://www.chrono24.com/rolex/rolex-lady-datejust--id45070783.htm",
  "title":            "Rolex Lady-Datejust",
  "subtitle":         "26 mm Bronze Diamond Dial Oyster Watch 6916 circa 1981",
  "brand":            "Rolex",
  "brandId":          221,
  "model":            "Lady-Datejust",
  "modelId":          53,
  "referenceNumber":  "6916",
  "price":            3299,
  "currency":         "USD",
  "priceNegotiable":  false,
  "conditionNew":     false,
  "availabilityText": "Item is in stock",
  "country":          "United States of America",
  "sellerType":       "Dealer",
  "sellerCountry":    "United States of America",
  "sellerMemberSince": 2018,
  "specs": {
    "referencenumber": "6916",
    "casediameter":    "26 mm",
    "year":            "1981",
    "condition":       "Used (very good)",
    "movementtype":    "Automatic",
    "caliber":         "2030",
    "powerreserve":    "42 h",
    "jewelnumber":     "26",
    "casematerial":    "Steel",
    "bezelmaterial":   "Steel",
    "glass":           "Plexiglass",
    "dialcolor":       "Bronze",
    "braceletmaterial":"Steel",
    "clasp":           "Fold clasp",
    "gender":          "Women's watch"
    // …20+ more spec_* fields, flattened when flatten=true
  },
  "images":    ["https://img.chrono24.com/images/uhren/45070783-%E2%80%A6-ExtraLarge.jpg", "…"],
  "thumbnail": "https://img.chrono24.com/images/uhren/45070783-%E2%80%A6-ExtraLarge.jpg",
  "sourceUrl": "https://www.chrono24.com/rolex/rolex-lady-datejust--id45070783.htm",
  "scrapedAt": "2026-06-02T…"
}
```

#### `rowType: "card"` (real sample — `fetchListingDetails: false`)

```jsonc
{
  "rowType":       "card",
  "listingId":     "46108138",
  "listingUrl":    "https://www.chrono24.com/omega/seamaster-diver--id46108138.htm",
  "title":         "Omega Seamaster Diver 300 M",
  "subtitle":      "Blue No Wave Dial Complete Set",
  "price":         4250,
  "currency":      "USD",
  "shippingCost":  300,
  "countryCode":   "US",
  "countryName":   "United States of America",
  "sellerType":    "Dealer",
  "stockInfo":     "InStock",
  "thumbnail":     "https://img.chrono24.com/images/uhren/46108138-%E2%80%A6-Square420.jpg",
  "images":        ["…", "…"],
  "sourceUrl":     "https://www.chrono24.com/omega/index.htm",
  "scrapedAt":     "2026-06-02T…"
}
```

***

### Key output fields

**Identity** — `listingId` (primary key), `referenceNumber` (best join key vs external watch DBs), `brand` + `model`, `productId`.

**Price** — `price` (numeric), `currency` (ISO 4217), `priceNegotiable`, `shippingCost`.

**Watch specs** (`specs_*` when flattened) — `year`, `condition`, `movementtype`, `caliber`, `powerreserve`, `jewelnumber`, `casediameter`, `casematerial`, `bezelmaterial`, `glass`, `dialcolor`, `braceletmaterial`, `clasp`, `lugwidth`, `gender`, `functions`, `waterresistance`, `scopeofdelivery`.

**Commerce** — `availabilityText`, `country`, `conditionNew`, `sellerType`, `sellerCountry`, `sellerMemberSince`.

**Media** — `images[]` (full resolution), `thumbnail`.

***

### FAQ

**Does this need a Cloudflare-bypass service or premium residential proxy?**
No. The actor uses Chrono24's mobile JSON API (`chrono24.app`), which is not behind Cloudflare's challenge. Any proxy works — datacenter (cheapest), any residential pool, or none for light use. This is the key difference from website scrapers, which hit Cloudflare on every request.

**How does it authenticate?**
It replicates the Chrono24 mobile app's request signing: a one-time session handshake plus a per-request HMAC signature header. You don't configure anything — it's automatic.

**Detail mode vs card mode?**
Detail mode (`fetchListingDetails: true`, default) costs one extra API call per listing but returns 40+ fields including caliber, materials, seller, and full description. Card mode skips the per-listing call and returns ~15 fields straight from the search response — 50 listings per request, much faster and cheaper.

**How do I scrape multiple brands or models in one run?**
Paste them all in `startUrls[]`. Mix brand pages, model pages, search queries, and individual listing URLs freely.

**Can I get the full image gallery?**
Yes. Detail rows return every photo at full (`ExtraLarge`) resolution; card rows return the gallery at `Square420`.

**Is currency normalised?**
No, by design. `price` is in the listing's native currency (`currency`). Normalise downstream against your own reference date.

**What about pagination?**
Brand/model/search URLs auto-paginate (50 listings/page) up to `maxIndexPages` or until `maxItems` is reached. A single Rolex brand page exposes 114,000+ listings across ~2,290 pages.

**How fresh is the data?**
Real-time — every run hits the live API.

***

### Support

- **Bug reports & feature requests** — open an issue on the actor's Apify page or email below.
- **Custom scraper builds** — see Additional Services.
- **Email** — `info@apifyscraper.com`

***

### Additional services

Need a custom watch-marketplace scraper (Bezel, WatchCharts, Hodinkee Shop, eBay watches), or this one extended with price-history reconstruction, seller-reputation enrichment, or image OCR for serial numbers? Reach out — most custom builds ship in 3-5 business days at fixed scope.

***

### Explore more scrapers

- [SoundCloud Scraper — Tracks, Artists, Playlists, Search & Bio Emails](https://apify.com/memo23/soundcloud-scraper)
- [TrustRadius Software Reviews Scraper](https://apify.com/memo23/trustradius-scraper)
- [Capterra Software & Reviews Scraper](https://apify.com/memo23/capterra-scraper)
- [TotalJobs UK Jobs Scraper](https://apify.com/memo23/totaljobs-scraper)
- [Pinterest Pins & Boards Scraper](https://apify.com/memo23/pinterest-scraper)

***

### 🤖 For AI Agents & LLM Apps

Compact reference for AI agents calling this actor via the [Apify MCP server](https://mcp.apify.com) or the Apify API (actor: `memo23/chrono24-scraper`).

**Purpose:** Scrapes Chrono24 luxury-watch listings from detail, model, brand, or search URLs via Chrono24's mobile JSON API and returns a 40+ field spec sheet per watch — no Cloudflare, no browser, any proxy.

**Minimal input:**

```json
{
  "startUrls": ["https://www.chrono24.com/rolex/daytona--mod2.htm"],
  "maxItems": 50
}
```

`startUrls` is required and the only entry point (no keyword search field). Detail, model page, brand page, and search URLs are auto-classified and can be mixed in one array. All other inputs are optional filters: `priceFrom`, `priceTo`, `year`, `usedOrNew`, `condition`, `movementTypes`, `caseMaterials`, `dialColor`, `gender`, `sellerType`, `countryIds`, `sortorder`, `searchParams` (JSON passthrough), `fetchListingDetails`, `maxIndexPages`, `flatten`, `includeRaw`, `maxConcurrency`, `minConcurrency`, `maxRequestRetries`, `proxy`.

**Output:** one dataset row per listing — `listingId`, `referenceNumber`, `brand`, `model`, `productId`, `price`, `currency`, `priceNegotiable`, `shippingCost`, `specs_*` (year, condition, movementtype, caliber, powerreserve, jewelnumber, casediameter, casematerial, bezelmaterial, glass, dialcolor, braceletmaterial, clasp, lugwidth, gender, functions, waterresistance, scopeofdelivery), `availabilityText`, `country`, `sellerType`, `sellerCountry`, `sellerMemberSince`, `images[]`, `thumbnail`.

**Behaviors an agent should know:**

- Always set `maxItems` — a single brand URL (e.g. Rolex) exposes 114,000+ listings across ~2,290 pages (50 per page). Brand/model/search URLs paginate up to `maxIndexPages` per URL.
- URL filters are honoured, and the filter fields stack on top of them; filters apply to brand/model/search URLs only — direct detail URLs ignore them.
- `fetchListingDetails` (default true) makes one extra API call per listing for the full 40+ field spec sheet; set false for fast card mode (~15 fields, 50 listings per request). `flatten` (default true) flattens `specs` into `specs_*` columns; `includeRaw` attaches the raw payload as `rawJson`.
- The actor routes through its own built-in residential proxy at no extra cost — leave `proxy` empty.
- Pay-per-event billing — see the Pricing tab on the actor page.

***

### ⚠️ Disclaimer

This Actor accesses publicly available data on Chrono24 for legitimate research, market intelligence, dealer-side competitive analysis, valuation, and personal-collection management purposes. Use of this Actor must comply with Chrono24 GmbH's Terms of Service and all applicable laws including data protection regulations (GDPR, CCPA, etc.). The Actor's authors are not affiliated with, endorsed by, or sponsored by Chrono24 GmbH. The "Chrono24" name and logo are trademarks of Chrono24 GmbH. Users must:

- Respect rate limits and avoid overloading Chrono24's infrastructure (the default concurrency with per-request proxy rotation is calibrated to stay well below any reasonable threshold).
- Not use scraped data to impersonate or defraud Chrono24 dealers or buyers.
- Use the data in compliance with applicable jurisdictions, especially around resale of personal data from seller pages.
- Not republish scraped images or copyrighted listing copy without permission from the original seller.

We do not store any scraped data; the Actor returns it directly to your Apify dataset for your authorized use.

***

### SEO Keywords

chrono24 scraper, chrono24 watch scraper, chrono24 listings scraper, chrono24 api, chrono24 api alternative, chrono24 data extraction, chrono24 bulk export, luxury watch scraper, rolex price scraper, omega listings scraper, patek philippe price tracker, watch marketplace scraper, watch arbitrage scraper, watch dealer inventory scraper, watch price tracker, watch market intelligence, reference number lookup, watch specs api, mobile api scraper, no-browser scraper, chrono24 json export, chrono24 csv export, web scraping, apify scraper

# Actor input Schema

## `startUrls` (type: `array`):

Full chrono24.com URLs to scrape. Brand/model/search URLs paginate automatically (50 listings per page) up to `Maximum index pages` per URL, until `Maximum items` is reached.

## `priceFrom` (type: `integer`):

Minimum price in USD. Leave empty for no lower bound.

## `priceTo` (type: `integer`):

Maximum price in USD. Leave empty for no upper bound.

## `year` (type: `integer`):

Only listings produced in this exact year (e.g. 2020).

## `usedOrNew` (type: `string`):

Restrict to brand-new/unworn or pre-owned watches.

## `condition` (type: `array`):

One or more condition grades. Leave empty for all.

## `movementTypes` (type: `array`):

One or more movement types. Leave empty for all.

## `caseMaterials` (type: `array`):

One or more case materials. Leave empty for all.

## `dialColor` (type: `array`):

One or more dial colors. Leave empty for all.

## `gender` (type: `string`):

Men's/unisex or women's watches.

## `sellerType` (type: `array`):

One or more seller types. Leave empty for all.

## `countryIds` (type: `array`):

Restrict to sellers located in these countries. Write country names ("Germany", "United States of America") or ISO codes ("DE", "US"). Leave empty for worldwide.

## `sortorder` (type: `string`):

How results are ordered before pagination — matters when `Maximum items` cuts the run short (e.g. sort by price ascending to get the cheapest listings first).

## `searchParams` (type: `object`):

Power-user passthrough for any Chrono24 search param not covered by the fields above (e.g. `braceletMaterial`, `waterproof`, `functions`, `specials`, `caseDiameter`, `listingType`). Keys are Chrono24 search params; values may be scalars or arrays, and human labels are resolved to Chrono24 ids automatically. Overrides the fields above on conflict.

Example: { "braceletMaterial": "leather", "functions": \["chronograph", "date"], "specials": "watch with original box and original papers" }

## `fetchListingDetails` (type: `boolean`):

When enabled (default), each listing found via a brand/model/search page triggers a follow-up detail call to harvest the full mobile-API spec sheet (reference, year, movement, caliber, power reserve, jewels, case/dial/bracelet specs, seller, description — 40+ fields). Disable for fast card mode (~15 fields straight from the search response, 50 listings per request, no per-listing fetch).

## `maxIndexPages` (type: `integer`):

How many pages of search results to walk per brand/model/search input URL. The API serves 50 listings per page, so 10 pages = up to 500 listings per input URL. Detail URLs ignore this setting.

## `flatten` (type: `boolean`):

When enabled (default), the nested `specs` object is flattened to `specs_*` top-level columns (e.g. `specs_caliber`, `specs_casediameter`) and arrays-of-objects become JSON-stringified `*_json` fields. Disable to keep the raw nested shape.

## `includeRaw` (type: `boolean`):

When enabled, the raw detail-API payload is attached as a `rawJson` field on every detail row. Useful for accessing fields the actor doesn't surface explicitly. Off by default to keep rows small.

## `maxItems` (type: `integer`):

Hard cap on the number of rows emitted. A single detail URL emits 1 row. A brand/model/search URL fans out to 50 rows per page × however many pages the actor walks.

## `maxConcurrency` (type: `integer`):

Maximum number of detail fetches processed in parallel. 6-10 is the sweet spot.

## `minConcurrency` (type: `integer`):

Minimum number of detail fetches processed in parallel.

## `maxRequestRetries` (type: `integer`):

Number of retries per search page before giving up. Each retry rotates to a fresh sticky proxy session (new IP + new Chrono24 cookies) and re-runs the consent/warm-up handshake.

## `proxy` (type: `object`):

Leave empty — the actor already routes all traffic through its own built-in residential proxy at no extra cost to you. Only set this if you want to use your own proxies.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.chrono24.com/rolex/daytona--mod2.htm",
    "https://www.chrono24.com/omega/index.htm",
    "https://www.chrono24.com/rolex/rolex-lady-datejust--id45070783.htm",
    "https://www.chrono24.com/search/index.htm?query=patek+nautilus"
  ],
  "fetchListingDetails": true,
  "maxIndexPages": 10,
  "flatten": true,
  "includeRaw": false,
  "maxItems": 1000,
  "maxConcurrency": 6,
  "minConcurrency": 1,
  "maxRequestRetries": 3
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        "https://www.chrono24.com/rolex/daytona--mod2.htm",
        "https://www.chrono24.com/omega/index.htm",
        "https://www.chrono24.com/rolex/rolex-lady-datejust--id45070783.htm",
        "https://www.chrono24.com/search/index.htm?query=patek+nautilus"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/chrono24-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "startUrls": [
        "https://www.chrono24.com/rolex/daytona--mod2.htm",
        "https://www.chrono24.com/omega/index.htm",
        "https://www.chrono24.com/rolex/rolex-lady-datejust--id45070783.htm",
        "https://www.chrono24.com/search/index.htm?query=patek+nautilus",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("memo23/chrono24-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    "https://www.chrono24.com/rolex/daytona--mod2.htm",
    "https://www.chrono24.com/omega/index.htm",
    "https://www.chrono24.com/rolex/rolex-lady-datejust--id45070783.htm",
    "https://www.chrono24.com/search/index.htm?query=patek+nautilus"
  ]
}' |
apify call memo23/chrono24-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,memo23/chrono24-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/R16QZrhnVcm6C4A6u/builds/2PYfdzXJIPeDfB2nV/openapi.json
