USCIS H-1B Employer Data: Approvals and Denials by Company avatar

USCIS H-1B Employer Data: Approvals and Denials by Company

Pricing

from $1.40 / 1,000 employer rows

Go to Apify Store
USCIS H-1B Employer Data: Approvals and Denials by Company

USCIS H-1B Employer Data: Approvals and Denials by Company

Official USCIS H-1B employer files as rows: fiscal year, employer, initial and continuing approvals and denials, totals and denial rate, NAICS sector with its name, tax-ID last four, city, state and ZIP. Filter by employer, state, city, industry, ZIP or petition volume. FY2009-FY2023, UTC dates.

Pricing

from $1.40 / 1,000 employer rows

Rating

0.0

(0)

Developer

Samat Makatov

Samat Makatov

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Categories

Security

Limited permissions

Share

Official USCIS H-1B employer files as rows: fiscal year, employer, initial and continuing approvals and denials, totals and denial rate, NAICS sector with its name, tax-ID last four, city, state and ZIP. Filter by employer, state, city, industry, ZIP or petition volume. FY2009-FY2023, UTC dates.

This actor reads the H-1B Employer Data Hub files published by U.S. Citizenship and Immigration Services — one CSV per fiscal year, no key and no account — and turns them into filtered, sorted dataset rows. One published row is one employer in one fiscal year with the counts of workers USCIS first decided on: initial employment and continuing employment, approvals and denials. On top of the published columns every row gets the totals, the number of decisions and the denial rate, the plain name of the NAICS sector and the full name of the state, so a dataset reads without a code table. Fiscal years 2009 through 2023 are published as files; a fiscal year runs 1 October to 30 September. No API key, no proxy, no browser.

Need it tailored to your workflow? Missing a field, a filter, another source or a different output format? Open an issue and describe what you need — we read every request and adapt the actor.

Use cases

  • One company's H-1B record — employers: ["microsoft"] with a fiscal year: every entity whose filed name contains that text, with approvals, denials and the denial rate. Case, punctuation and spaces are ignored, so walmart finds WAL MART ASSOCIATES INC. For journalists and analysts after a news story.
  • The biggest sponsors in a state — states: ["CA"], minTotalApprovals: 50, sort: "approvalsDesc": the long alphabetical tail of one-petition employers disappears and the employers that sponsor at scale come first. For recruiters, relocation services and sales teams.
  • Where decisions went against the employer — naics: ["54"], minTotalDenials: 1, sort: "denialsDesc", or maxDenialRate: 0.05 for the other direction. For immigration lawyers and in-house mobility teams.
  • A five-year sponsor profile — mode: "employerTotals" with five fiscal years: one row per employer with yearCount, firstFiscalYear, lastFiscalYear and the summed counts. For investor and policy research.
  • Sponsors in one city — cities: ["Seattle"]: who files H-1B petitions from a city, largest first. For job seekers and local press.
  • A watch on a state or an industry — onlyNew: true: each run writes only rows that were not written before, so you never pay twice for the same employer when you re-run a watch with wider filters, take the next maxItems rows of a long list, or add a fiscal year to it. The published files do not change, so a schedule on the same input writes rows until the list is exhausted; a fiscal year USCIS publishes later has to be chosen in fiscalYears once this actor lists it.

Input

Every field is optional. A run with nothing but fiscalYears returns the top maxItems employers of that year by approvals.

