ParseForge Scrapers

MSHA Mine Data Scraper - Violations, Inspections, Accidents

parseforge/msha-mine-data-scraper

Other

Streams all 20 MSHA Open Government Data files, 17.8 million rows on US mines, violations, inspections, accidents, penalties, production and health samples.

Run this scraper See the API call
Total runs
23
Bookmarked
0
Last modified
8 days ago

This scraper was last updated on .

What does the MSHA Mine Data Scraper - Violations, Inspections, Accidents return?

ParseForge

MSHA Mine Data Scraper - Violations, Inspections & Accidents

Scrape MSHA mine data from all 20 Open Government Data files: 17,856,581 rows covering every US mine since 1970 and every violation, inspection and accident since 2000. Every row is a flat record with the source's own field names mapped to readable keys, dates normalised to ISO, and no empty columns. No login, no API key, no FOIA request. Export to CSV, JSON, Excel, or XML.

MSHA publishes this data as 582 MB of ZIP archives that you are expected to download whole, unzip, and load into a database before you can ask a single question. This Actor streams the archives and stops reading the moment it has your rows, so a 10-row request against the 1.4 GB violations file transfers a few kilobytes instead of 120 MB, and filters by mine, state, date, penalty or injury run while the file streams.

Who uses it What they scrape MSHA data for
Mine safety consultants Violation and inspection history for a client's mine ID before an audit
Insurance underwriters Injury rates, penalty history and employment size to price a mining risk
Industrial sales teams Active mines by state, commodity and employee count with operator contacts
Journalists and researchers Fatality records, narratives and enforcement outcomes as primary sources
Legal and compliance teams Contested citations, FMSHRC dockets and civil penalty decisions

What it does

This Actor reads MSHA's Open Government Data archives and returns each record as a flat row. Pick one dataset or all twenty in a single run:

  • โ›๏ธ Mines: 91,979 mines since 1970 with status, type, controller, operator, commodity, SIC, employee count and coordinates.
  • ๐Ÿšจ Enforcement: 3,096,400 violations, 3,029,093 assessed penalties, 451,718 contested citations, 481,753 civil penalty dockets, 162,065 conferences and 3,861 imminent danger orders.
  • ๐Ÿ” Inspections: 1,156,532 inspection events with activity, inspector count, on-site hours and the areas covered.
  • ๐Ÿฉน Accidents: 274,448 injury and illness reports from MSHA form 7000-1, including the full free-text narrative.
  • ๐Ÿ“Š Production: 5,062,796 employment and production rows for mine operators and contractors, quarterly and yearly.
  • ๐Ÿงช Health samples: 3,784,443 coal dust, quartz, area, personal health and noise samples.
  • ๐Ÿ”— Optional joins: add mine master details, operator contact addresses or the latest production summary to any row that carries a mine ID.

Results export to CSV, JSON, Excel, or XML, or stream from the API.

What you can do with MSHA data

๐Ÿญ Build a targeted list of active mines. Filter 91,979 mines down to the ones that matter: active status, a given state, sand and gravel or stone, above a minimum employee count. Tick the operator contact block and every row carries the business name, contact title and street address MSHA has on file.

โš–๏ธ Reconstruct a mine's enforcement history. Feed a mine ID and select violations, assessed violations, contested violations and penalty dockets in one run. You get the citation, its gravity and negligence findings, the penalty proposed, what was actually paid, whether it was contested and how the judge ruled.

๐Ÿ“‰ Study injuries and fatalities. The accidents dataset carries the degree of injury, the classification, the equipment involved, the miner's experience, days lost, and the inspector's narrative. Filter to fatalities only and you have all 1,210 fatal records with their stories.

๐Ÿงญ Track an operator across its mines. Controller and operator history maps 169,809 controller-to-operator associations with start and end dates, so you can follow who owned which mine and when, then join production and violations onto the same mine IDs.

Why choose this scraper

What you get
Full coverage All 20 live MSHA data files, 17,856,581 rows, 562 source columns, nothing summarised away
Streamed, not downloaded Reads the ZIP as it arrives and stops early, so small requests stay small
Filters that run upstream of your dataset Mine ID, state, date, penalty, injury, negligence and 16 more, applied while the file streams
Clean rows ISO dates, real numbers, Yes/No booleans, "N/A" where MSHA withheld a value, and zero always-empty columns
Joins MSHA makes you do yourself Mine master, operator address and production summary attached by mine ID
Priced per row You pay for rows written, not for the 582 MB the source makes you fetch

