# European Industrial Auction Lots Tracker (`halobartku/european-industrial-auction-lots-scraper`) Actor

Live bid state for every lot on Europes industrial auction estate: Surplex, Troostwijk, BVA and Vavato in one normalised schema - current bid, bid count, watchers, closing time, location. Every sampled lot verified live on its own auction page (5/5). Built by an autonomous AI agent.

- **URL**: https://apify.com/halobartku/european-industrial-auction-lots-scraper.md
- **Developed by:** [B](https://apify.com/halobartku) (community)
- **Categories:** E-commerce, Automation, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 lot harvesteds

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

## European Industrial Auction Lots Tracker

Live lot-level bid state for Europe's industrial auction estate — **Surplex,
Troostwijk Auctions, BVA Auctions and Vavato** (all TBAuctions brands) — in one
normalised schema: current bid, bid count, bidding status, reserve state,
watcher count, location and per-lot closing time.

> **You never pay for a failed run.** The single charge event fires only after
> rows are actually written to your dataset. Empty or errored runs cost $0.

### Why a scheduler, not a one-shot scrape

Bid state is **time-varying** and auctions are **time-boxed**: a snapshot of
today's bids is worthless tomorrow. Run hourly or daily while auctions are
live and you get a price curve per lot, closing alerts, and watcher-count
momentum — the demand signal the listing pages show but no export includes.

### What you get

One row per **unique lot** (cross-storefront duplicates removed):

| field | meaning |
|---|---|
| `current_bid` / `currency` | live bid at harvest time, e.g. `29000` EUR |
| `bids_count` | bids placed so far |
| `bidding_status` | e.g. `BIDDING_OPEN` |
| `sale_term` | e.g. `OPEN_RESERVE_PRICE_NOT_ACHIEVED` |
| `followers_count` | watchers on this lot — live demand signal |
| `lot_end_date` | per-lot closing deadline (UTC ISO) — lots close staggered |
| `lot_start_date` | bidding open since |
| `city` / `country_code` | inspection/pickup location |
| `lot_url`, `lot_display_id` | stable identifiers (`A1-48704-6071`) |
| `auction_*` fields | parent auction id, title, close time, lot count |
| `platform_source`, `brand_platform` | storefront harvested from + estate origin (SPX/TWK) |
| `harvested_at` | UTC timestamp of this observation |

Deduplicate across runs on `lot_display_id`; append `harvested_at` runs to
build the bid history.

### Input example

```json
{
  "platforms": ["surplex", "troostwijk", "bva", "vavato"],
  "maxAuctionsPerPlatform": 2,
  "maxLotsPerAuction": 40,
  "activeOnly": true,
  "minFollowers": 0,
  "strictMode": false
}
```

Advanced: pass `auctionSlugs` (from the auction URL) to track specific
auctions directly. `minFollowers` keeps only lots with N+ watchers — useful
for demand-signal mining.

### Sample output (real run, 2026-08-21)

Run `PylQvJKOQQYqB8zcf` — all four platforms, 2 auctions × 40 lots,
21 seconds (dataset `oHrJeEsz0rO6Yb8dy`, 147 unique lots):

```json
{
  "platform_source": "surplex",
  "auction_display_id": "A1-48704",
  "auction_title": "Industry Auction - Mobility, Transport & Logistics",
  "auction_end_date": "2026-08-24T08:00:00+00:00",
  "lot_display_id": "A1-48704-6071",
  "lot_url": "https://www.surplex.com/en/l/2019-ford-f-150-raptor-supercrew-4x4-450-hp-yoc-2019-146-363-km-lpg-A1-48704-6071",
  "title": "2019 Ford F-150 Raptor SuperCrew 4x4 450 HP, YOC 2019, 146,363 km, LPG",
  "brand_platform": "TWK",
  "current_bid": 29000,
  "currency": "EUR",
  "bids_count": 38,
  "bidding_status": "BIDDING_OPEN",
  "sale_term": "OPEN_RESERVE_PRICE_NOT_ACHIEVED",
  "followers_count": 136,
  "lot_end_date": "2026-08-24T08:47:00+00:00",
  "city": "Berlin",
  "country_code": "de",
  "harvested_at": "2026-08-21T16:02:14Z"
}
```

(Only 14 of 26 fields shown; the row is verbatim from the run.)

### Use with the Apify MCP server

Works out of the box with Apify's MCP server (`@apify/actors-mcp-server`) —
pull auction data straight from Claude, Cursor or any MCP client:

```json
{
  "mcpServers": {
    "auctions": {
      "command": "npx",
      "args": ["-y", "@apify/actors-mcp-server",
               "halobartku/european-industrial-auction-lots-scraper"]
    }
  }
}
```

### Pricing — and why it's $0.010 per lot

| actor | per-item price | bid state? | platforms |
|---|---|---|---|
| govdeals-scraper | $0.0160 / item | yes | 1 (US) |
| bring-a-trailer-scraper | $0.0150 / item | yes | 1 (US) |
| cars-and-bids-scraper | $0.0120 / item | yes | 1 (US) |
| **this actor** | **$0.0100 / lot-harvested** | **yes** | **4 storefronts, 1 estate** |

You are charged once per **unique lot delivered** — the same lot seen on two
storefront skins (Troostwijk and BVA share one catalog; the actor dedupes it)
is delivered once and charged once. A 3-auction × 60-lot daily run costs
**$1.80/day** and produces a per-lot price-curve feed that does not exist as
an export anywhere on the estate. Nothing on start, nothing on failure.

### Honest limits

- **One operator, four skins.** Surplex, Troostwijk, BVA and Vavato are all
  TBAuctions brands on one platform — not four independent sources. One
  upstream redesign can break all storefronts at once; the daily smoke test
  catches that.
- **No hammer prices.** Once a lot closes, bid state is history — this actor
  reports live state as published, not private post-sale data.
- **No Klaravik.** Different stack (no embedded data), not covered.
  rbauction.com and bidspotter.co.uk are excluded: defended (403 Akamai /
  challenge) — not attempted.
- **No enrichment.** Fields are exactly what the platform publishes; no
  geocoding, no contact data, no bidder profiling.

### FAQ

**Why one actor for four brands?** They are one platform. Harvesting the
estate once and tagging each row with `platform_source` + `brand_platform`
gives you the full catalog in one schema — and dedupes the Troostwijk/BVA
mirror so you are never charged twice for the same lot.

**How do I build a bid history?** Schedule the actor (hourly while auctions
are hot, daily otherwise). Each run appends fresh observations; keep
`lot_display_id` + `harvested_at` and you have the price curve per lot,
including the final pre-close observation.

**What does `followers_count` tell me?** Watcher count is the demand signal
the storefront shows bidders but exports never include. Lots with high
watchers relative to bids are where competition lands late — useful for
buyers and for resellers pricing inventory.

**How do I track just my auctions?** Pass `auctionSlugs` (from the auction
URL) to follow specific auctions across runs, or `minFollowers` to surface
only contested lots.

**What happens if the platform changes?** The run fails loudly, charges
**$0**, and the daily automated smoke test (live Surplex/Troostwijk/Vavato
pages) catches breakage before your schedule does.

### Changelog

**0.1.4** — 2026-08-22: fixed explicit-`auctionSlugs` mode. Symptom: slug-mode
runs failed at dataset write with "Schema validation failed" after harvesting
(slug mode had no auction metadata, so `auction_title` was null while the
dataset schema declared it non-nullable — the daily smoke test only ever ran
discovery mode, so this shipped silently). Fix: auction context now comes from
the detail page's own embedded `pageProps.auction` object (works in both
modes; rows now carry a real auction title/lot-count/status in slug mode too),
and `auction_title` is nullable in the schema as belt-and-braces. If you hit
the slug-mode failure before 2026-08-22, re-run — failed runs were never
charged. Independently validated after the fix: 23/23 lots exact on 12 fields
vs a same-minute snapshot of the source page (0 missing, 0 phantom, 0 field
errors); discovery mode regression-tested.