FieldTypeDefaultAllowed values / notes
modestring (enum)byYearbyYear = one row per employer per fiscal year, as published. employerTotals = one row per employer with the selected fiscal years summed up (adds yearCount, firstFiscalYear, lastFiscalYear, fiscalYearsCovered, and has no fiscalYear). Strict: the platform refuses any other value before the run starts.
fiscalYearsstring[] (enum)prefill ["2023"], empty = FY2023One file per year: 2023 … 2009 (all years). Strict enum — FY2024 and later are refused before the run starts, because they are not published as files (see Limits). Max 15 values.
employersstring[] (free text)prefill ["microsoft"]Matched inside the employer name as filed: microsoft, deloitte, mayo clinic. Case, punctuation and spaces are ignored — walmart finds WAL MART ASSOCIATES INC; several values are OR. The value that found a row is written to matchedEmployer. A value that matched nothing is named in the run's status message; a value written in another script (日本電気株式会社) matches nothing, because the files hold the names in ASCII capitals. Max 20 values.
statesstring[] (enum)—Two-letter codes of the employer's mailing address (all 56 codes), OR-combined. Strict enum. stateName is written to every row.
citiesstring[] (free text)—Whole city name: Seattle, NEW YORK, san jose. Case and extra spaces are ignored, several values are OR; york does not match NEW YORK. Unmatched values are named in the status message. Max 20.
zipPrefixesstring[] (free text)—A full ZIP (98101) or its first 2-5 digits (100 keeps every 100xx ZIP). Several values are OR; combined with states/cities as AND. Anything that is not 2-5 digits is refused with a message. Max 20.
naicsstring[] (enum)—Two-digit NAICS sectors (all 25), OR-combined. Strict enum. 99 is the file's own "industry unknown". naicsLabel is written to every row.
minTotalApprovalsinteger—Keep rows with at least this many approved workers (totalApprovals). In employerTotals the threshold applies to the summed row.
minTotalDenialsinteger—Keep rows with at least this many denied workers (totalDenials). 1 = every row where a decision went against the employer.
maxDenialRatenumber—Keep rows whose denialRate is at most this share (0.1 = refused in at most a tenth of the decisions). Rows with no decision at all have no rate and are dropped by this filter.
sortstring (enum)approvalsDescapprovalsDesc, denialsDesc, denialRateDesc, employer, fiscalYear. Strict enum. In byYear the order is applied inside each fiscal year (years are written newest first); in employerTotals to the whole result.
maxItemsinteger501-5000. Hard cap on the rows this run writes, and therefore on what it costs.
onlyNewbooleanfalseRemember the rows written and, on the next run of the same actor or task, write only rows that were not written before — a rerun therefore returns the next rows of the list, not nothing. The published files do not change, so this is a way to avoid paying twice, not a freshness window: the files carry no per-row timestamp and a new fiscal year has to be chosen in fiscalYears.
fieldsstring[] (free text)all columnsKeep only these columns, in this order; fiscalYear, employer, totalApprovals, totalDenials, url and fetchedAt are always kept (first, unless you list them yourself, and then where you put them). Column names are matched ignoring case and underscores, and a few short names work (approvals, denials, decisions, rate, industry, year, taxid). A name that is none of these is reported in the run's status message with the closest column; if no name is a column at all, the run stops at once and names them.

Reference

Fiscal years

2023, 2022, 2021, 2020, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012, 2011, 2010, 2009.

A fiscal year runs from 1 October of the previous calendar year to 30 September (FY2023 = 1 October 2022 to 30 September 2023). Each year is a separate file and a separate download. FY2023 is the newest year published as a file; a value outside this list is refused by the platform before the run starts, with the list of allowed values.

NAICS sectors

CodeSector
11Agriculture, forestry, fishing and hunting
21Mining, quarrying, oil and gas extraction
22Utilities
23Construction
31Manufacturing: food, textiles, apparel
32Manufacturing: wood, paper, chemicals, plastics
33Manufacturing: metals, machinery, electronics, vehicles
42Wholesale trade
44Retail trade: vehicles, building, food, health stores
45Retail trade: clothing, sports, general and online stores
48Transportation
49Postal service, couriers and warehousing
51Information: software publishing, telecoms, media
52Finance and insurance
53Real estate, rental and leasing
54Professional, scientific and technical services (IT consulting, engineering, research)
55Management of companies and enterprises
56Administrative and support services (staffing agencies)
61Educational services (universities, schools)
62Health care and social assistance (hospitals, clinics)
71Arts, entertainment and recreation
72Accommodation and food services
81Other services except public administration
92Public administration
99Industry unknown, as the file records it

