H-1B Approvals
Approved H-1B visa petitions by employer, from USCIS.
h1b_approvals — the dataset name to pass to the Obscura API.
What one row means
One employer's H-1B petition approval/denial counts — split into initial (new) and continuing (extension/amendment) petitions — for one worksite city/state/ZIP, for one USCIS federal fiscal year; sourced one-CSV-per- fiscal-year from the USCIS H-1B Employer Data Hub (h1b_datahubexport-{year}.csv). History back to FY2009.
One row per (fiscal_year, employer, state, city, zip).
Point-in-time availability
Every Obscura dataset carries available_date: the calendar day the publisher made the row
available, day-of, with no session rounding. It is the one column a backtest filters on, and it means the
same thing on every dataset in the catalog.
For h1b_approvals: published: available_date = period_end (USCIS fiscal-year-end, Sep 30 of fiscal_year) + ~183d, USCIS's documented post-FY-close Employer Data Hub dissemination lag.
Refresh cadence
Obscura refreshes h1b_approvals weekly — the most frequent scheduled job that re-collects or re-exports it. This is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when a row became public is recorded per row in available_date.
Schema — 12 columns
The full public column list for h1b_approvals, with the meaning of every field. The same
schema is served unauthenticated at https://api.obscura.trade/v1/catalog/h1b_approvals.
| Column | Type | Description |
|---|---|---|
| fiscal_year | integer · not null | USCIS federal fiscal year the counts cover (Oct 1 of fiscal_year-1 through Sep 30 of fiscal_year), taken verbatim from CSV field 0 'Fiscal Year' of h1b_datahubexport-{year}.csv. Part of the composite primary key; the orchestrator task (h1b.rs) always re-fetches the newest present fiscal_year (still accruing) and skips older, already-final years. |
| employer | text · not null | Petitioning employer's name exactly as USCIS reports it in CSV field 1 'Employer' (raw casing/punctuation preserved; commas inside quoted CSV fields kept intact by csv_util::rows). Part of the composite primary key; rows with a blank employer are dropped during parsing (parse_csv). |
| state | text · not null | Two-letter US state abbreviation of the employer worksite location, from CSV field 8 'State'. Part of the composite primary key. |
| city | text · not null | Employer worksite city, from CSV field 9 'City', as USCIS provides it (typically uppercase). Part of the composite primary key. |
| zip | text · not null | Employer worksite 5-digit ZIP code, from CSV field 10 'ZIP'. Stored as text (not integer) because leading zeros are significant (e.g. '08854' for Piscataway, NJ) and would be lost as a number. Part of the composite primary key. |
| initial_approval | integer · not null | Count of new (first-time, non-extension) H-1B petitions USCIS approved for this employer/worksite/fiscal_year, from CSV field 2 'Initial Approval'. Defaults to 0 when the CSV cell is blank/unparseable (fn int() in h1b.rs). The core hiring/expansion signal for this dataset — new headcount, as opposed to continuing_approval which is renewals of existing staff. |
| initial_denial | integer · not null | Count of new H-1B petitions USCIS denied for this employer/worksite/fiscal_year, from CSV field 3 'Initial Denial'. Defaults to 0 on a blank/unparseable cell. |
| continuing_approval | integer · not null | Count of continuing (extension/amendment, i.e. renewing an existing H-1B worker's status) petitions USCIS approved for this employer/worksite/fiscal_year, from CSV field 4 'Continuing Approval'. Defaults to 0 on a blank/unparseable cell; distinct from initial_approval (net-new hires). |
| continuing_denial | integer · not null | Count of continuing H-1B petitions USCIS denied for this employer/worksite/fiscal_year, from CSV field 5 'Continuing Denial'. Defaults to 0 on a blank/unparseable cell. |
| naics | text | Two-digit NAICS sector code for the employer's industry (e.g. '54' Professional/Scientific/Technical Services, '51' Information), from CSV field 6 'NAICS'. Nullable: USCIS's Tax ID field (CSV field 7) is dropped entirely by the collector (never persisted, for privacy) and a blank NAICS cell is normalized to NULL rather than an empty string (h1b.rs parse_csv). |
| period_end | date | STORED generated column: make_date(fiscal_year, 9, 30) — the true natural close of the USCIS federal fiscal year (Oct 1 of fiscal_year-1 through Sep 30 of fiscal_year). The period/event basis available_date's lag is measured from. |
| available_date | date | STORED generated column: period_end (fiscal-year-end, Sep 30) + 183 days, USCIS's documented post-FY-close Employer Data Hub dissemination lag. The true public-availability date — the point-in-time column to filter/join on. Read-only. |
Access h1b_approvals
Two delivery paths, one identifier. Both require an Obscura account and an active subscription; the catalog entry and the schema above are public.
import obscura
client = obscura.Client("obs_live_…")
df = client.query(
dataset="h1b_approvals",
start="2024-01-01",
)
Create a free account Browse all 95 datasets
Frequently asked questions
What is in the h1b_approvals dataset?
Approved H-1B visa petitions by employer, from USCIS. One employer's H-1B petition approval/denial counts — split into initial (new) and continuing (extension/amendment) petitions — for one worksite city/state/ZIP, for one USCIS federal fiscal year; sourced one-CSV-per- fiscal-year from the USCIS H-1B Employer Data Hub (h1b_datahubexport-{year}.csv). History back to FY2009.
How do I avoid look-ahead bias with h1b_approvals?
Filter on h1b_approvals.available_date, the day the publisher made the row public. For this dataset that date is derived as follows — published: available_date = period_end (USCIS fiscal-year-end, Sep 30 of fiscal_year) + ~183d, USCIS's documented post-FY-close Employer Data Hub dissemination lag. A query of the form WHERE available_date <= '<as-of date>' never sees a row before it existed.
In what formats can I get h1b_approvals?
As a Parquet bulk export (POST https://api.obscura.trade/v1/download) or as JSON from the typed query API (POST https://api.obscura.trade/v1/query), both with dataset="h1b_approvals". The column schema is public at https://api.obscura.trade/v1/catalog/h1b_approvals.
How often is h1b_approvals updated?
Obscura refreshes h1b_approvals on a weekly schedule — that is the most frequent scheduled job that re-collects or re-exports the table. It is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when the publisher makes a row available is described by the availability rule above, and is recorded per row in available_date.