How it compares

Four other MSHA Actors exist on the Apify Store, and each covers one slice: a mine lookup, an operator lead list, or the assessed violations file. None of them reads all twenty files, and none joins the mine master onto the enforcement rows. This Actor costs more per row than the cheapest of them, and what the difference buys is coverage and the joins: one run can return mines, their violations, their inspections, their accidents and their production, with state and status filters working even on the files that carry neither column.

This Actor Typical single-file MSHA Actor Downloading the files yourself
Datasets covered 20 1 to 2 20
Rows reachable 17,856,581 Under 3.1 million 17,856,581
Filters 22, applied while streaming Usually a mine ID Whatever you write
Bytes moved for 10 rows A few KB Varies 582 MB, then unzip
Mine master join Built in No Write it yourself
Setup None None Download, unzip, parse, load

What an MSHA mine record looks like

One real row from a verified run, unedited:

{
  "dataset": "mines",
  "mineId": "0100003",
  "mineName": "O'Neal Quarry & Mill",
  "coalOrMetal": "M",
  "mineType": "Surface",
  "mineStatus": "Active",
  "mineStatusDate": "1979-01-22",
  "controllerId": "0041044",
  "controllerName": "Lhoist Group",
  "operatorId": "L13586",
  "operatorName": "Lhoist North America of Alabama, LLC",
  "state": "AL",
  "bureauOfMinesStateCode": "01",
  "countyFipsCode": "117",
  "countyName": "Shelby",
  "congressionalDistrict": "06",
  "companyType": "Other",
  "controllerBeginDate": "1989-07-01",
  "district": "M3",
  "officeCode": "M3661",
  "officeName": "Birmingham AL Field Office (A)",
  "assessmentControlNo": "000638053",
  "primarySicCode": "327400",
  "primarySicDescription": "Lime",
  "primarySicCodeShort": "3274",
  "primarySicSuffix": "00",
  "secondarySicCode": "142200",
  "secondarySicDescription": "Crushed, Broken Limestone NEC",
  "secondarySicCodeShort": "1422",
  "secondarySicSuffix": "00",
  "primaryCommodityCode": "6",
  "primaryCommodity": "Stone",
  "secondaryCommodityCode": "6",
  "secondaryCommodity": "Stone",
  "status103i": "Never Had 103I Status",
  "status103iDate": "N/A",
  "portableOperation": "No",
  "portableStateFipsCode": "N/A",
  "daysPerWeek": 7,
  "hoursPerShift": 8,
  "productionShiftsPerDay": 3,
  "maintenanceShiftsPerDay": 0,
  "employeeCount": 108,
  "part48Training": "Yes",
  "longitude": -86.758889,
  "latitude": 33.177778,
  "avgMineHeightInches": "N/A",
  "gasCategoryCode": "N/A",
  "methaneLiberationCfd": "N/A",
  "producingPitCount": "N/A",
  "nonProducingPitCount": "N/A",
  "tailingPondCount": 0,
  "pillarRecoveryUsed": "No",
  "highwallMinerUsed": "No",
  "multiplePits": "No",
  "minersRepresentative": "No",
  "safetyCommittee": "No",
  "milesFromOffice": 100,
  "directionsToMine": "Approx 7 miles south of the city of Alabaster on Hwy 31.",
  "nearestTown": "Calera",
  "mineDataRetrievalUrl": "https://www.msha.gov/mine-data-retrieval-system?mineid=0100003",
  "scrapedAt": "2026-08-27T16:20:57.704Z"
}

Rows from the other 19 datasets carry that dataset's own columns instead. Violations, inspections, accidents and the sample files each have their own shape, and the dataset key tells you which one you are looking at.

Configure the run

Pick datasets, set maxItems, and add filters. Filters run as each record is read, so only matches reach your dataset, and a filter naming a column the selected dataset does not have is ignored for that dataset. The Input tab lists every parameter.

Active sand and gravel mines in Texas, with the operator's mailing address:

{ "datasets": ["mines"], "states": ["TX"], "mineStatuses": ["Active"], "commodities": ["SandAndGravel"], "includeOperatorContact": true, "maxItems": 500 }

Everything MSHA has on one mine, across four enforcement datasets:

{ "datasets": ["violations", "assessedViolations", "contestedViolations", "penaltyDockets"], "mineIds": ["0100003"], "maxItems": 2000 }

The most recent fatal accidents in West Virginia, with the mine master joined on:

{ "datasets": ["accidents"], "states": ["WV"], "fatalitiesOnly": true, "sortBy": "newestFirst", "includeMineDetails": true, "maxItems": 200 }

Free users

Free-plan runs return up to 10 rows as a preview. Upgrade your Apify plan to collect up to 1,000,000 rows per run.

Run it

  1. Create a free Apify account with $5 in credit.
  2. Open the MSHA Mine Data Scraper.
  3. Pick one or more datasets, set maxItems, add any filters, and click Start.
  4. Export the results as CSV, Excel, JSON, or XML from the Dataset tab.

Run it programmatically through the Apify API or the ApifyClient for JavaScript and Python.

Use with AI agents (MCP)

Give an AI agent live access to MSHA data through the Model Context Protocol. Add the Actor to Claude, Cursor, or any MCP client:

claude mcp add --transport http apify "https://mcp.apify.com?tools=parseforge/msha-mine-data-scraper"

Then prompt it in plain language:

  • "List the active underground coal mines in West Virginia with more than 50 employees."
  • "Pull every violation issued at mine ID 4600015 since 2024 and total the proposed penalties."
  • "Find the most recent fatal mining accidents and summarise the narratives."

Troubleshooting

No results at all. Check that the filters you set exist on the dataset you picked. mineIds returns nothing on contractor production or conferences, because neither file carries a mine ID. degreesOfInjury only applies to accidents.

Fewer rows than I asked for. Either the filters matched fewer records than maxItems, or the run hit its time limit on a large file. Selecting several datasets splits maxItems between them unless you set maxItemsPerDataset. Free-plan runs stop at 10 rows.

A sorted run returned fewer rows than an unsorted one. Sorting has to read the whole file and hold the candidates, so it is capped by the run's memory and by a hard ceiling of 50,000 rows per dataset. The log says the cap it settled on. Narrow the filters, drop the optional joins, or use file order to get the full set.

A field is empty. MSHA leaves fields blank when it never recorded the value, and those arrive as "N/A". Coordinates are present on 51.8% of mines and sectionOfAct on 0.6% of violations; that is the source, not the scraper. Columns that are empty in every single row upstream are dropped rather than shipped.

The run is slow. File order is the fast path and stops early. A sort, or a filter that matches rarely, forces a full read of files that reach 1.4 GB uncompressed: a full pass over all 3,096,400 violations takes a couple of minutes. Narrow the date range or the mine list to cut the work.

FAQ

Question Answer
Do I need an MSHA account or API key? No. These are public Open Government Data files served without any login or rate limit.
How fresh is the data? MSHA refreshes the files every Friday afternoon. Each run reports the publication date it read.
Which datasets are included? All 20 live ones: mines, violations, assessed and contested violations, inspections, accidents, penalty dockets, conferences, 107(a) orders, addresses, controller history, four production files and five sample files.
Can I get everything for one mine in a single run? Yes. Select the datasets you want and set mineIds. Every dataset that carries a mine ID is filtered to it.
Can I filter violations by state? Yes. The violations file has no state column, so the Actor resolves it through the mine master. That lookup is loaded once and is not billed.
What is the mine ID format? Seven characters, zero padded, for example 0100003. Shorter IDs are padded for you.
How many rows per run? Free plan: 10. Paid: up to 1,000,000, bounded by what your filters match and the run's time limit.
Are the accident narratives included? Yes, the full free-text narrative from MSHA form 7000-1 is in the narrative field of every accident row.
Why are some numeric fields "N/A"? Because MSHA left them blank. The Actor never emits a literal null, so a withheld number arrives as "N/A" and a real one as a number.
Is this an official MSHA product? No. It is unofficial and reads only publicly published MSHA data files.

๐Ÿ†˜ Need help? Email parseforge@protonmail.com with your run ID, your input, and what you expected.