naicsLabel in every row carries the sector name from this table. Code 99 covers a large share of the smaller employers: the file itself does not know their industry.

States and territories

AL Alabama · AK Alaska · AZ Arizona · AR Arkansas · CA California · CO Colorado · CT Connecticut · DE Delaware · DC District of Columbia · FL Florida · GA Georgia · HI Hawaii · ID Idaho · IL Illinois · IN Indiana · IA Iowa · KS Kansas · KY Kentucky · LA Louisiana · ME Maine · MD Maryland · MA Massachusetts · MI Michigan · MN Minnesota · MS Mississippi · MO Missouri · MT Montana · NE Nebraska · NV Nevada · NH New Hampshire · NJ New Jersey · NM New Mexico · NY New York · NC North Carolina · ND North Dakota · OH Ohio · OK Oklahoma · OR Oregon · PA Pennsylvania · RI Rhode Island · SC South Carolina · SD South Dakota · TN Tennessee · TX Texas · UT Utah · VT Vermont · VA Virginia · WA Washington · WV West Virginia · WI Wisconsin · WY Wyoming · PR Puerto Rico · GU Guam · VI U.S. Virgin Islands · AS American Samoa · MP Northern Mariana Islands.

The state is the employer's mailing address on the petition, not the worksite. Some rows of the oldest files carry no state at all; those rows can never match a state filter.

Sort orders

  • approvalsDesc — most approved workers first (the default; the published files are alphabetical).
  • denialsDesc — most denied workers first.
  • denialRateDesc — highest share of denials first; rows without a single decision go last.
  • employer — employer name, A to Z.
  • fiscalYear — newest fiscal year first, then most approvals.

Examples

One company in the newest published year

{ "mode": "byYear", "fiscalYears": ["2023"], "employers": ["microsoft"], "sort": "approvalsDesc", "maxItems": 25 }

Every Microsoft entity in FY2023 with its approvals, denials and denial rate.

The biggest sponsors in California, with chosen columns

{
"fiscalYears": ["2023"],
"states": ["CA"],
"minTotalApprovals": 50,
"sort": "approvalsDesc",
"maxItems": 25,
"fields": ["employer", "state", "totalApprovals", "denialRate"]
}

Californian employers with 50 or more approved workers, largest first, narrowed to four columns (plus the always-kept ones).

Denials in technical services

{ "fiscalYears": ["2023"], "naics": ["54"], "minTotalDenials": 1, "sort": "denialsDesc", "maxItems": 25 }

IT consulting, engineering and research employers with at least one denied worker, most denials first.

Five fiscal years of one employer group, summed

{ "mode": "employerTotals", "fiscalYears": ["2023", "2022", "2021", "2020", "2019"], "employers": ["amazon"], "maxItems": 20 }

One row per Amazon entity with the five years added up, yearCount and the first and last year with decisions.

Hospitals and clinics above a size threshold

{ "fiscalYears": ["2023"], "naics": ["62"], "minTotalApprovals": 10, "sort": "approvalsDesc", "maxItems": 25 }

Universities in one state, 20 rows at a time

{ "fiscalYears": ["2023"], "naics": ["61"], "states": ["MA"], "onlyNew": true, "maxItems": 20 }

Run it again and the next 20 Massachusetts universities arrive, without paying for the first 20 twice.

Output

A real row from a cloud run of 2026-10-08 (byYear mode, FY2023, employers: ["microsoft"]):

