# Catawiki Scraper & Auction Price Monitor (`olliolli/catawiki-prices`) Actor

Monitor Catawiki auction bids, sold lots and price changes. Export structured lot details; pay for new or changed observations, with unchanged lots free in monitor mode. Public pages, no login or bidding.

- **URL**: https://apify.com/olliolli/catawiki-prices.md
- **Developed by:** [Tom J](https://apify.com/olliolli) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 lot observations

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Catawiki Scraper & Auction Price Monitor

Track **Catawiki auction prices, current bids and sold lots** without checking every object by hand. This Catawiki scraper accepts keywords, category pages, auction URLs and individual lot links. Export structured observations to CSV, Excel or JSON, or keep a watch running: new lots and actual changes are delivered, while unchanged observations are free of result charges in monitor mode.

Built for collectors, dealers and auction researchers who need to distinguish a live bid from a confirmed final bid. It reads public pages without a Catawiki account and never bids or buys.

### Start with a small watch

```json
{
  "searchQueries": ["rolex"],
  "mode": "monitor",
  "stateName": "my-rolex-watch",
  "maxItems": 20,
  "maxPages": 2,
  "maxKnownChecks": 10
}
```

Run again with the same `stateName` and locale to compare observations. Use a separate state name for each watchlist or customer. The default limits favour small, predictable runs. Set a maximum run cost in Apify as an additional guardrail.

For a known object, including a recently closed auction lot:

```json
{
  "startUrls": [{"url": "https://www.catawiki.com/en/l/107740761"}],
  "mode": "snapshot",
  "maxItems": 1
}
```

Example URLs can disappear or change status. Snapshot mode returns and charges each successful lot observation, including on repeated runs.

### What a price means

| Field | Meaning |
|---|---|
| `currentBid` | Displayed bid for an open lot; null after closure |
| `lastBid` | The displayed bid amount at observation time, including closed lots |
| `finalBid` | Set only when the public bidding data explicitly says **closed and sold** |
| `status` | `open`, `sold`, or `closed_unsold` |
| `currency` | Currency reported by the public page; no exchange-rate conversion |
| `reservePriceSet`, `reservePriceMet` | Published indicators when available; never the hidden reserve amount |
| `estimateLow`, `estimateHigh` | Published expert estimate in the reported currency, or null |
| `nextMinimumBid` | Next allowed bid shown for an open lot, when available |

**A bid is not the total purchase cost.** Buyer Protection fees, shipping and taxes are excluded. An estimate is not a valuation guarantee. A sold label records the site's auction outcome; it does not prove payment, delivery or the absence of a later cancellation. Closed but unsold objects never receive a fabricated final price.

Direct lot pages may omit the separate reserve-set indicator even when the catalogue exposes it. Missing data stays null. Some currency-specific estimates are not published. The source decides which currency it shows; this Actor does not promise EUR, GBP or USD conversion.

### Monitoring and price changes

The first successful observation of a lot produces a `lot` row. Subsequent runs produce a `change` row when supported fields change: bid, currency, closed/sold status, end time, reserve status, estimate, title, subtitle or specifications. `changeFields`, `previousValues` and observation timestamps show what changed. One changed observation receives one change event even if several fields changed.

Known open lots that have disappeared from current search pages can be revisited through their saved public lot URLs, up to `maxKnownChecks` and the overall `maxItems` limit. This helps capture closure. If search results fill the overall limit, there may be no room for those revisits; `uncheckedKnownLots` makes this visible. Narrow your search or increase the limits for a focused watch.

Disappearance, a 404 or a blocked page is **not** treated as a sale. Closed lots are not automatically revisited once absent from the supplied sources. Include their URLs explicitly to check later corrections. Monitoring records changes between observations, not every intermediate bid.

State is limited to 1,000 known lots per watch. It retains identifiers, public URLs, comparison fields and timestamps—not seller or bidder profiles. Changing queries while retaining a state name retains its existing tracked lots; use a fresh state name for a different watch. Concurrent runs of the same watch are guarded by a best-effort lease; schedule them sequentially. If delivery is interrupted mid-checkpoint, the run stops on restart instead of replaying a potentially billed row. Exactly-once delivery across external failures is not guaranteed.

### Inputs and limits

| Input | Default | Meaning |
|---|---|---|
| `searchQueries` | Rolex if no targets supplied | Up to 20 keywords and URLs combined |
| `startUrls` | Empty | Public `/s`, `/c`, `/a` or `/l` Catawiki URLs |
| `locale` | `en` | Generated query language: en, nl, fr, de, es, it or pt; pasted URLs retain theirs |
| `mode` | `monitor` | Deliver new/changed observations; `snapshot` delivers every successful observation |
| `stateName` | `catawiki-watch` | Reuse for the same watch; letters, digits, hyphens and underscores |
| `maxItems` | 20 | Maximum unique lots inspected across the run, including failed and known lots; 1–200 |
| `maxPages` | 2 | Catalogue pages per target; 1–10 |
| `maxKnownChecks` | 20 | Additional known-open-lot checks within the overall item limit; 0–100 |
| `maxRequests` | 100 | Public HTTP request cap, including redirects and recovery; 1–500 |
| `maxRunSeconds` | 150 | Working time limit; 30–240 seconds, with brief cleanup afterwards |
| `connection` | `auto` | Direct first, at most one datacenter recovery; `direct` and `datacenter` are explicit alternatives |

Targets are processed in the supplied order. A broad first query can consume the item limit before later targets are inspected. Copy public filtered URLs from Catawiki; supported query keys are `q`, `page`, `filters` and `sort`. Filtering and ordering remain source-defined. Unsupported URLs and parameters are rejected instead of silently changing their meaning.

### Output and coverage

Each row includes the lot ID and link, title/subtitle, price/status fields, auction/category IDs, public specifications, available images, timestamps and change metadata. Detailed lot observations are included in the result price; there is no separate detail surcharge.

`OUTPUT` reports `lotsChecked`, `lotsDelivered`, `changesDelivered`, `unchangedLots`, `failedLots`, `sources`, `partial`, `stopped`, `warnings`, `uncheckedKnownLots`, `requests`, `connectionAttempts`, `recoveryEvents` and `chargedEvents`.

Do not rely only on a green run status. A run can contain useful data and still be partial due to item, page, time, state or request limits. Source `complete` describes the supplied catalogue coverage; lot-detail failures are separately counted in `failedLots` and `warnings`. A structured no-match search is different from a blocked or unrecognized page. Catawiki sometimes fills an empty search with recommendations; those are dropped and counted in `fallbackLotsDropped`.

This is a bounded watch, not a full historical sales database. Catawiki does not provide a complete searchable archive of sold lots through these pages. Use known lot/auction links while they remain publicly available, and schedule observations near closure. Very old or removed objects can return not found. Search rankings, catalogue counts and live bids may change during a run.

### Pricing

| Event | Price | When charged |
|---|---:|---|
| `lot` | $0.0025 | A delivered new lot in monitor mode, or a delivered snapshot |
| `change` | $0.0015 | A delivered changed observation of a known lot |
| `apify-actor-start` | $0.00005 per allocated GB, minimum one | Standard start, including failed runs |

At the default memory, examples are:

- 20 new lots: **$0.05005**.
- 1,000 delivered new lots across five 200-lot runs: **$2.50025**.
- A later run with 10 changed observations: **$0.01505**.
- An entirely unchanged monitor run: the standard **$0.00005** start event only, with no result events.

Duplicates, failed lot lookups, dropped fallback recommendations and unchanged monitor observations receive no result charge. There is no automatic dataset-item event. A changed row receives only the change event, not a lot event as well. Check the live Pricing tab before running. When testing your own Actor, Apify's platform-cost cap can stop a run even when no result events are being charged.

### Scheduling and integrations

Create an Apify Task with your watch input, then schedule it at a suitable interval. Keep the same state name and avoid overlapping runs. Export the dataset or connect it to Google Sheets, Make, Zapier or n8n. Use OUTPUT to route partial or failed checks for review.

Via API, send the same input to:

```text
POST https://api.apify.com/v2/acts/olliolli~catawiki-prices/runs
Authorization: Bearer YOUR_APIFY_TOKEN
Content-Type: application/json
```

Read the returned run's dataset and OUTPUT after completion. Keep your Apify token secret.

### FAQ

**Can I find underpriced objects?** The Actor provides observations and available estimates for your own analysis. It does not establish authenticity, fair value, profitability or a guaranteed bargain.

**Why is there no row on a repeat run?** In monitor mode this can be expected for unchanged lots. Confirm `unchangedLots`, coverage and warnings before concluding nothing changed.

**Does it collect sellers or bidders?** It excludes dedicated seller, expert and bidder profile fields, contact fields and bid histories. Item titles/specifications may still name artists or contain identifying object information; this is not a guarantee of anonymization.

**Does it log in, bid or solve a CAPTCHA?** No. It uses anonymous public requests with browser-compatible transport. Lots whose public data flags an age check are excluded (including some alcohol lots). It stops on recognized login/challenge pages and does not endlessly rotate IPs. Availability can change.

**Why did a result change since my last visit?** Bids are live. Compare the observation timestamp and currency. Results describe what the public page returned at that time.

Independent product; not affiliated with or endorsed by Catawiki. See Catawiki's [reserve-price explanation](https://auction.catawiki.com/en/help/reserve-prices/i-d-like-to-place-a-bid-on-an-object-with-a-reserve-price-what-does-this-mean-and-how-do-i-know-what-the-reserve-price-is) and [Buyer Protection fee explanation](https://www.catawiki.com/en/help/fees/how-does-the-buyer-protection-fee-work) for the distinction between a bid, a sale and checkout costs.

# Actor input Schema

## `searchQueries` (type: `array`):

Keywords to monitor. At most 20 keywords and URLs combined.

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

Public HTTPS Catawiki search, category, auction and lot links. Targets run in the supplied order.

## `locale` (type: `string`):

Language for generated keyword searches; pasted URLs keep their language.

## `mode` (type: `string`):

Monitor skips unchanged observations; snapshot charges each successful observation.

## `stateName` (type: `string`):

Reuse for the same watch; use another name for a different watchlist.

## `connection` (type: `string`):

Auto tries direct, then at most one datacenter session if appropriate. No residential surcharge or unlimited rotation.

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

Overall unique lot-check cap, including known and failed lots.

## `maxPages` (type: `integer`):

Catalogue pages. Item and time limits can stop earlier.

## `maxKnownChecks` (type: `integer`):

Revisit known open lots missing from current results, within the overall item limit.

## `maxRequests` (type: `integer`):

Public request cap including redirects and recovery.

## `maxRunSeconds` (type: `integer`):

Maximum working seconds; allow additional time for cleanup in run options.

## Actor input object example

```json
{
  "searchQueries": [
    "rolex"
  ],
  "locale": "en",
  "mode": "monitor",
  "stateName": "catawiki-watch",
  "connection": "auto",
  "maxItems": 20,
  "maxPages": 2,
  "maxKnownChecks": 20,
  "maxRequests": 100,
  "maxRunSeconds": 150
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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 = {
    "searchQueries": [
        "rolex"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("olliolli/catawiki-prices").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 = { "searchQueries": ["rolex"] }

# Run the Actor and wait for it to finish
run = client.actor("olliolli/catawiki-prices").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 '{
  "searchQueries": [
    "rolex"
  ]
}' |
apify call olliolli/catawiki-prices --silent --output-dataset

```

## MCP server setup

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

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/n9CARwvIYmhA7EBlO/builds/Gxj2cO7ByC7v9g30G/openapi.json
