OSHA Safety Search — establishment inspection records
Pricing
from $13.40 / 1,000 resolved safety records
OSHA Safety Search — establishment inspection records
Look up an establishment's OSHA inspection record by name or inspection number in the DOL's official OSHA enforcement data: site, dates, NAICS, inspection codes, violation counts and penalty totals. Official source. No API key. Pay per record.
Pricing
from $13.40 / 1,000 resolved safety records
Rating
0.0
(0)
Developer
NexGen Watch
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Share
📚 OSHA Safety Search — establishment inspection records
OSHA inspection records by establishment name or inspection number, from the U.S. Department of Labor's own OSHA enforcement data. Give it company names or OSHA activity numbers; for each one you get the inspection: establishment name and site address, open and close dates, NAICS and SIC codes, the inspection type, scope, union and owner codes as OSHA records them, employees at the site, and the citation summary — violation count by type code and the initial and current penalty totals in US dollars.
Official source. No API key. Pay per record. The data is the DOL's public bulk download of the OSHA inspection and violation tables (data.dol.gov), refreshed by DOL daily. Every row carries data_as_of, the date of the DOL file it came from.
Why it changed (2026-10-03). This actor used to read OSHA's IMIS establishment search pages. Since late September 2026 those pages answer 403/405 to every automated request, so the actor failed (loud and unbilled) on every run. It now searches an index built from the same enforcement data that IMIS shows, published by DOL as bulk files.
Output is one safety_record row per result; billing is pay-per-event, the value event being one resolved safety record (a $0.02 start fee per run, then $0.02 per resolved safety record). Source: data.dol.gov, www.osha.gov.
Who buys this
Buyers usually search for OSHA inspections or OSHA violations.
- Sales and lead-generation teams building lists from OSHA inspections.
- KYB, onboarding and compliance teams checking OSHA violations.
- Market researchers and data teams that need the official record as rows.
📊 Sample Output
Real rows from run RJYxcUcdv5pgFHEGq on build 0.1.28 (2026-10-03), the same input as the Quick start below — every value is as the source published it (emails masked, long text shortened):
| input | resolved | establishment_name | establishment_site | site_address | data_as_of |
|---|---|---|---|---|---|
| 348668104 | True | JMG CUSTOMS METALS SHOP INC | 7318 NW 79TH TERRACE, MEDLEY, FL 33166 | 7318 NW 79TH TERRACE | 2026-10-02T11:04:28Z |
| Amazon | False | 2026-10-02T11:04:28Z |
The run finished with the status message: PARTIAL: 1 resolved (1 ambiguous refusals, 0 unavailable) of 2; data as of 2026-10-02T11:04:28Z | safety-record billable=1 | safety-record charged=1
✅ What you get
Each row is flat JSON with these fields (from the dataset schema and the sample run; a field the source does not publish for a given row is null):
record_type(string) — e.g.safety_recordinput(string/null) — e.g.348668104resolved(boolean/null) — e.g.Truefound(boolean/null) — e.g.Trueactivity_id(string/null) — e.g.348668104establishment_name(string/null) — e.g.JMG CUSTOMS METALS SHOP INCestablishment_site(string/null) — e.g.7318 NW 79TH TERRACE, MEDLEY, FL 33166site_address(string/null) — e.g.7318 NW 79TH TERRACEsite_city(string/null) — e.g.MEDLEYstate(string/null) — e.g.FLsite_zip(string/null) — e.g.33166date_opened(string/null) — e.g.2025-12-30close_conference_date(string/null) — e.g.2025-12-30close_case_date(string/null) — null in every sample rowcase_modified_date(string/null) — e.g.2026-10-01naics(string/null) — e.g.332999sic(string/null) — null in every sample rowinspection_type(string/null) — e.g.Cscope(string/null) — e.g.Bunion_status(string/null) — e.g.Bsafety_or_health(string/null) — e.g.Sowner_type(string/null) — e.g.Aemployees_at_site(integer/null) — e.g.3reporting_office_id(string/null) — e.g.0418800violations_total(integer/null) — e.g.8violations_by_type(object/null) — e.g.{"S": 8, "W": 0, "R": 0, "O": 0}penalty_initial_usd(number/null) — e.g.16143penalty_current_usd(number/null) — e.g.16143last_citation_date(string/null) — e.g.2026-04-17detail_url(string/null) — e.g.https://www.osha.gov/ords/imis/establishment.inspection_detail?id=348668104data_as_of(string/null) — e.g.2026-10-02T11:04:28Zsource(string/null) — e.g.U.S. Department of Labor enforcement data (data.dol.gov), OSHA inspection + violunavailable_reason(string/null) — e.g.ambiguous_refusal_with_candidatesestablishment_query(string/null) — e.g.Amazonmatch_count(integer/null) — e.g.819candidates(array/null) — e.g.[{"activity_id": "349167437", "establishment_name": "AMAZON.COM SERVICES LLC - Prefusal(string/null) — e.g.'Amazon' is ambiguous: 819 OSHA inspections match (newest first below). This isnote(string/null) — null in every sample row
⚙️ Sample inputs
1. Quick start — the Store example (this is what the sample above came from)
{"establishments": ["348668104","Amazon"]}
The sample run charged exactly: 1 × $0.02 apify-actor-start + 1 × $0.02 safety-record = $0.04 on the Free tier — every delivered row was billed.
This actor takes no size cap or filter beyond the input above, so the Store example is the one input to run; put it on a schedule to keep the data current.
🧾 JSON sample record
One real record from run RJYxcUcdv5pgFHEGq, exactly as it lands in the dataset (emails masked, long text shortened):
{"record_type": "safety_record","input": "348668104","resolved": true,"found": true,"activity_id": "348668104","establishment_name": "JMG CUSTOMS METALS SHOP INC","establishment_site": "7318 NW 79TH TERRACE, MEDLEY, FL 33166","site_address": "7318 NW 79TH TERRACE","site_city": "MEDLEY","state": "FL","site_zip": "33166","date_opened": "2025-12-30","close_conference_date": "2025-12-30","close_case_date": null,"case_modified_date": "2026-10-01","naics": "332999","sic": null,"inspection_type": "C","scope": "B","union_status": "B","safety_or_health": "S","owner_type": "A","employees_at_site": 3,"reporting_office_id": "0418800","violations_total": 8,"violations_by_type": {"S": 8,"W": 0,"R": 0,"O": 0},"penalty_initial_usd": 16143,"penalty_current_usd": 16143,"last_citation_date": "2026-04-17","detail_url": "https://www.osha.gov/ords/imis/establishment.inspection_detail?id=348668104","data_as_of": "2026-10-02T11:04:28Z","source": "U.S. Department of Labor enforcement data (data.dol.gov), OSHA inspection + violation tables","unavailable_reason": null}
🔧 How it works
Transport. Plain HTTPS from the Apify platform, no proxy.
Charging. Each resolved safety record is charged at the moment it is pushed (safety-record). Refusals and notices are pushed to the dataset too, uncharged, so the dataset can hold more rows than were charged; the run's status message gives both counts.
Source. DOL's public OSHA bulk files: https://data.dol.gov/data-catalog/OSHA/inspection/OSHA_inspection.zip (about 5.2 million inspections) and https://data.dol.gov/data-catalog/OSHA/violation/OSHA_violation.zip (about 13.3 million citation lines). No login, no key. A weekly publisher job reads both files (only when DOL has published a newer file), adds up each inspection's citations (deleted citations excluded), and stores a compact index split into small pieces. A run reads one index piece per query, so a typical run takes a few seconds.
Matching. A number is looked up as an OSHA activity number (the inspection number, nine digits for recent inspections). A name matches establishments whose name starts with it, after removing punctuation and a leading "The" ("Amazon" matches "AMAZON.COM SERVICES LLC"); add a two-letter state to narrow (Acme, TX). One match is a record. No match is a sourced "not found" record. Several matches give a refusal listing up to 30 candidates, newest first, with their activity numbers, and that refusal is not charged.
Codes. Inspection type, scope, union status, owner type and safety/health are given as the one-letter codes OSHA publishes; violation counts are keyed by OSHA's violation type code (S, W, R, O). This actor does not translate the codes into words, because DOL's code list sits behind its API key. OSHA's own field definitions are at osha.gov/data/inspection-detail-definitions.
What is not charged. Ambiguous names (refusal with candidates), an IMIS-style id with a decimal (e.g. 1908104.015) that is not an activity number, empty queries, and index outages are delivered as notices and never charged. If nothing in a run resolves, the run FAILS and charges nothing.
Freshness. data_as_of on every row is the DOL file date. Recent inspections can still be open: penalties and citations change until the case closes (close_case_date). detail_url is OSHA's inspection page for that activity number; this actor builds the link but does not read it.
What is not done. No login, no cookie or CAPTCHA bypass, no private or personal-account data, no browser automation.
💰 Pricing example
| Event | Free | Bronze | Silver | Gold |
|---|---|---|---|---|
Actor Start (apify-actor-start) | $0.02 | $0.02 | $0.02 | $0.02 |
Resolved safety record (safety-record) | $0.02 | $0.018 | $0.016 | $0.0134 |
Worked at the live Free-tier price:
- 2 resolved safety records: $0.02 start + 2 × $0.02 = $0.06
- 25 resolved safety records: $0.02 start + 25 × $0.02 = $0.52
- 100 resolved safety records: $0.02 start + 100 × $0.02 = $2.02
A run that delivers zero rows charges the $0.02 start fee only. A BLOCKED run (source refused) fails loud and charges no value event. The start fee is charged once per GB of run memory; the default run memory is 1024 MB.
Yield on the sample run: PARTIAL: 1 resolved (1 ambiguous refusals, 0 unavailable) of 2; data as of 2026-10-02T11:04:28Z | safety-record billable=1 | safety-record charged=1.
⚖️ Legal & ToS
This actor reads public, logged-out pages and feeds published by data.dol.gov, www.osha.gov. It collects only what the source publishes to any visitor, identifies itself, and does not access accounts, private data or anything behind authentication. Use the output in line with the source's terms and your local law; the intended use is B2B research and monitoring.
❓ FAQ
Q: Do I need an API key or a login?
A: No. The source (data.dol.gov, www.osha.gov) is read logged-out; the input schema has no key field and the actor carries no secrets.
Q: Why did my run return 0 rows?
A: Read the run's status message. GENUINE_EMPTY means the source was read and had nothing in scope for your input; BLOCKED means the source refused and the run failed without billing a value event — retry later or narrow the input. A zero-row run bills the start fee only.
Q: How fresh is the data?
A: Every run reads the source live at run time; nothing is cached between runs. Put it on a schedule for a continuous feed.
Q: What formats can I export?
A: The dataset downloads as JSON, CSV, Excel, XML or RSS from the run's Dataset tab or the Apify API, and any run can push to a webhook or integration.
Q: How is this different from the other public records lookups actors?
A: Same output shape and billing model; this one covers data.dol.gov, www.osha.gov. The siblings under Related Actors cover the other sources or slices — run several on one schedule for a combined feed.
Q: Are there rate limits?
A: The actor paces itself against the source; there is no per-buyer limit beyond your Apify plan's concurrency.
🆘 Troubleshooting
- Run FAILED with BLOCKED → the source refused the request or changed its page shape → nothing was billed beyond the start fee; retry after a while, and if it persists open an Issue with the run id.
- Fewer rows than expected → the source had fewer items in scope → widen the input.
- Input validation error on start → a field is outside the schema's allowed values → start from the Quick start block and change one field at a time.
- Run TIMED-OUT → a very wide request on a slow day → raise the run timeout in Run options or narrow the input; what was delivered before the timeout is still in the dataset.
🔗 Related Actors
- Eurostat Tertiary Education Graduates (educ_uoe_grad02) — Structured graduates from tertiary education by ISCED level, field of education and sex, from Eurostat (the UOE data collection), read directly from…
- Eurostat Monthly Tourism Arrivals (tour_occ_arm) — Structured monthly tourist arrivals at accommodation establishments — by residence of the tourist and accommodation type — from Eurostat, read direct…
- Eurostat Tourism Nights (tour_occ_nim) — Structured nights spent at tourist accommodation establishments (monthly) from Eurostat, read directly from the official Eurostat dissemination API (…
- UK Legislation Section Retrieval — legislation.gov.uk — Retrieve individual sections of UK legislation from the official legislation.gov.uk service
- US Federal Register Rules Scraper — Scrape US Federal Register rules and proposed rules: agency, title, document type, dates and docket. Every run returns the current records as a datas…
- 🏢 About NexGen Watch — NexGen Watch is a catalog of more than 300 public data actors built on official sources, pay-per-result. Browse the catalog at apify.com/nexgenwatch.
⭐ Found this useful?
If this actor saved you a manual check, a quick review on the Apify Store helps other teams find it. Feature request or a source that changed? Open it from the Issues tab — every one is read.