{
"fiscalYear": 2023,
"sourceRow": 18720,
"employer": "MICROSOFT CORPORATION",
"matchedEmployer": "microsoft",
"taxIdLast4": "4442",
"naics": "51",
"naicsLabel": "Information: software publishing, telecoms, media",
"city": "REDMOND",
"state": "WA",
"stateName": "Washington",
"zip": "98052",
"initialApprovals": 39,
"initialDenials": 0,
"continuingApprovals": 1950,
"continuingDenials": 45,
"totalApprovals": 1989,
"totalDenials": 45,
"totalDecisions": 2034,
"denialRate": 0.0221,
"sourceMode": "byYear",
"url": "https://www.uscis.gov/sites/default/files/document/data/h1b_datahubexport-2023.csv",
"fetchedAt": "2026-10-08T20:02:55.704Z"
}
FieldTypeMeaning
fiscalYearintegerFiscal year of the file the row comes from. Always present in byYear; absent in employerTotals.
sourceRowintegerThe data line of the file this row was read from. A few lines repeat an employer, an address and the same counts exactly; this is what tells them apart. byYear only.
employerstringPetitioner name as filed, in capitals and often shortened. Empty on the rows where the file carries no name.
matchedEmployerstringThe employers value that found this row; empty when no employer filter was used.
taxIdLast4stringLast four digits of the petitioner's tax id, as published. Empty where the file leaves it empty.
naicsstringTwo-digit NAICS sector as the file records it; 99 = unknown, empty = no code in the file.
naicsLabelstringPlain name of the sector (computed by this actor).
city, state, zipstringEmployer's mailing address as filed. state and zip are empty on some rows of the oldest files.
stateNamestringFull name of the state code (computed by this actor).
initialApprovals, initialDenialsintegerWorkers first decided for initial employment.
continuingApprovals, continuingDenialsintegerWorkers first decided for continuing employment (extensions, employer changes, amended petitions).
totalApprovals, totalDenials, totalDecisionsintegerThe four published counts added up — computed by this actor, not published. Always present.
denialRatenumber or nulltotalDenials / totalDecisions, four decimals — computed by this actor; null when the row holds no decision at all.
yearCount, firstFiscalYear, lastFiscalYear, fiscalYearsCoveredinteger / integer[]employerTotals only: how many of the selected fiscal years carry decisions for this employer, and which.
sourceModestringbyYear or employerTotals.
urlstringThe fiscal-year file the row was read from. The published rows have no page of their own, so the file is the row's provenance. Always present.
fetchedAtstringWhen this run read the file, ISO 8601 UTC. Always present.

Dataset views: H-1B employers (employer, place, industry name, the approval split, denials, rate), Decisions in detail (the four published counts plus the computed ones), Employer totals over the selected years.

Use it from code / agents

