Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PC×
Skip to content
World desk4 min

PERM Disclosure Data in Python: Count Green Card Employers by City

A practical Python workflow for counting PERM employers by city, with guidance on choosing the right location field, release, and counting unit.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

You can use U.S. Department of Labor (DOL) PERM disclosure data in Python to count employers associated with a city—but the result depends on which location field you choose and whether you count distinct employers or case records. Start with the matching record layout for the release: an employer-address city is not necessarily the job’s worksite city.

What a PERM city count does—and does not—show

The Office of Foreign Labor Certification (OFLC) publishes selected information extracted from application tables in its case-management systems. These are administrative records, not a census of every employer sponsoring a worker, a directory of current openings, or a complete account of every application field.

As an Amazon Associate I earn from qualifying purchases.

A city-level result answers a specific question about records in a particular release. For example, grouping by an employer-address city would answer where the employer’s recorded address is associated with the cases; grouping by a place-of-employment or job-opportunity city would answer a different question. Do not call either one simply “sponsors in the city” unless the geographic definition is clear.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

PERM disclosure data is organized by federal fiscal year, which runs October 1 through September 30. At the October 7, 2026 snapshot, the latest listed quarterly file was FY2026 Q3, covering determinations issued from October 1, 2025 through June 30, 2026. Check the OFLC Performance Data page for the current file and its matching record layout; the latest release can change.

Choose the release and verify its fields

Download the workbook and its layout

Use the official OFLC Performance Data page to download the PERM disclosure workbook and the Program Record Layout for the same fiscal year and quarter. OFLC distributes the workbook as an Excel file (.xlsx); use the layout to identify field names and meanings rather than guessing from column labels.

The precise current field names for employer identity and city should be confirmed in that release’s layout before adapting the code below. In particular, establish whether the location field represents an employer address, worksite, job opportunity, or another location. A field that happens to contain a city name is not enough to establish its meaning.

Keep release eras separate unless fields are compatible

OFLC says layouts changed substantially beginning with FY2020 as new forms, appendices, and addenda were introduced through FLAG. FY2024 also has separate files for old and new forms. For a multi-year comparison, inspect each relevant layout and handle those form-era differences explicitly; do not assume that similarly named fields are equivalent.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Inspect the workbook before counting

The following Python pattern is a starting point for inspecting an .xlsx file. It uses pandas and openpyxl; it is not a claim that a particular OFLC workbook or import has been tested. Install those packages in your Python environment if needed, then set path to the downloaded workbook.

import pandas as pd

path = "perm_disclosure.xlsx"

# List worksheets before choosing one.
book = pd.ExcelFile(path, engine="openpyxl")
print(book.sheet_names)

# Read the worksheet selected after inspecting the workbook.
sheet = book.sheet_names[0]
df = pd.read_excel(path, sheet_name=sheet, engine="openpyxl")

print(df.columns.tolist())
print(df.head())
print(df.isna().mean().sort_values(ascending=False))

Use the printed sheet names, column names, sample rows, and null rates to understand the file. A worksheet’s first tab is not guaranteed to be the one you need. Match the chosen sheet and column meanings to the release’s record layout, then replace the example column names in the next section with the exact verified names.

Count distinct employers by city in Python

For a sponsor-oriented count, distinct employers are usually more informative than rows: an employer can appear in multiple cases. Use the employer identifier specified by the layout where available, rather than assuming that employer names are unique. The example below deliberately uses clearly labeled stand-ins; replace them with verified column names before running it.

employer_col = "VERIFIED_EMPLOYER_IDENTIFIER"
city_col = "VERIFIED_CITY_FIELD"
state_col = "VERIFIED_STATE_FIELD"  # Use only if this field exists in the layout.

# Preserve source values and make conservative normalized matching keys.
df["city_original"] = df[city_col]
df["city_key"] = df[city_col].astype("string").str.strip().str.casefold()
df["employer_key"] = df[employer_col].astype("string").str.strip()

# Include state when available so same-named cities are not merged.
if state_col in df.columns:
    df["state_key"] = df[state_col].astype("string").str.strip().str.casefold()
    group_cols = ["city_key", "state_key"]
else:
    group_cols = ["city_key"]

valid = df["city_key"].notna() & df["city_key"].ne("")
valid &= df["employer_key"].notna() & df["employer_key"].ne("")

counts = (
    df.loc[valid]
      .groupby(group_cols)["employer_key"]
      .nunique()
      .rename("distinct_employers")
      .reset_index()
      .sort_values("distinct_employers", ascending=False)
)

print(counts.head(20))

Normalization above trims surrounding whitespace and case-folds the matching key; it does not try to infer that differently spelled place names are the same city. Keep the original values for review. If the layout provides state, group by city and state to reduce the risk of combining distinct cities with identical names.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If your question is instead how many case records have a city value, count rows rather than distinct employer identifiers. Label that output as cases or determinations, not employers; the two measures answer different questions.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Interpret and report the result responsibly

  • State the geography: name the verified location field and explain whether it represents employer address, worksite, job opportunity, or another location.
  • State the unit: say whether a value counts distinct employers or case records.
  • Identify the release: include fiscal year and quarter, and give the determination coverage dates where relevant.
  • Explain missing locations: disclose whether blank location values were excluded; the example excludes blank city and employer identifiers.
  • Keep comparisons compatible: specify the form era and check that field meanings remain comparable across releases.

OFLC notes that data may contain blanks and anomalies from application or data-entry errors. Some records may not appear because cases are still pending without final determinations, information is personally identifiable, or open-text fields are difficult to extract in usable form. A fiscal-year dataset contains unique records keyed by OFLC case number and reflects the most recent date a determination decision was issued; some determinations can change in later quarterly releases after appeals or redeterminations.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.