# WARN Layoff Notices Scraper — 10 US States, Official Data API (`cblu/warn-layoff-notices-scraper`) Actor

WARN Act layoff & plant-closure notices from 10 official state sources (CA, TX, FL, IL, PA, NJ, VA, WI, CO, MD) - company, employees affected, dates. JSON/CSV/Excel.

- **URL**: https://apify.com/cblu/warn-layoff-notices-scraper.md
- **Developed by:** [Steven Carleton](https://apify.com/cblu) (community)
- **Categories:** Lead generation, Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 layoff notices

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/platform/actors/running/actors-in-store#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

## WARN Layoff Notices Scraper — US Layoff & Plant Closure Data from Official State Sources

**Know which companies are about to lay people off, 60–90 days before it happens, across 10 states in one run.** A WARN notice is a statutory filing: the employer, the site, how many people, and the date it takes effect. Recruiters use it to reach experienced candidates before they hit the market; sales teams use it as the strongest public distress signal on an account.

Data comes from 10 official state government sources, normalized into one schema. No login, no API key, no HTML scraping of news sites.

### A real run, with the real number

Every WARN notice filed in the covered states in the last 90 days:

```json
{
    "noticeDateFrom": "2026-05-16",
    "maxResults": 20000
}
```

**Result on 2026-08-14: 400 notices, from 10 of 10 state sources, cost $2.00.** That is the whole national picture for a quarter, for the price of a coffee — and the run reports which states succeeded so you always know what you are looking at.

### See real records for 13 cents before you commit

Set `maxResults` to `25` and run it once. You are charged **$0.005 per notice** — so a 25-record look costs **$0.125**, and a run that matches nothing costs only Apify's fraction-of-a-cent start event.

### What one record actually looks like

Real output from a live run, trimmed to the fields most people check first:

```json
{
    "state": "CA",
    "company": "McDonald's Corporation",
    "city": "City of Industry",
    "county": "Los Angeles",
    "employeesAffected": 2,
    "noticeDate": "2026-06-30",
    "layoffDate": "2026-09-01",
    "closureType": "Closure",
    "industry": "72 Accommodation and Food Services",
    "sourceUrl": "https://edd.ca.gov/en/jobs_and_training/Layoff_Services_WARN/"
}
```

Every record carries both the **normalized** value (ISO dates, integer counts, Closure/Layoff classification) and the **raw** value exactly as the state published it, so nothing is lost to normalization. Every record also names the official source it came from.

### What a real job costs

Pricing is **$5.00 per 1,000 notices** ($0.005 each), charged only on notices actually returned:

| What you pull | Notices | Cost |
|---|---|---|
| A look at the output before buying | 25 | **$0.13** |
| All 10 states, last 90 days | 400 (measured) | **$2.00** |
| A year of one state | varies | **$0.005 each** |

There is no subscription — just the per-notice price plus Apify's fraction-of-a-cent platform events (an Actor start event and $0.00001 per result, about 0.2% on top). A weekly monitoring schedule that finds 30 new notices costs about 15 cents.

> **On very large pulls:** Apify caps each run with a maximum-charge limit. If a run reaches it, the run stops early and returns fewer records than your `maxResults` — the run's status message will tell you when this happens. For big pulls, raise the maximum-charge setting on the run (or your plan limit) before starting it.

### Who uses WARN data?

- **Recruiters & staffing agencies** — a WARN notice is a public list of experienced people who will be job-hunting on a known date, 60-90 days before they hit the market. Filter by state, industry, and size to find fresh talent pools first.
- **B2B sales & account teams** — a WARN filing is one of the strongest publicly available distress/change signals for an account: churn risk for vendors, an opening for cost-cutting products, facility consolidation intelligence.
- **Journalists & researchers** — track layoff waves by state, industry, and month from primary government sources, not press releases.
- **Investors & analysts** — plant closures and mass layoffs, straight from the statutory filings, weeks before they show up in quarterly numbers.
- **Local economic development & workforce boards** — monitor incoming dislocations in your region.

### What data do you get?

One result per WARN notice (per affected site, where the state files them that way):

| Field | Example |
|---|---|
| `state` / `stateName` | `TX` / Texas |
| `company` | `Essendant` |
| `address` / `city` / `county` | `300 Central Ave.` / `Irving` / `Dallas` |
| `employeesAffected` | `136` |
| `noticeDate` | `2026-08-03` (ISO; see coverage notes for month-only states) |
| `noticeMonth` / `noticeDateRaw` | `2026-08` / date exactly as the state published it |
| `layoffDate` / `layoffDateRaw` | `2026-10-03` / `10-03-26 thru 10-13-26` |
| `closureType` / `closureTypeRaw` | `Closure` / `Closure Permanent` |
| `industry` | `Health Care and Social Assistance` (where published) |
| `source` / `sourceUrl` | The official state source each record came from |

### State coverage — honest and specific

There is **no federal WARN database**. Every state publishes its own portal in its own format — Excel workbooks, CSV exports, Google Sheets, paginated HTML, PDF-only filings. This Actor wraps the machine-readable ones, normalizes the fields, and tells you exactly which states it can and cannot cover.

Covered now (10 states, ~45% of US employment):

| State | Official source | Format | History available |
|---|---|---|---|
| **California** | EDD WARN Report | Excel, updated Tue & Thu | **Current fiscal year only** (July 1 onward) — EDD publishes prior years as PDF |
| **Texas** | TWC WARN Act Listings | Excel per year | Multi-year (per-year files) |
| **Florida** | FloridaCommerce REACT | HTML per year | Multi-year (verified to 2015) |
| **Illinois** | DCEO monthly WARN reports | Excel per month | Recent years (older months are PDF-only) |
| **Pennsylvania** | L\&I WARN notices page | HTML | Current + previous year; **notice date = posting month** |
| **New Jersey** | NJ DOL WARN Archive | Excel workbook | **Since 2004**; notice date = posting month |
| **Virginia** | Virginia Works | CSV export | Multi-year |
| **Wisconsin** | DWD WARN notices | Official data feed | Since 2020 |
| **Colorado** | CDLE layoff/WARN list | Google Sheets per year | ~3 years |
| **Maryland** | DWDAL WARN log | HTML per year | Multi-year |

**Not covered yet — and why** (verified individually, August 2026):

- **New York** — NY DOL moved WARN data into a Tableau dashboard behind bot protection; the underlying filings are per-notice PDFs. On the roadmap.
- **Ohio** — JFS reorganized its site in 2026; the public notice listing URLs currently return 404. Will be added when the listing resurfaces.
- **Georgia** — TCSG publishes notices through a JavaScript widget without a stable public data endpoint.
- **Michigan** — publishes scanned per-notice PDFs only.
- **Washington** — ESD's "WARN database" page currently ships no data table (JS app removed/broken at source).
- Remaining states are a mix of PDF-only, JS-only, and no-portal situations. Ask in the Issues tab if you need a specific state — portals change, and coverage is re-verified with every update.

If a covered state changes its portal, that state fails **in isolation**: the run continues, you are only charged for records actually returned, and the run's key-value store contains a `COVERAGE` report showing exactly which states succeeded and failed.

### How to use it

All covered states, notices from the last 90 days:

```json
{
    "noticeDateFrom": "2026-05-14",
    "maxResults": 10000
}
```

Big layoffs in Texas and Florida this year:

```json
{
    "states": ["TX", "FL"],
    "noticeDateFrom": "2026-01-01",
    "minEmployees": 250,
    "maxResults": 5000
}
```

Track one company everywhere:

```json
{
    "companySearch": "amazon",
    "noticeDateFrom": "2025-01-01"
}
```

Leave `states` empty for all covered states. Without `noticeDateFrom`, the current + previous calendar year are fetched. `maxResults` caps the run — **you are only charged for records actually returned**.

#### Date semantics (worth 20 seconds)

- `noticeDate` is the date the state received/posted the notice; `layoffDate` is when the layoff/closure takes effect (first date, when a range was filed).
- **NJ and PA publish only the posting month**, not an exact day. For those states `noticeDate` is `null`, `noticeMonth` (e.g. `2026-08`) is set, and date filters match by month.
- A handful of filings state effective dates as prose ("9/6/2026 or within 14 days after"); the ISO field is then `null` and the prose is preserved in `layoffDateRaw`.

### Why not scrape the state sites yourself?

You can — every source this Actor uses is public and official. What you'd be signing up to maintain:

- 10 different formats: xlsx workbooks (3 different layouts), CSV exports with rotating filenames, Google Sheets discovered by scraping a CMS page, paginated ASP.NET tables, and an AEM accordion page.
- Excel serial dates, `MM-DD-YY` vs `MM/DD/YYYY`, "thru" ranges, month-only dates, and "or within 14 days after" prose — normalized here into ISO dates plus raw originals.
- Portals that move: three states relocated or restructured their WARN pages in 2026 alone. This Actor re-verifies sources on every update and degrades gracefully per state.

### Pricing

Pay per result: **$0.005 per notice** ($5.00 per 1,000). You are charged per notice actually returned, plus Apify's small platform events: a fraction-of-a-cent Actor start event and $0.00001 per dataset item — about 0.2% on top of the per-notice price. No subscription; a run that finds nothing costs only the fraction-of-a-cent start event.

### FAQ

**Is this legal?** Yes. WARN notices are statutory public records published by state governments precisely so that workers, communities, and businesses can act on them. This Actor reads only official government sources.

**How fresh is the data?** As fresh as the states publish: CA updates twice a week, most HTML/CSV states update as notices arrive, IL publishes monthly files. Schedule the Actor daily or weekly to keep a rolling feed.

**Why is a notice missing that I saw in the news?** Either it was filed in a non-covered state (see the table), it is newer than the state's last portal update, or the employer wasn't required to file (WARN thresholds: generally 100+ employees, 50+ affected).

**Can I get notified of new notices?** Run the Actor on an [Apify Schedule](https://docs.apify.com/platform/schedules) with a rolling `noticeDateFrom` and wire the dataset to email/Slack/webhooks via Apify integrations.

# Actor input Schema

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

Which states to pull WARN notices from. Leave empty for ALL covered states. Covered: CA, CO, FL, IL, MD, NJ, PA, TX, VA, WI (the states whose official portals publish machine-readable data - see the README coverage table for what each source provides and why other states are not covered yet).

## `noticeDateFrom` (type: `string`):

Optional. Only return notices dated on/after this date (format <code>YYYY-MM-DD</code>). Without it, the current + previous calendar year are fetched. States that publish only a posting month (NJ, PA) are filtered by their layoff/effective date instead.

## `noticeDateTo` (type: `string`):

Optional. Only return notices dated on/before this date (format <code>YYYY-MM-DD</code>).

## `companySearch` (type: `string`):

Optional. Case-insensitive substring match against the company and DBA name, e.g. <code>amazon</code>.

## `minEmployees` (type: `integer`):

Optional. Only return notices affecting at least this many employees, e.g. <code>250</code> to see only major layoffs. Notices where the state did not publish a count are excluded when this filter is set.

## `maxResults` (type: `integer`):

Maximum number of notices to return across all states, e.g. <code>500</code> for a sample or <code>100000</code> for everything available. You are only charged for records actually returned.

## Actor input object example

```json
{
  "states": [],
  "maxResults": 500
}
```

# Actor output Schema

## `notices` (type: `string`):

All extracted WARN layoff and plant-closure notices as JSON.

## `noticesCsv` (type: `string`):

All extracted WARN layoff and plant-closure notices as CSV.

## `coverage` (type: `string`):

Which state sources succeeded, failed, or were skipped in this run, with record counts.

# 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 = {
    "maxResults": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("cblu/warn-layoff-notices-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 = { "maxResults": 500 }

# Run the Actor and wait for it to finish
run = client.actor("cblu/warn-layoff-notices-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 '{
  "maxResults": 500
}' |
apify call cblu/warn-layoff-notices-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cblu/warn-layoff-notices-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/LgMrSShtfINVTbSrt/builds/AGoPmDiLHlV2y0t2n/openapi.json