โš ๏ธ Disclaimer. This Actor is unofficial and is not affiliated with, endorsed by, or sponsored by the Mine Safety and Health Administration or the US Department of Labor. It collects only publicly published MSHA Open Government Data. You are responsible for using the data in compliance with applicable laws, including GDPR, CCPA, and PIPL. Accident records describe injuries to identifiable workers; do not use them to identify, profile, or target individuals.

What input does the MSHA Mine Data Scraper - Violations, Inspections, Accidents accept?

FieldTypeWhat it doesDefault
datasets array Which MSHA Open Government Data files to read. Each selected dataset is downloaded and streamed in turn, and every dataset bills its own event. Row counts are from the 2026-08-21 publication. ["mines"]
maxItems integer Free users: limited to 10 items (preview). Paid users: up to 1,000,000. This is the total across every selected dataset. 10
maxItemsPerDataset integer Cap for each selected dataset. Leave empty and the Max Items budget is split evenly across the datasets you selected. not set
mineIds array Seven digit MSHA mine IDs, for example 0100003. Shorter IDs are zero padded for you. Applies to every dataset that carries a mine ID; contractor production and conferences do not, so they return nothing when this is set. not set
companyIds array Controller, operator, contractor or violator IDs, for example 0041044 or L13586. A row matches when any of the dataset's company ID columns equals one of these. not set
states array Two letter state or territory. Datasets without a state column are matched through the mine master, which is loaded once and not billed. not set
coalOrMetal string (3 options) Restrict to coal mines or to metal and nonmetal mines. any
searchText string Case insensitive substring matched against the dataset's name columns: mine, operator, controller, contractor and violator names, plus the accident narrative. Datasets with no name column match their identifier columns instead. not set
dateFrom string Inclusive lower bound on the dataset's main date, in YYYY-MM-DD. On the four employment and production files, which only carry a calendar year, the year part is compared instead. not set
dateTo string Inclusive upper bound on the dataset's main date, in YYYY-MM-DD. not set
mineStatuses array Current mine status. Applies to the mines, addresses and controller history datasets directly, and to the rest through the mine master. not set
mineTypes array Underground, surface or facility. not set
commodities array Primary canvass commodity from the mine master. not set
subunits array Location or operation within the mine. Applies to accidents and to the four employment and production datasets. not set
documentTypes array Citation, order, safeguard or notice. Applies to the violations, assessed violations, contested violations and penalty docket datasets. not set
significantAndSubstantial string (3 options) S&S designation on the citation or order. any
negligenceLevels array Inspector's negligence finding. not set
likelihoodLevels array Gravity likelihood recorded on the citation. not set
injuryIllnessLevels array Gravity injury or illness that could reasonably be expected. not set
minPenaltyUsd number Keep only rows whose proposed penalty is at least this much. Decimals are allowed. not set
maxPenaltyUsd number Keep only rows whose proposed penalty is at most this much. Decimals are allowed. not set
degreesOfInjury array Degree of injury recorded on MSHA form 7000-1. not set
accidentClassifications array MSHA accident classification, the 29 values that appear in the file. not set
fatalitiesOnly boolean Shortcut for degree of injury FATALITY. There are 1,210 fatal records in the file. false
activityContains string Case insensitive substring of the inspection activity, for example "regular" or "103(i)". The file uses 86 activity spellings, so a substring beats an exact list. Applies to the inspections dataset only. not set
sortBy string (5 options) File order streams and stops early, which is by far the fastest. Any other order has to read the whole file before it can answer, so it costs the full download of every selected dataset and is capped at 50,000 rows per dataset. fileOrder
includeMineDetails boolean Join the mine master onto every row that carries a mine ID, adding mine name, type, status, state, county, commodity, SIC, controller, operator, employee count and coordinates. Billed per row actually enriched. Skipped on the mines dataset, which already has these columns. false
includeOperatorContact boolean Join the mine addresses of record, adding business name, contact title, street, PO box, city, state, ZIP and country. Billed per row actually enriched. false
includeProductionSummary boolean Join the latest reported calendar year from the yearly employment file, summed across subunits: hours, coal production in short tons and average employees. Billed per row actually enriched. false
proxyConfiguration object MSHA serves these files without any bot protection, so no proxy is needed. Turn one on only if your own network cannot reach arlweb.msha.gov. {"useApifyProxy":false}

