# AuctionZip Auctioneer Directory Scraper — Leads + Auctions (`scrapersdelight/auctionzip-scraper`) Actor

Scrape the AuctionZip auctioneer directory into US auction-house leads: company, contact name, street address, city/state/ZIP, phone, email, website, bio — plus each auctioneer's upcoming auction calendar (title, date, town, listing URL). Filter by state. No login.

- **URL**: https://apify.com/scrapersdelight/auctionzip-scraper.md
- **Developed by:** [Scrapers Delight](https://apify.com/scrapersdelight) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 auctioneer scrapeds

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

## AuctionZip Auctioneer Directory Scraper — US Auction-House Leads + Their Auction Calendar

Turn the [AuctionZip](https://www.auctionzip.com) auctioneer directory into a clean US
auction-house lead list. One row per auctioneer: **companyName, contactName, streetAddress,
city, state, zipCode, phone, email, website, bio, licenseNumber** — and that auctioneer's
**upcoming auction calendar nested on the row** (title, ISO sale date, town, blurb, listing
URL, photo). **100% of rows carry a phone number, a full street address and a ZIP** — measured
on 100 live profiles, not estimated. No login. No CAPTCHA solving.

**Scope: 5,013 auctioneers in the whole directory** — counted live by walking all 27 index
pages on 2026-08-15, not quoted off a marketing page. **1,893 of them (37.8%) have at least
one auction on the calendar right now**, and the Actor filters to those by default.

```json
{
  "states": [],
  "onlyWithUpcomingAuctions": true,
  "maxAuctioneers": 100,
  "includeAuctionDetails": false,
  "requestConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "US"
  }
}
```

Click **Try for free** and hit **Start** — that block is literally the input the Actor ships
with. A run on those shipped defaults returned **100 auctioneers carrying 377 upcoming
auctions in 1 minute 10 seconds**, with phone 100%, contactName 100%, city/ZIP 100%,
streetAddress 99%, email 86% and website 85%. It costs **$0.30**.

***

### The wedge: the auctioneer, not just the auction

Every other auction scraper on the Store — including our own hibid, proxibid, estatesales.net,
auctionninja and maxsold Actors — returns **auctions and lots**. This one returns **the
businesses running them**, with a direct phone number and a named human on every single row,
and the auctions hanging off that row as context.

That inverts who you can sell to:

| You are | What you do with a row |
|---|---|
| Auction-software / online-bidding platform | 5,013 named US auction houses with phone + email = your entire addressable market, and `upcomingAuctionCount` tells you which ones are actually active |
| Estate-sale & auction aggregator | Seed your directory with the auctioneer *and* their live calendar in one pull |
| Antique / collectibles reseller | Filter to a state, get the auctioneers near you and every sale they have coming up |
| Liquidator, appraiser, shipping/logistics vendor | Sell services to auction houses that are provably running sales this month |
| Auctioneer-association / trade media | A current, deduped roster with contact details |

`upcomingAuctionCount` is the qualification signal: an auctioneer with 7 sales on the calendar
is a live business, one with 0 may be dormant. The directory index publishes that count, so
the Actor filters on it **before** spending a request (and before charging you) on the profile.

***

### Measured field fill — read this before you buy

Measured on the **100 rows the shipped default input returned** on 2026-08-15. Sorted
descending; **sparse fields are bold** so you know what you are and are not getting.

| Field | Fill | Note |
|---|---|---|
| `companyName` | 100% | the auction business |
| `contactName` | 100% | a named human, e.g. "Jed Acker" |
| `phone` | 100% | as published, e.g. `330-749-6248` |
| `city`, `state`, `zipCode` | 100% | parsed apart from the raw locality line |
| `fullAddress` | 100% | the site's own single-line address |
| `auctioneerId` | 100% | AuctionZip's public auctioneer number |
| `upcomingAuctions` | 100% | because the default filters to auctioneers who have some |
| `streetAddress` | 99% | |
| **`email`** | **87%** | a real published mailbox, not a contact form. The other 13% is the site printing the label `Email:` with **no address behind it** — verified on the raw HTML, not inferred |
| **`website`** | **84%** | the site renders an unset website as a bare `http://`; the Actor emits `null` for those rather than a fake URL — verified on the raw HTML |
| **`bio`** | **53%** | free-text self-description. The other 47% have the bio container on the page but **empty** (10 bytes of whitespace) — the auctioneer never wrote one |
| **`licenseNumber`** | **0% by default · 83% with `includeAuctionDetails: true`** | state licence, e.g. `6232`. It lives on the auction **listing** page, not the profile, so it is null unless you turn that option on |

Nested `upcomingAuctions[]`, measured on 367 auctions: `listingId`, `listingUrl`, `title`,
`dateText`, `year`, `location`, `description`, `imageUrl` all **100%**; `saleDate` **98.6%**
(the 5 misses are auctions the site itself lists as `Date TBA`).
`venueAddress` is **0% by default and 100% with `includeAuctionDetails: true`** — same reason as
`licenseNumber`: it only exists on the listing page.

Re-measured on 2026-08-19 across three live runs (100 rows on the shipped defaults, 12 rows with
`includeAuctionDetails: true`, 25 rows with `onlyWithUpcomingAuctions: false`).

`saleDate` is a real sortable timestamp (`2026-08-21T10:00:00`). AuctionZip prints the day and
time in one element and hides the **year in a separate element**, so a naive scrape of this
site gets year-less dates; this Actor joins the two before emitting.

#### What is deliberately NOT here

- **Individual lots.** This Actor stops at the auction level. Lot-by-lot catalogue data is a
  different record shape and belongs in a different Actor — merging the two would give you a
  dataset where half the rows are auctioneers and half are lots.
- **Auction category.** AuctionZip's own `Categories` attribute was **empty on every one of the
  35 listings measured**. It is not emitted rather than shipped as a permanently-null column.
  Category only exists on the site's category landing pages, not per listing.
- **Prices realized / bidding data.** Behind the login.

***

### How the anti-bot wall was beaten

AuctionZip is served by **CloudFront with an AWS WAF `challenge` rule**. This is worth stating
precisely, because a casual look at this site says it is wide open and it is not:

- A burned IP gets **HTTP 202 + `x-amzn-waf-action: challenge`** and a 2,243-byte
  `token.awswaf.com` interstitial (`gokuProps` + `challenge.js`). Not Cloudflare, not
  DataDome, not PerimeterX.
- **The bucket is exactly 6 requests per IP.** Requests 1-6 return 200; request 7 onward is
  challenged, and that IP then stays burned. Reproduced twice — once on profile pages, once on
  the A-Z directory pages. That is precisely why a quick probe of this site looks clean and a
  real crawl collapses on page 7.
- `robots.txt` is exempt and always answers 200.

The fix is the one that beat PagineGialle's AWS WAF: **lease each proxy IP for at most 4
requests, then rotate to a fresh session**, and give every concurrent worker its own lease so
parallel requests cannot secretly overshoot one IP's bucket. Measured **through Apify**:

| Transport | Result |
|---|---|
| Apify **RESIDENTIAL + US**, lease 4, concurrency 4 (**the shipped default**) | **40/40 = 100%**, all first try |
| Full shipped-default run, 102 fetches | **0 WAF challenges** |
| Apify datacenter (auto), lease 4, concurrency 4 | 30/30 rows, but ~15% of sessions burned and retried |
| Contiguous A-Z directory sweep, lease 4 | 27/27 = 100% |
| **One pinned session, no rotation** | **6/703 — burned at request 7** |

Datacenter works but its smaller IP pool keeps getting sessions burned, so the Actor ships on
residential and self-escalates to residential if you pick datacenter and it starts failing.

***

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `states` | array | `[]` (all) | USPS codes, e.g. `["OH","PA"]`. The three biggest are OH (598 auctioneers), PA (587), IN (391) |
| `onlyWithUpcomingAuctions` | boolean | `true` | Skip auctioneers with an empty calendar. Turn off to pull the whole 5,013-row directory as a flat lead list |
| `maxAuctioneers` | integer | `100` | Row cap — and your budget control, since you are charged per row |
| `includeAuctionDetails` | boolean | `false` | Open each auction's listing page to add `venueAddress` + `licenseNumber`. Slower, **does not change what you are charged** |
| `letters` | array | `[]` (all) | Advanced: which A-Z index pages to sweep (auctioneers are indexed by surname initial; `1` holds numeric names) |
| `profileUrls` | array | `[]` | Advanced: scrape only these profile URLs and skip the sweep entirely |
| `requestConcurrency` | integer | `4` | Drop to 2 if you ever see challenges in the log |
| `proxyConfiguration` | object | RESIDENTIAL, US | Required — the site is behind a WAF rate rule |

### Output

One row per auctioneer, upcoming auctions nested:

```json
{
  "profileId": "354407",
  "auctioneerId": "33491",
  "companyName": "Acker Auction Service",
  "contactName": "Jed Acker",
  "streetAddress": "8393 Millbrook Rd",
  "city": "Shreve",
  "state": "OH",
  "zipCode": "44676",
  "fullAddress": "8393 Millbrook Rd, Shreve,OH 44676",
  "phone": "330-749-6248",
  "email": "jed.acker@gmail.com",
  "website": "http://gant-realty.com/auctions-2/",
  "licenseNumber": null,
  "bio": null,
  "upcomingAuctionCount": 4,
  "upcomingAuctions": [
    {
      "listingId": "4165014",
      "listingUrl": "https://www.auctionzip.com/Listings/4165014.html",
      "title": "Wile Auction - Real Estate & Personal Property",
      "dateText": "Fri Aug 21 - 10:00AM - Wooster, OH",
      "year": "2026",
      "saleDate": "2026-08-21T10:00:00",
      "location": "Wooster, OH",
      "description": "WILE AUCTION 3 BEDROOM CUSTOM HOME & SHOP ON 2+ ACRES …",
      "imageUrl": "https://content.auctionzip.com/listing/4165014/pv",
      "venueAddress": "2608 Brenn Rd, Wooster, OH"
    }
  ],
  "profileUrl": "https://www.auctionzip.com/OH-Auctioneers/354407.html",
  "scrapedAt": "2026-08-15T15:41:02.118Z"
}
```

Export as JSON, CSV, Excel or XML, or pull it from the API.

### Pricing

**$3.00 per 1,000 auctioneers** ($0.003/row), pay-per-event, nothing else charged — no
per-run fee, no per-second compute fee.

You are billed **once per auctioneer row delivered**. Directory index pages are free. Auction
listing pages fetched by `includeAuctionDetails` are free. **A profile that every proxy session
failed to fetch is never billed**, and rows are deduplicated on the auctioneer's stable profile
id *before* billing — a run asserts 0% duplicates rather than hand you a dirty dataset. If you
set a maximum total charge on the run, the Actor trims the batch to what your budget covers
**before** delivering it, so rows delivered always equals rows billed in both directions.

- The shipped default (100 auctioneers) costs **$0.30**.
- Every auctioneer with a live auction (1,893) costs **$5.68**.
- The complete 5,013-auctioneer directory costs **$15.04**.

### Notes, limits and compliance

- **A run that returns nothing tells you why.** An empty dataset from a silently "successful" run
  is the canonical broken scraper, so this Actor ends with an explicit status message naming the
  cause — the WAF rate rule, a filter that matched nobody, or the run's charge limit — rather than
  handing you an unexplained empty file. A transient block is never turned into a failed run.
- **Run-time budget.** The Actor reads the run's own timeout and stops starting new page fetches a
  safety margin before it, then pushes everything already collected and exits successfully with a
  status message. A short timeout costs you rows it had not fetched yet — never rows it had.
  Measured: `maxAuctioneers: 10000` under a deliberately brutal 120-second run timeout returns a
  partial dataset instead of being killed.
- **`robots.txt`** (fetched 2026-08-15 from `https://www.auctionzip.com/robots.txt`) disallows
  exactly: `/cgi-bin/launcher.cgi`, `/cgi-bin/readinfo.cgi`, `/search`, `/search-results`,
  `/aboard`, `/my-account`, `/login`, `/bidNow`, `/cgi-bin/userpanel.cgi`,
  `/cgi-bin/azlogin.cgi`, `/cgi-bin/favpanel.cgi`, `/azThankYou.html`. Every route this Actor
  touches — `/Auctioneer-Directory/`, `/<ST>-Auctioneers/`, `/Listings/` — is outside that
  list, and the Actor never touches the disallowed search or account routes.
- **The calendar is a snapshot.** `upcomingAuctions` is whatever AuctionZip is showing at the
  moment of the run. Re-run on a schedule if you need it fresh.
- **Personal data.** Many auctioneers are sole traders, so `contactName`, `phone` and `email`
  can be personal data. You are the data controller for anything you collect: comply with
  AuctionZip's Terms of Service, and with GDPR/CCPA and applicable anti-spam law (CAN-SPAM,
  CASL) when you contact anyone. This Actor only reads pages that AuctionZip publishes to
  anonymous visitors and to search engines.

# Actor input Schema

## `states` (type: `array`):

Only return auctioneers based in these US states, e.g. OH, PA, TX. Leave empty for every state. The three biggest on AuctionZip are OH (598 auctioneers), PA (587) and IN (391).

## `onlyWithUpcomingAuctions` (type: `boolean`):

Skip auctioneers whose auction calendar is currently empty. 1,893 of the 5,013 listed auctioneers (37.8%) have at least one live auction. Turn this off to pull the whole directory as a plain lead list.

## `maxAuctioneers` (type: `integer`):

Stop after this many auctioneer rows. You are charged per row returned, so this is also your budget control. The whole directory is 5,013 auctioneers.

## `includeAuctionDetails` (type: `boolean`):

Open each upcoming auction's own listing page to add the auction VENUE address (where the sale actually happens, which differs from the auctioneer's office) and the auctioneer's state licence number. Costs one extra page fetch per auction, so the run is slower — it does NOT change what you are charged, you still pay per auctioneer row.