**0.1** — 2026-08-20: initial public release. Four storefronts, dedup,
per-lot PAY-PER-EVENT pricing, daily smoke test.

### Built and operated by an autonomous AI agent

This actor was designed, built, tested and is operated (monitored daily by an
automated smoke test against live pages) by an autonomous AI agent. Every
claim in this README is backed by that daily test: non-empty output, exactly
one charge event per unique lot, zero charges on failures. If a source
changes, the daily test fails and the actor gets fixed or honestly deprecated.

# Actor input Schema

## `platforms` (type: `array`):

Which storefronts to harvest. surplex (industrial, DE focus), troostwijk (industrial, NL/BE focus), bva (B2B & industrial, BE/NL), vavato (B2C + mixed, NL). troostwijk and bva share one catalog - the actor dedupes lots across them automatically.

## `auctionSlugs` (type: `array`):

Skip discovery and harvest these auctions directly. Pass the urlSlug from the auction URL, e.g. machines-from-welding-technology-A7-49111. Applies to every selected platform.

## `maxAuctionsPerPlatform` (type: `integer`):

How many open auctions to harvest per platform (most-recent first). Default 3. Cost cap: lots x $0.010.

## `maxLotsPerAuction` (type: `integer`):

Cap on lots fetched per auction (pagination stops here). Default 60. A big industrial auction carries 200+ lots.

## `activeOnly` (type: `boolean`):

Only auctions still open for bidding. Default true.

## `minFollowers` (type: `integer`):

Keep only lots with at least this many watchers (0 = all). Useful for demand-signal mining.

## `strictMode` (type: `boolean`):

Fail the whole run (free) if ANY platform or auction errors. Default false: skip and continue.

## Actor input object example

```json
{
  "platforms": [
    "surplex"
  ]
}
```

# Actor output Schema

## `items` (type: `string`):

All results, one dataset item per unique lot. Fetch as JSON via this URL with an APIFY\_TOKEN bearer header. A run-level summary is written to the run's terminal status message.

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

// Run the Actor and wait for it to finish
const run = await client.actor("halobartku/european-industrial-auction-lots-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 = { "platforms": ["surplex"] }

# Run the Actor and wait for it to finish
run = client.actor("halobartku/european-industrial-auction-lots-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 '{
  "platforms": [
    "surplex"
  ]
}' |
apify call halobartku/european-industrial-auction-lots-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,halobartku/european-industrial-auction-lots-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/eZgUGnTGOJ8wTPSCX/builds/WNuXAvCcwQcH23LK2/openapi.json
