Methodology
How we collect, normalize, deduplicate, and serve six federal labor datasets. Open, audit-friendly, and explicit about what we cannot do.
Last updated: 2026-05-12. Material methodology changes are noted in the changelog at the bottom of this page.
Sources at a glance
| Dataset | Source | Cadence | Coverage | License |
|---|---|---|---|---|
| WARN Act notices | 50 state workforce agencies | Daily | 1988–present, 47 states and DC publish | Public records (source); compiled files under our terms |
| H-1B / LCA petitions | USCIS + DOL Office of Foreign Labor Certification | Monthly full reload; current fiscal year refreshed weekly | FY2009–present (LCA back to FY2012) | Public records (source); compiled files under our terms |
| SEC 8-K filings | SEC EDGAR | Daily | 2014–present (items 1.03 & 2.05) | Public records (source); compiled files under our terms |
| Bankruptcy filings | PACER, SEC, FJC IDB | Daily | 2015–present | Public records (source); compiled files under our terms |
| DOL unemployment claims | U.S. Department of Labor | Weekly | 1984–present | Public records (source); compiled files under our terms |
| JOLTS labor turnover | BLS Job Openings & Labor Turnover Survey | Monthly | 2000–present | Public records (source); compiled files under our terms |
WARN Act data — 50 state scrapers
The Worker Adjustment and Retraining Notification (WARN) Act requires US employers with 100+ employees to give 60 days' advance notice of mass layoffs and plant closures. Each state collects these filings and publishes them through its labor or workforce agency — with no federal central repository.
WARN Firehose operates 51 independent scrapers (50 states and DC), each tailored to that agency's publishing format (PDF, HTML table, Excel, or CSV). Every scraper runs daily at 05:00 UTC and:
- Fetches the latest filings from the agency website (or PDF, where the state still publishes that way)
- Parses structured fields: company name, city, county, state, employees affected, notice date, effective date, layoff type
- Generates a deterministic record ID:
{STATE}-{YEAR}-{md5[:8]}so the same filing produces the same ID on re-scrape (idempotent ingest) - Validates against a schema and writes to SQLite with WAL mode
- Fires webhooks to active subscribers if matched on watched companies
Every record carries the URL we captured it from, unchanged. For most recent records that is the notice’s entry on the state agency page; for much of the historical backlog it is the state’s WARN listing page rather than a per-notice document (2026 records: about 9 in 10 have a per-notice URL; 2020: about 1 in 5). The API says which with source_granularity; we do not invent links.
Cross-dataset joins
Public WARN notices alone don't tell the whole story. We cross-reference each WARN record against five other federal datasets to surface signals that individual sources miss:
- SEC 8-K item 2.05 — "Costs Associated With Exit or Disposal Activities" — a restructuring disclosure that may precede, follow or coincide with a WARN notice; we do not measure a lead time
- SEC 8-K item 1.03 — "Bankruptcy or Receivership" notices, shown for the same employer with no timing relationship claimed
- Chapter 11 / Chapter 7 bankruptcy filings — cross-matched on normalized employer name only (the case’s state is shown as reported and is not used for matching; see the rules below)
- H-1B / LCA petitions — the same employer's recent visa sponsorship volume, surfaced on company pages beside its WARN notices
- DOL initial unemployment claims by state — the leading macroeconomic indicator that contextualizes a WARN filing
These joins power the Risk Signal API and the cross-referenced data tables on every company page.
How matches are made — and what they are not
No public dataset shares an identifier with WARN notices, so every cross-dataset link on this site is made by us. Each is an algorithmic estimate: it is not verified by the SEC, the Department of Labor, the bankruptcy courts or any state agency, and it can miss a company whose name differs between filings or pair two entities that share a name. The rules, per surface:
- Company pages — SEC 8-K rows. Looked up by a ticker, then a CIK, then the exact upper-cased company name. The ticker and CIK are assigned to WARN records by our SEC enrichment (a multi-pass fuzzy match against the SEC's company-ticker list, with a small set of hand-verified overrides). No date window: the filings shown are not restricted to the period of the WARN notices.
- Company pages — H-1B / LCA counts. Exact match on the importer's normalized employer name (lowercased, selected legal suffixes stripped, whitespace collapsed, known aliases applied — punctuation is kept, so "A.B.C." and "ABC" do not join), across all fiscal years.
- Bankruptcies page — WARN cross-reference. Normalized name equality, else the normalized WARN company name appearing inside the normalized court case name (that name must be at least 12 characters and must not start with a generic word). The link is stored at import with no date limit; the page then counts only cases filed and WARN notices dated in the last year, so a linked case can show 0 recent notices — and there is no requirement that the two filings be close in time.
- SEC filings page — WARN cross-reference. Joined on the ticker our enrichment assigned to the WARN record, so a name-derived link one step removed.
- Charts — layoffs vs H-1B hiring. WARN names normalized in the query and joined to the petition datasets' own normalized employer names (two different normalizers, so under-matching is likely); layoff counts are all-time while petition counts cover a single fiscal year.
- H-1B employer pages — WARN column. The employer's name as the LCA importer normalized it (lowercased, legal suffixes stripped, known aliases applied) compared, upper-cased, against WARN company names with only case and whitespace stripped — two different normalizations, so even an identical legal name such as "Example Inc" can fail to match, and an employer whose WARN notices carry a suffix or a different legal name shows 0 here. Both counts are all-time.
- Risk Signal. A descriptive company score over WARN notice count and recency, SEC 8-K restructuring items, bankruptcy filings and H-1B denial rate, thresholded into Critical / Elevated / Moderate / Low — not a forecast.
- The five indexes. Each is a descriptive score over the filings named on its own card: WARN notice velocity and employee velocity with DOL initial claims as the third input, weighted 40/40/20 — no JOLTS data (WARN Velocity); WARN trend, DOL claims, LCA volume, bankruptcies and employer concentration per state (Workforce Stress); layoffs alongside LCA/H-1B petitions (Talent Displacement); multi-employer clustering in a metro, and multi-state clustering by industry (Metro Contagion, Industry Domino). None is a forecast.
A count of zero on any of these surfaces means no match under these rules, not that the agency holds no filing.
Normalization rules
Public datasets are messy. WARN Firehose applies the following normalization in the ingest pipeline:
- Company name normalization — "Amazon.com, Inc.", "Amazon Inc", "AMAZON.COM SERVICES LLC", and "Amazon Web Services" are unified under a canonical employer slug. Variants are preserved in a
display_namecolumn. - NAICS industry codes — back-filled from LCA petition records, sibling company records, known-employer mapping, and keyword classification.
- County geocoding — when a record has a city but no county, we infer from a US Census place-to-county mapping.
- Date parsing — multiple formats (ISO, US slashes, European slashes, "Jan 5, 2026") collapsed to ISO 8601.
- Slug generation — URL slugs are deterministic, lowercase, hyphen-separated, ASCII-only.
- Deduplication — exact and near duplicates (same company, state, notice date and headcount) are resolved by the nightly cleanup, which keeps the most complete record and removes the duplicate. Ambiguous candidates (same company and effective date, different notice rows) are flagged for review, not deleted.
Documented gaps
We do not generate or estimate data we don't have. The following gaps are real and disclosed:
Data quality status
Current quality metrics (refreshed 2026-03-08):
- WARN records: 3.4% missing city, 1.1% missing county, 6.7% missing industry (continuing to back-fill from LCA + keyword classifiers)
- LCA petitions: 24.1% missing wage data (older fiscal years), 47.7% missing SOC code (older fiscal years)
- H-1B petitions: 0.3% missing state (clean)
- SEC 8-K filings: 100% parsed for items 1.03 & 2.05
- Bankruptcies: 77.2% WARN-matched, 71.1% missing chapter (source-data limitation)
Accuracy guarantees
WARN Firehose surfaces public records as filed. We do not guarantee that the underlying agencies are correct. If a state agency publishes an error (wrong employer name, wrong employee count, wrong effective date), we mirror that error until they correct it. We are a data aggregator, not a primary source.
If you find a record we ingested incorrectly — for example, a parsing failure that misattributed a row — email [email protected] with the record ID and source URL and we will investigate within one business day.
Open source
The scraper pipeline, normalization code, and SEO page generators are publicly auditable at github.com/sendkamal. Issues, PRs, and reports of parsing failures are welcome.
Changelog
- 2026-05-12: Initial publication of this methodology page.
- 2026-03-08: NAICS back-fill pipeline reduced missing-industry rate from 13.2% to 6.7%.
- 2026-03-05: LCA schema expanded from 22 to 40 columns (employer address, worksite county, H1B-dependent flags, etc.).
- 2026-02-22: Federal data import workflow added to GitHub Actions (LCA + H-1B + JOLTS) — named "quarterly", it runs monthly on the 15th.
- 2024-12-01: Site launched with initial 14 state scrapers; expanded to 50 by mid-2025.