curl -X POST "https://api.apify.com/v2/acts/yadroo~uscis-h1b-employers/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"fiscalYears":["2023"],"states":["CA"],"minTotalApprovals":50,"sort":"approvalsDesc","maxItems":25}'
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('yadroo/uscis-h1b-employers').call({
fiscalYears: ['2023'],
employers: ['microsoft'],
maxItems: 25,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("yadroo/uscis-h1b-employers").call(run_input={
"mode": "employerTotals",
"fiscalYears": ["2023", "2022", "2021"],
"employers": ["amazon"],
"maxItems": 20,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items

MCP: add https://mcp.apify.com to Claude / Cursor / any MCP client and call the yadroo/uscis-h1b-employers tool with the same JSON input. Two things help an agent: fields keeps the answer small (["employer","totalApprovals","denialRate"]), and mode, fiscalYears, states, naics and sort are validated by the platform before the run starts, so a wrong value comes back as an error with the allowed values instead of a wrong dataset.

Pricing

Pay per event: $0.001 per run start + $0.002 per dataset row. The start event is charged on every run, including a run that ends with no rows. Tier discounts apply to the row event (Bronze −10 %, Silver −20 %, Gold and above −30 %); the start event is flat.

Typical runs at the full price:

  • a company lookup in one fiscal year, 5 rows: 0.001 + 5 × 0.002 = $0.011;
  • a state shortlist, 25 rows: 0.001 + 25 × 0.002 = $0.051;
  • the default 50 rows: 0.001 + 50 × 0.002 = $0.101;
  • a five-year totals run, 20 rows: 0.001 + 20 × 0.002 = $0.041 (reading five files costs time, not rows).

Every row written to the dataset is charged, and only rows: an employer filter that matched nothing writes no marker row, so you pay the start event alone and the status message tells you what did not match. Reading a file always costs the same few seconds whatever maxItems is, so filter first, sort second and keep maxItems small. The run stops as soon as your Maximum cost per run is reached, keeps every row it already wrote and says so in its status message ("Stopped at your spending limit: N rows delivered").

Limits & FAQ

FY2024 and later are not in here. Only fiscal years 2009 to 2023 are published as files. Newer years exist inside the interactive data hub, whose pages and export buttons the site's robots.txt closes to automated clients, so this actor does not read them and offers no workaround.

Speed and the site's pace. robots.txt of uscis.gov asks for a crawl delay of 10 seconds, and this actor keeps it: one request per 10 seconds to the site, retries included. Everything else is fast. Measured in the Apify cloud on 2026-10-08: a one-fiscal-year run takes 4-7 seconds end to end (the FY2023 file is 2.1 MB with 33,332 published rows, FY2022 3.9 MB with 59,983 rows, and each one downloads and parses in well under a second); a run over all 15 published fiscal years read 15 files and wrote 913 rows in 145 seconds — about 6 files and 380 rows a minute, nearly all of it waiting politely between requests. Nothing was throttled or blocked in that run. The largest input the schema allows therefore fits comfortably into the 900 s run timeout, and a run that still would not fit stops by itself, keeps the rows it has written and says so ("Stopped before the run timeout: N rows saved" — verified in the cloud with a 60 s run timeout: 40 rows of 4 fiscal years kept).

What the numbers are and are not. They are first decisions on petitions — appeals, revocations, reopened cases and pending petitions are not in them, so a case later won on appeal still counts as a denial here. They count workers, not petitions in flight. The address is the employer's mailing address, not the worksite, so a national employer filing from one headquarters appears in one state only. 99 means the file does not know the industry; some rows of the oldest files have no state and no ZIP, and some rows of the newest files have no employer name at all — those rows are real decisions and are kept, with empty values. Data-entry spellings in the source are kept as filed (SAGINAW VLY ST UNIV), which is why the employer filter matches a part of the name. The files themselves are not uniform — the newest ones name the columns "Initial Approval", the older ones "Initial Approvals", and the quoting differs too; the actor reads both and stops with the header it saw if a column is ever missing.

Repeated lines and employer identity. A few lines of the published files repeat an employer, an address and the same counts exactly; every published line becomes its own row and sourceRow tells them apart. In employerTotals mode employers are grouped by their name (ignoring case and punctuation) plus taxIdLast4, so

AMAZON.COM SERVICES LLC
and AMAZON COM SERVICES LLC are one employer — but a changed legal form (… INC to … LLC) counts as two, because the files give no company id beyond the name and the four digits. A totals run with no employer, state, city, ZIP or industry filter is cut at 120,000 employers; the status message says so when it happens.

Not personal data. The rows carry an employer name plus the last four digits of a tax id — an employer identifier. No beneficiaries, no salaries, no contact details.

H-1B is not a green card. This is the record of H-1B petition decisions. It says nothing about permanent residence, PERM or the green-card lottery.

Salaries are elsewhere. Wages and job titles come from the Department of Labor's own disclosure data, a different dataset that is not in this actor.

Empty results. A filter that matched nothing is a successful run with no rows and a status message naming what did not match (an employer value, a city) — never a silent empty dataset. With onlyNew a run that finds nothing new says so and how many matching rows earlier runs already delivered. A bad value (a ZIP that is not digits, a denial rate above 1) stops the run at once with a message saying what to change, and an off-list value in one of the enum fields is refused by the platform before the run even starts.

Questions or problems: open an issue on the Issues tab of this actor.


Made by Yadroo. Sibling actors: federal-register-documents · sec-edgar-filings · data-gov-datasets · bls-release-calendar · himalayas-remote-jobs