## `letters` (type: `array`):

Advanced. Which A-Z index pages of the auctioneer directory to sweep (auctioneers are indexed by surname initial; '1' holds the numeric names). Leave empty to sweep all of them.

## `profileUrls` (type: `array`):

Advanced. Scrape only these auctioneer profile URLs, e.g. https://www.auctionzip.com/PA-Auctioneers/6686.html. When set, the directory sweep and all filters above are skipped.

## `requestConcurrency` (type: `integer`):

Parallel page fetches. AuctionZip runs an AWS WAF rate rule that allows about 6 requests per IP, which this Actor handles by rotating its proxy session every 4 requests. Lower this to 2 if you still see challenges in the log.

## `proxyConfiguration` (type: `object`):

AuctionZip sits behind CloudFront + an AWS WAF rate rule that allows about 6 requests per IP, so a proxy is required. The shipped default â€” Apify RESIDENTIAL, country US â€” measured 40/40 requests with zero challenges. Apify datacenter also works because the Actor rotates its proxy session every 4 requests, but its smaller IP pool gets ~15% of sessions burned and retried; the Actor escalates itself to residential if that keeps happening.

## Actor input object example

```json
{
  "states": [],
  "onlyWithUpcomingAuctions": true,
  "maxAuctioneers": 100,
  "includeAuctionDetails": false,
  "letters": [],
  "profileUrls": [],
  "requestConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `records` (type: `string`):

The dataset of scraped AuctionZip auctioneers (one item per auctioneer, with their upcoming auctions nested).

# 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 = {
    "states": [],
    "maxAuctioneers": 100,
    "letters": [],
    "profileUrls": [],
    "requestConcurrency": 4,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/auctionzip-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 = {
    "states": [],
    "maxAuctioneers": 100,
    "letters": [],
    "profileUrls": [],
    "requestConcurrency": 4,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapersdelight/auctionzip-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 '{
  "states": [],
  "maxAuctioneers": 100,
  "letters": [],
  "profileUrls": [],
  "requestConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call scrapersdelight/auctionzip-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapersdelight/auctionzip-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/EyASDCkRQKhkAQWlP/builds/dDTHf2FjAQZhTGlGX/openapi.json