How much does the MSHA Mine Data Scraper - Violations, Inspections, Accidents cost?

from $2.67 per 1,000 results

Charged forWhat it isPrice each
Actor Start Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). $0.0178 to $0.02
Dataset opened One per MSHA data file opened and streamed, whatever its size. Select three datasets, pay three. $0.0178 to $0.02
Mine record One row from the Mines master file: 60 fields including status, controller, operator, commodity, SIC and coordinates. $0.00623 to $0.007
Violation record One citation, order or safeguard from the Violations file, with gravity, negligence, penalty and termination fields. $0.00623 to $0.007
Assessed violation record One row from the Assessed Violations file, with the penalty points breakdown, amounts proposed, assessed and paid. $0.00623 to $0.007
Contested violation record One contested citation before the FMSHRC, with the judge, the original attributes and the decision attributes side by side. $0.00623 to $0.007
Inspection record One MSHA inspection event, with activity, inspector count, on-site hours and the areas covered. $0.00623 to $0.007
Accident record One accident, injury or illness from MSHA form 7000-1, including the free-text narrative and the degree of injury. $0.00623 to $0.007
Penalty docket record One civil penalty docket line, with the original and decided penalty amounts, the decision type and the appeal. $0.00623 to $0.007
Conference record One completed safety and health conference, with who requested it and how the citation ended up. $0.00623 to $0.007
107(a) order record One imminent danger order, with the mine, operator, controller, contractor and the termination date. $0.00623 to $0.007
Mine address record One mine address of record: business name, contact title, street, PO box, city, state, ZIP and country. $0.00623 to $0.007
Controller history record One controller-to-operator association at a mine, with the start and end dates on both sides. $0.00623 to $0.007
Mine production record One mine employment and production row, quarterly or yearly, by subunit: employees, hours and coal short tons. $0.00623 to $0.007
Contractor production record One contractor employment and production row, quarterly or yearly, by subunit. $0.00623 to $0.007
Coal dust or quartz sample One respirable coal dust or quartz sample: cassette, weights, concentration, occupation and void reason. $0.00623 to $0.007
Exposure or noise sample One metal/nonmetal area sample, personal health sample or noise survey, with contaminant, concentration and action taken. $0.00623 to $0.007
Mine master details added Optional. Charged only when the mine master actually resolved the row: name, type, status, state, county, commodity, SIC, controller, operator, employees, coordinates. $0.00267 to $0.003
Operator contact added Optional. Charged only when the address of record resolved: business name, contact title, street, PO box, city, state, ZIP, country. $0.00267 to $0.003
Production summary added Optional. Charged only when the yearly employment file resolved: latest reported year, hours, coal short tons, average employees. $0.00267 to $0.003

Tiered: the lower figure is the price on a higher Apify plan. Billing and the free credit live on Apify.

How do I call the MSHA Mine Data Scraper - Violations, Inspections, Accidents API?

One POST returns the dataset directly. Same shape for every scraper in the library, so swapping the slug is the only change.

POST ยท run and get results
curl -X POST "https://api.apify.com/v2/acts/parseforge~msha-mine-data-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "datasets": [
      "mines"
    ],
    "maxItems": 10,
    "coalOrMetal": "any",
    "significantAndSubstantial": "any",
    "fatalitiesOnly": false
  }'

What example inputs can I use?

Use these inputs to see how a run is configured.

input.json
{
  "datasets": [
    "mines"
  ],
  "maxItems": 10,
  "coalOrMetal": "any",
  "significantAndSubstantial": "any",
  "fatalitiesOnly": false
}

What do users say about the MSHA Mine Data Scraper - Violations, Inspections, Accidents?

No reviews yet. Be the first.

How do I report an issue with the MSHA Mine Data Scraper - Violations, Inspections, Accidents?

We build and maintain this scraper, so a problem with it comes to us. Report it on the Apify listing and the thread stays attached to the scraper where the next person can find it: open an issue.

Broken and urgent, or you would rather not post in public? Write to parseforge@protonmail.com and it reaches the people who wrote it.

What related scrapers can I use?

Run MSHA Mine Data Scraper - Violations, Inspections, Accidents on Apify All scrapers