# Industry Auction Signals: Plant Closure & Liquidation Sales (`mdcurt/industry-auction-signals`) Actor

One signal per industrial auction newly listed by six US liquidation houses (Heritage Global, CIA Industrial, Heath, Schneider, Loeb, Rosen): seller, reason for sale, industry tags, sale date, location, catalog link. Filter by industry (cannabis, brewery, biotech lab). Keyless, pay per signal.

- **URL**: https://apify.com/mdcurt/industry-auction-signals.md
- **Developed by:** [Matthew Curtis](https://apify.com/mdcurt) (community)
- **Categories:** News, AI
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $105.00 / 1,000 auction signals

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Industry Auction Signals: Plant Closure & Liquidation Sales

One signal per industrial auction newly listed by six US liquidation houses — **Heritage Global Partners**, **CIA Industrial** (Cincinnati Industrial Auctioneers), **Heath Industrial**, **Schneider Industries**, **Loeb Equipment** and **Rosen Systems** — with the seller, the reason for the sale, industry tags, the sale date, the location, the lot count and the catalog link. Toggle industries (cannabis, brewery/distillery, biotech lab, printing, metalworking, food, plastics, trucks …) or pass a keyword, and get only the auctions that matter to your buyers. Keyless, stateless, pay per signal.

The houses publish each auction as a WordPress post; this Actor reads their public JSON index (`/wp-json/wp/v2/auction`) for the auctions posted in your window, opens each auction's own page once, and extracts the header block the house itself wrote: sale date, address, "Plant Closed" / "By Order of the United States Bankruptcy Court" / "Owner Retiring" / "Surplus to the ongoing operations of" lines. Nothing is inferred from menus, sidebars or lot lists. Individual debtors' and estate sales are never emitted; cancelled sales are skipped.

### Input

| field | type | default | what it does |
|---|---|---|---|
| `industries` | select (multi) | `[]` = all | Keep only auctions tagged with any of these: `cannabis`, `brewery-distillery`, `food-beverage`, `printing`, `plastics-rubber`, `metalworking-cnc`, `fabrication-welding`, `woodworking`, `stone-ceramics-glass`, `pharma-biotech-lab`, `semiconductor-electronics`, `data-center-it`, `packaging`, `automotive-aerospace`, `construction-heavy-equipment`, `material-handling-warehouse`, `trucks-fleet`, `medical`, `textiles-apparel`, `paper-converting`, `chemical-processing`, `waste-energy-utilities`, `restaurant-retail`, `entertainment-fitness`, `media-av`, `office-furniture`, `electrical-contractor`, `plumbing-hvac-contractor`, `automotive-repair`, `steel-service`, `agriculture`. |
| `keyword` | string | `""` | Case-insensitive substring filter on title, headline, seller, reason and industry tags (`"injection mold"`, `"Pfizer"`, `"bankruptcy"`, `"plant closure"`). |
| `sinceDays` | integer 1–180 | `30` | Auctions **posted** by the houses within the last N days. Sale dates can be weeks ahead of the posting. |
| `houses` | select (multi) | all six | `hgp`, `cia`, `heath`, `schneider`, `loeb`, `rosen`. |
| `maxSignals` | integer | `200` | Stop after this many signals. |
| `proxyConfiguration` | proxy | Apify datacenter | All six houses answer datacenter IPs; failed proxy attempts are retried directly. |

### Output — one record per auction

```json
{
  "id": "cia:20082",
  "kind": "auction-listed",
  "house": "CIA Industrial",
  "title": "Puck Plastics",
  "seller": "Puck Plastics",
  "sellerConfidence": "inferred",
  "reason": "plant-closure",
  "reasonConfidence": "verified",
  "reasonEvidence": "house term: Plant Closed",
  "industries": ["plastics-rubber", "material-handling-warehouse"],
  "houseCategories": [],
  "location": { "city": "Shawnee", "state": "KS" },
  "otherLocations": null,
  "status": null,
  "saleDate": "2026-12-03",
  "saleMonth": null,
  "saleDateCue": "date line",
  "biddingOpens": null,
  "postedAt": "2026-10-29T16:18:42",
  "modifiedAt": "2026-11-05T12:01:10",
  "lots": null,
  "bidPlatform": "bidspotter",
  "headline": "Startup Plastic Injection Molding Facility Featuring (2) 2025 – 716 Ton JSW Injection Molding Machines, Robots, Chillers, Blenders …",
  "slug": "puck-plastics",
  "sourceUrl": "https://www.cia-industrial.com/auction/puck-plastics/",
  "observedAt": "2026-11-12T13:50:00Z",
  "confidence": "verified",
  "whyItMatters": "CIA Industrial listed “Puck Plastics” (plant closure) in Shawnee, KS; sale 2026-12-03; plastics-rubber, material-handling-warehouse. Startup Plastic Injection Molding Facility …",
  "source": "cia",
  "scrapedAt": "2026-11-12T13:50:00Z"
}
```

- `kind` — `auction-listed`, or `negotiated-sale` for "buy now" / "for immediate sale" / turnkey offerings without a bidding date.
- `reason` — `plant-closure`, `bankruptcy`, `receivership`, `assignment-for-benefit-of-creditors`, `secured-party`, `owner-retiring`, `relocation`, `real-estate-sold`, `surplus-ongoing`, `consignment`, or `null` when the house states none. `reasonConfidence` is `verified` when the house's own term or sentence says so (`reasonEvidence` quotes it, ≤ 300 chars).
- `seller` — the company named in the title ("Ron Jones Electric, Inc.", "Schwebel Baking Company"); `null` for anonymised sales ("Fortune 1000 Company's Engineering Toolroom"), multi-seller consignment sales and product-named sales. Always `inferred`. The URL `slug` often still names a seller the house later anonymised.
- `industries` — the house's own category plus keyword packs applied to the title and headline only, strongest first (at most four). Empty when nothing matched.
- `confidence` — `verified` when both a sale date and a location were read from the page; `inferred` otherwise (date TBD, month-only, state-only).
- `status` — Heath Industrial's own label (`active`, `upcoming`, `completed`); other houses do not print one.
- `saleMonth` — month precision when the house prints "Late December 2026" or "January 2027" instead of a day.

Copied text is limited to the house's headline sentence (≤ 300 chars) and the reason evidence; contact e-mails and phone numbers are redacted.

### Pricing

**$0.15 per signal + $0.005 per run** (Store discounts on). Auctions outside your filter, cancelled sales and individual-debtor sales are read but never charged. A 30-day sweep of all six houses ≈ 35 signals ≈ $5.25; a weekly cannabis or brewery watch is usually $0.30–1.50; a one-signal agent lookup is $0.155.

### Speed (measured 2026-11-12, datacenter proxy)

| run | signals | requests | time |
|---|---|---|---|
| one cannabis signal, 150 days | 1 | 36 | 14 s (first record 7 s) |
| HGP biotech lab surplus, 30 days | 6 | 9 | 5 s |
| brewery + food, 90 days, six houses | 11 of 107 auctions | 113 | 87 s |
| bankruptcy keyword, Heath + Rosen, 60 days | 12 of 35 | 37 | 55 s |
| every auction, six houses, 60 days | 76 of 81 | 90 | 72 s, 0 failed, 0 blocked |

Rosen Systems is read one page at a time, two seconds apart (its server resets concurrent connections), so Rosen-heavy runs are slower.

### Monitoring recipe

Run weekly with `sinceDays: 7` and the industries you buy in; every record `id` is stable (`<house>:<post id>`), so a scheduled run plus [mdcurt/dataset-diff-monitor](https://apify.com/mdcurt/dataset-diff-monitor) on the dataset gives you only the auctions that are new since the last run. For a monthly digest, `sinceDays: 30` and download the dataset as CSV (`house, title, seller, reason, industries, location, saleDate, sourceUrl`).

### Tutorials

- Cannabis cultivation and extraction equipment at liquidation houses: `industries: ["cannabis"]`, `sinceDays: 90` — on 2026-11-12 that returned SSAC Corp (Verdi, NV — Mobius processing line, LED grow lights; HGP, Dec 15) and RC Brown Associates (San Jose, CA — HVAC, trimming, filling; HGP) and Schneider's multi-location cannabis equipment auction.
- Plant closures and court-ordered sales across all industries: `keyword: "bankruptcy"` or `keyword: "plant closure"` with `sinceDays: 30`.
- Biotech lab surplus (the single biggest stream: HGP lists several a week in Hayward, San Diego, Boston and the Research Triangle): `industries: ["pharma-biotech-lab"]`, `houses: ["hgp"]`.

### For AI agents

Pass one thing: `industries` (an array of the tags above) **or** `keyword`; everything else has a default. You get back an array of auction signals (fields above), newest posting first per house, each with a `sourceUrl` you can open and a one-sentence `whyItMatters`. A one-signal lookup (`maxSignals: 1`) costs $0.155 and answers in about 5–15 seconds; a 30-day industry watch costs well under a dollar.

### Limitations (stated honestly)

- Six houses, chosen because they publish a structured public index; BidSpotter, HiBid, Proxibid, GovDeals, Liquidation.com and the aggregators are not read (bot protection or robots rules). Lot-level data is never read — this is one record per auction.
- The houses edit and rename posts after publishing (CIA anonymised "Puck Plastics" into "Startup Plastics Facility" within a day; Heath pages flip to "Completed"). Records reflect the page at run time; `postTitle` keeps the index title when it differs.
- Industry tags are keyword packs on the title and headline, verified at 18/20 and 19/20 on two hand-checked draws of 20 (90–95 % precision); a 3D-printing shop still tags as `printing`. Treat the tags as a filter, read the headline before bidding.
- Sale dates come from the house's header; a date more than 400 days before the posting is dropped (repurposed pages). Multi-day sales appear once per day post (Day 1 / Day 2) as the houses post them.
- Volume: ≈ 35 auctions a month across the six houses (177 in the 150 days to 2026-11-12). This is a precise, low-volume feed, not a lot scraper.

### Changelog

- 1.0.0 (2026-11-12) — first release: six houses, 31 industry packs, 10 reasons, per-house header parsers, individual-debtor and cancelled-sale filters, contact redaction, pay per signal.

# Actor input Schema

## `industries` (type: `array`):

Keep only auctions tagged with any of these industries. Tags come from the auction house's own category plus keyword packs applied to the title and headline (e.g. `cannabis` = cannabis/hemp cultivation, extraction, trimming, grow lights; `brewery-distillery` = brewhouse, fermenters, stills; `pharma-biotech-lab` = HPLC, bioreactors, lab automation). Leave empty for every industry.

## `keyword` (type: `string`):

Optional case-insensitive filter on the auction title, headline, seller, reason and industry tags (e.g. "injection mold", "Pfizer", "bankruptcy", "plant closure", "receiver"). Leave empty for no keyword filter.

## `sinceDays` (type: `integer`):

Auctions posted by the houses within the last N days (the posting date, not the sale date). 7 for a weekly digest, 30 for a monthly sweep; max 180. Sale dates in the records can be weeks ahead of the posting.

## `houses` (type: `array`):

Which houses to read: `hgp` Heritage Global Partners (biotech, pharma, food, metalworking), `cia` CIA Industrial / Cincinnati Industrial Auctioneers (plant closures, Midwest), `heath` Heath Industrial (Chicago; bankruptcy court sales), `schneider` Schneider Industries (St. Louis; plant closures, brewery consignment), `loeb` Loeb Equipment (food & packaging), `rosen` Rosen Systems (Dallas; bankruptcy sales, restaurants, Xchange consignment). Default: all six.

## `maxSignals` (type: `integer`):

Stop after this many signals (each signal is one charged record). A 30-day sweep of all six houses yields ≈ 30–40.

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

Apify Proxy (datacenter is enough: all six houses answer datacenter IPs). Requests that fail twice through the proxy are retried on a direct connection.

## Actor input object example

```json
{
  "industries": [],
  "keyword": "",
  "sinceDays": 30,
  "houses": [
    "hgp",
    "cia",
    "heath",
    "schneider",
    "loeb",
    "rosen"
  ],
  "maxSignals": 200,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `signals` (type: `string`):

One record per auction: house, title, seller, reason (plant-closure | bankruptcy | receivership | secured-party | owner-retiring | relocation | real-estate-sold | surplus-ongoing | consignment | assignment-for-benefit-of-creditors), industries\[], location, saleDate, biddingOpens, lots, bidPlatform, headline, whyItMatters, confidence, sourceUrl, observedAt.

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

SUMMARY record: auctions listed and read per house, signals by house / industry / reason, skipped individual and cancelled sales, requests, blocked pages, time to first record and compute seconds.

# 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 = {
    "industries": [],
    "keyword": "",
    "houses": [
        "hgp",
        "cia",
        "heath",
        "schneider",
        "loeb",
        "rosen"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("mdcurt/industry-auction-signals").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 = {
    "industries": [],
    "keyword": "",
    "houses": [
        "hgp",
        "cia",
        "heath",
        "schneider",
        "loeb",
        "rosen",
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("mdcurt/industry-auction-signals").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 '{
  "industries": [],
  "keyword": "",
  "houses": [
    "hgp",
    "cia",
    "heath",
    "schneider",
    "loeb",
    "rosen"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call mdcurt/industry-auction-signals --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mdcurt/industry-auction-signals"
        }
    }
}
```

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/3O9WA3mwnl6mAICYC/builds/AqKb3cmOjodj9zSzK/openapi.json
