# WARN notices scraper - California, Illinois, New York layoffs (`retrainmap/warn-notices`) Actor

WARN notices from the California EDD report, the Illinois DCEO monthly workbooks and the New York State DOL WARN dashboard, normalised to one schema: employer, city, county, employees, notice date, effective date, notice type, source file and its Last-Modified stamp. $10 per 1,000 rows, no run fee.

- **URL**: https://apify.com/retrainmap/warn-notices.md
- **Developed by:** [RetrainMap Team](https://apify.com/retrainmap) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$10.00 / 1,000 warn notice rows

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

## WARN notices scraper - California, Illinois, New York layoffs

**Returns:** one row per current WARN layoff/closure notice from the California EDD report, the Illinois DCEO monthly workbooks and the New York State DOL WARN dashboard — employer, city, county, employees, notice date, effective date, notice type, source file and its server date.
**Input:** `{ "states": ["CA", "IL", "NY"], "il_months_back": 2, "max_records": 5000 }` — all optional; empty `{}` reads all three states.
**Price:** $10.00 per 1,000 rows ($0.01 per notice row). No run fee. Pay per event; no subscription.

Current Worker Adjustment and Retraining Notification (WARN) layoff and closure notices
from three state agencies, normalised to one row schema: `state`, `employer`, `city`,
`county`, `employees`, `notice_date`, `effective_date`, `notice_type`, `source_url`,
`file_last_modified` — plus the extra columns each state publishes (address, ZIP, reason,
industry, NAICS, layoff schedule). One row per notice or per affected site, exactly as the
agency lists it.

**Nothing here decides anyone's eligibility.** Whether a worker is covered by WARN, owed
notice pay, or eligible for unemployment insurance or retraining aid is decided locally by
the state agency, the local workforce board and, for WARN itself, the courts. The rows are
the agencies' published lists — the agencies say they do not capture all layoff activity.

### Sources, cadence and status

| State | File read on every run | Cadence | Status |
|---|---|---|---|
| CA | California EDD — `Detailed WARN Report` sheet of https://edd.ca.gov/siteassets/files/jobs\_and\_training/warn/warn\_report1.xlsx (page: https://edd.ca.gov/en/jobs\_and\_training/Layoff\_Services\_WARN/) | The workbook says it is "updated every Tuesday and Thursday"; it covers the current reporting period (e.g. "07/01/26 to 08/31/2026"), which the row field `source_period` repeats | Public record of a state agency, published for public use |
| IL | Illinois DCEO monthly WARN workbooks linked from https://www.illinoisworknet.com/LayoffRecovery/Pages/ArchivedWARNReports.aspx (page: https://dceo.illinois.gov/workforcedevelopment/warn.html). The newest `il_months_back` workbooks are read (xlsx from March 2020; older months are PDFs and are not read) | Monthly | Public record of a state agency, published for public use |
| NY | New York State DOL WARN Dashboard data export — https://public.tableau.com/views/WorkerAdjustmentRetrainingNotificationWARN/WARN.csv (page: https://dol.ny.gov/warn-dashboard; NYS DOL: "As of 4/1/2025, WARN notices will no longer be posted to the database and can be found in the new WARN Dashboard") | Continuous (dashboard); the export covers the current year's notices | Public record of a state agency, published for public use |

Copyright: the federal WARN Act materials are works of the United States Government and
not subject to copyright (17 U.S.C. §105). The state files are public records released by
state agencies for public use; the rows reproduce the facts they publish (employer, dates,
counts), and facts are not copyrightable. Please cite the agency named in `source_page`.

Politeness: the plain Python-urllib User-Agent, the operator's contact address in the
standard `From:` header, at most one request per second (default). A full run is five
requests (CA file; IL archive page + two workbooks; NY export).

### Layout guard

Each file is checked against the exact column layout measured on 2026-09-03 (the nine
CA columns, the twenty IL columns, the twelve NY columns). If a state changes its layout,
the run **fails with the expected and the found header** — it never guesses a mapping.
The failure text tells the maintainer which parser to update.

### Input

| Field | Type | Meaning |
|---|---|---|
| `states` | array of `CA` / `IL` / `NY` | Default all three, read in the order given |
| `max_records` | integer | Default 5000 |
| `il_months_back` | integer 1–12 | Default 2: newest monthly Illinois workbooks to read |
| `request_interval_ms` | integer | Default 1000 (floor 500) |
| `contact_email` | string | Sent in the `From:` header |

### Output (dataset row)

Common: `state`, `employer`, `city`, `county`, `zip`, `address`, `employees`, `notice_date`,
`effective_date` (ISO date when the file gives a date; otherwise `null` with the verbatim text in
`effective_date_text`, e.g. Illinois' "10/25/2026 or w/in 14 days after"), `notice_type`
(`Closure Permanent`, `Layoff Temporary`, ...; the raw wording in `notice_type_raw`), `reason`,
`industry`, `source_url`, `source_page`, `source_period`, `file_last_modified` (the server's
`Last-Modified` header — California sends one, Illinois and the NY export do not, then `null`),
`fetched_at`, `notice_id` (stable hash of state, employer, dates, address and count — use it to
de-duplicate across runs).

`notice_kind` is `initial` for every CA and NY row and for the month's notices in Illinois;
Illinois workbooks also carry a second table, **supplemental notices** (amendments to earlier
notices: extra workers, changed dates), which come out as rows with `notice_kind: "supplemental"`,
`notice_type: "Supplemental"`, the agency's wording in `supplemental_info`, the original filing in
`initial_notice_date`, and `employees` = the *additional* workers affected. Both Illinois tables
have their own exact header guard, and the parser reconciles the month's rows with the sheet's own
"Total Layoff Events" / "Total Impacted" figures (recorded in `RUN_SUMMARY`).

Per state: CA `processed_or_posted_date`; IL `dba`, `ending_layoff_date`, `layoff_schedule`,
`naics`, `union`, `local_workforce_area`, `region`, `ceja_related`, `supplemental_info`,
`initial_notice_date`; NY `processed_or_posted_date`, `site_index`.

A run summary (per-state counts, workbook labels, request count) is stored as `RUN_SUMMARY` in
the run's key-value store.

### Pricing (pay per event)

| Event | Price |
|---|---|
| `warn-record` — per row written | $0.01 |

A typical full run (about 190 CA rows, 100–150 IL rows for two months, 190 NY rows) costs
about $5. Rows stop when your run's maximum charge is reached; the run summary says so.

### Operator

Steelyard Ventures LLC (RetrainMap) — info@steelyardclinical.com. The Actor writes only to
its own dataset and key-value store; it stores no credentials and sends nothing else.

# Actor input Schema

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

State files to read, in this order. CA = the EDD current-period WARN workbook; IL = the newest monthly DCEO workbooks (see il\_months\_back); NY = the NYS DOL WARN dashboard export.

## `max_records` (type: `integer`):

Stop after this many rows in total (states are read in the order given).

## `il_months_back` (type: `integer`):

How many of the newest monthly Illinois WARN workbooks to read (1-12). Each is one request.

## `request_interval_ms` (type: `integer`):

Politeness delay towards the state servers (floor 500 ms).

## `contact_email` (type: `string`):

Sent in the standard From: request header so a data owner can reach the operator.

## Actor input object example

```json
{
  "states": [
    "CA",
    "IL",
    "NY"
  ],
  "max_records": 5000,
  "il_months_back": 2,
  "request_interval_ms": 1000,
  "contact_email": "info@steelyardclinical.com"
}
```

# Actor output Schema

## `results` (type: `string`):

One row per notice: state, employer, city, county, employees, notice and effective dates, type, source file and date.

## `results_csv` (type: `string`):

The same rows as a CSV file.

# 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 = {};

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

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

```

## MCP server setup

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

```

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/9c86Yw2PywH9bfDyo/builds/zmoSG9kkADTeomXhI/openapi.json
