The National Labor Relations Board is the independent federal agency that administers union representation elections, investigates unfair labor practice charges, and adjudicates disputes under the National Labor Relations Act. Its case database—spanning tens of thousands of election petitions, ULP charges, and Board decisions each year—is the authoritative public record of labor organizing activity, employer and union conduct, and the legal standards governing collective bargaining in the United States private sector.
The NLRB: structure and jurisdiction
The National Labor Relations Board was created by the National Labor Relations Act of 1935—commonly called the Wagner Act after its Senate sponsor, Robert F. Wagner of New York—and stands as one of the New Deal's most consequential institutional creations. The Board consists of five members appointed by the President and confirmed by the Senate, serving staggered five-year terms. One member is designated Chair. The NLRB General Counsel, separately appointed and confirmed, functions as an independent prosecutorial authority: the GC decides whether ULP charges are meritorious enough to issue a formal complaint and litigate before the Board. The Board and the GC are institutionally independent—a structural feature designed to separate the prosecutorial and adjudicative functions and prevent a single political appointee from controlling both.
The agency operates through 26 regional offices, each headed by a Regional Director who has authority to investigate charges, conduct elections, issue complaints, and in some cases seek 10(j) injunctive relief in federal district court. The regional offices handle the initial case processing; contested matters are appealed to the Board in Washington, which issues published decisions that constitute binding precedent in the labor law system. Board decisions are appealable to the US Courts of Appeals—typically the D.C. Circuit or the circuit where the employer is located—and ultimately to the Supreme Court.
The NLRA's coverage is broad but contains significant exclusions that define which workers can invoke its protections. The Act covers most private-sector employees. Explicitly excluded are: agricultural laborers and domestic workers (exclusions inserted in 1935 to preserve Southern political support and widely criticized as racially discriminatory in intent); supervisors (employees who exercise genuine authority to hire, fire, discipline, or direct other employees using independent judgment—a frequently litigated line given that many workers carry nominal supervisory titles); independent contractors (whose classification turns on a common-law agency test balancing the degree of control, method of payment, furnishing of tools, and entrepreneurial opportunity); and employees of railway and airline carriers, who are covered by the Railway Labor Act of 1926 and administered by the National Mediation Board instead.
Public-sector employees at the federal level are covered by the Civil Service Reform Act and the Federal Labor Relations Authority, not the NLRA. State and local public employees are governed by state public employee relations acts in states that have enacted them—roughly half the states extend collective bargaining rights to state and local workers; the remainder do not. This fragmentation means the NLRB's jurisdiction covers approximately 100 million private-sector employees but excludes roughly 23 million public-sector workers and an indeterminate number of independent contractors whose legal status is actively contested.
Representation election petition types: R cases
The NLRB's election function is administered through “R cases”—representation cases—which include several distinct petition types, each with its own procedural path:
- RC (Representation, Certification of Representative): filed by a union or group of employees seeking to be certified as the exclusive bargaining representative for an appropriate bargaining unit. The most common petition type and the vehicle for new organizing campaigns.
- RM (Representation, Employer Petition): filed by an employer with a good-faith, reasonable basis to doubt the majority status of a currently recognized union. Rarely used; employers typically file RM petitions when presented with competing union claims or when a substantial portion of the workforce signs authorization cards for a rival union.
- RD (Decertification): filed by employees seeking to remove an existing union as their bargaining representative. Requires a 30% showing of interest. The union may file a “blocking charge” alleging employer misconduct that tainted employee sentiment, which under the 2023 rules can suspend the election while the ULP charge is investigated.
- UC (Unit Clarification): a petition to clarify the scope of an existing certified bargaining unit, typically when new job classifications have been created or when the employer disputes whether certain employees fall within the certified unit. Resolved by Regional Director decision rather than election.
- AC (Amendment of Certification): a petition to amend an existing certification, most commonly when a union has changed its name or merged with another union. Also decided without an election.
The RC election process begins when a petitioning union files an RC petition with the appropriate regional office, accompanied by a “showing of interest”—authorization cards or petitions signed by at least 30% of the employees in the proposed bargaining unit. The 30% threshold is a processing requirement, not a merits standard; experienced organizers typically seek 65–70% card support before filing, both to ensure a cushion against attrition during the campaign period and because employers who see a card majority sometimes choose voluntary recognition rather than contesting the election.
After the petition is filed, the Regional Director investigates the proposed unit—assessing whether it constitutes an “appropriate” unit under the community of interest standard, which examines the similarity of wages and working conditions, the extent of common supervision, the history of collective bargaining at the employer, and employee desires. The parties may reach a “Stipulated Election Agreement” on unit scope and election logistics, or the Regional Director may order a pre-election hearing to resolve contested unit questions. After the unit is established, the Regional Director issues a Notice of Election and an election date is set.
Elections are conducted by secret ballot, typically at the employer's premises or by mail ballot if in-person voting is impractical. Eligible voters are the employees in the bargaining unit as of a designated eligibility date. After the election, votes are tallied in the presence of observers from both the union and the employer. A union that receives a majority of valid votes cast—not a majority of eligible voters—is certified as the exclusive bargaining representative, and the employer is legally obligated to bargain in good faith over wages, hours, and terms and conditions of employment. If the union loses, an “election bar” prevents another petition in the same unit for 12 months.
The 2014 “Ambush Election” rule and 2023 revisions
The timeline from petition filing to election has been the subject of intense regulatory conflict across administrations. Under rules prevailing through 2014, the pre-election period typically lasted 38 to 42 days— a window during which employers routinely conducted mandatory employee attendance meetings, distributed anti-union communications, and retained management-side labor consultants. Critics argued this period systematically advantaged employers by giving them a captive communications channel with employees that unions lacked access to.
In April 2014, the Obama-era NLRB issued a final rule that significantly accelerated the process. The “Ambush Election” rule— so labeled by employer-side advocates who opposed it—required parties to submit election-related positions before the pre-election hearing, reducing duplicative litigation. It also required employers to provide detailed employee contact lists (home addresses, phone numbers, and personal email addresses if known) within two business days of a Direction of Election or Stipulated Election Agreement. The median pre-election period fell from approximately 38 days to approximately 23 days after the 2014 rule took effect in April 2015.
The first Trump administration rescinded the 2014 rule in 2019, reinstating longer pre-election hearing periods and modifying the blocking charge procedure so that pending ULP charges no longer automatically delayed elections. Instead, elections would proceed and ballots be impounded pending charge resolution—a change that employers favored because it prevented unions from using meritless charges to indefinitely delay elections.
In August 2023, the Biden-era Board issued a new final rule restoring and in some respects strengthening the 2014 framework. The 2023 rule reinstated the blocking charge procedure (allowing ULP charges to delay elections while the charge is investigated and potentially resolved), restored the “voluntary recognition bar” (preventing a decertification petition for a reasonable period following an employer's voluntary recognition of a union on the basis of card majority), modified construction industry election rules applicable to Section 8(f) pre-hire agreements, and clarified standards for when a union filing ULP charges can bar a decertification election.
Election volume and win rate trends
The volume of NLRB election activity is a barometer of the broader labor organizing environment and has tracked the rise and fall of union density across several decades. At the peak of organizing activity in the mid-1970s, the NLRB processed more than 8,000 election petitions per year. By the mid-2000s, annual petition volume had fallen to approximately 2,000–2,500 cases, reflecting the structural decline of manufacturing and the increasing cost and difficulty of running NLRB election campaigns. Volume remained in that range through the 2010s.
Beginning in fiscal year 2022, a significant uptick materialized. Petition volume increased approximately 57% compared to the prior year—the largest single-year increase in decades—driven substantially by high-profile campaigns at Amazon and Starbucks that drew widespread media attention and appear to have encouraged organizing elsewhere. The NLRB received approximately 2,510 RC election petitions in FY2022. Union win rates improved in parallel: unions won approximately 65–70% of elections held in FY2022 and FY2023, compared to roughly 55–65% through much of the 2010s. The combination of higher filing volume and higher win rates represented a material shift in the effectiveness of NLRB election campaigns as an organizing vehicle.
The Amazon Labor Union's April 1–2, 2022 election at the LDJ5 fulfillment center in Staten Island, New York is the most prominent single election result in recent NLRB history. The ALU—an independent union not affiliated with any national labor federation, organized primarily by warehouse workers with assistance from the Retail, Wholesale and Department Store Union—petitioned for an election covering approximately 8,300 employees. After a vigorous employer campaign that included mandatory attendance meetings and extensive use of consultants, the election produced a vote of 2,654 in favor of union representation to 2,131 against, a margin of 523 votes. This was the first successful union election at an Amazon facility in the United States. A subsequent election at a second Staten Island facility (LDJ4) was won by Amazon. Subsequent organizing campaigns at Amazon facilities in other states produced mixed results, with several elections lost and multiple ULP charges filed alleging employer misconduct during campaigns.
The Starbucks Workers United campaign, launched in late 2021 at a Buffalo, New York location, produced the largest sustained single-employer organizing wave in the NLRB system in decades. From late 2021 through 2023, more than 400 Starbucks locations filed election petitions, and unions won elections at a majority of stores where votes were held. The NLRB General Counsel's office issued numerous consolidated complaints alleging widespread and systematic ULP conduct by Starbucks across the campaign, including terminating union organizers, closing unionized stores, and withholding wage increases and benefits from unionizing stores that were granted to non-unionizing locations— a practice the Board charged violated the Section 8(a)(3) prohibition on discrimination based on union activity.
Unfair labor practice charges: C cases
Unfair labor practice charges—“C cases” in NLRB terminology—are the second major category of NLRB caseload. Any person, including an employee, union, or employer, may file a ULP charge with the appropriate regional office at no cost, using NLRB Form 501 (charges against employers) or NLRB Form 508 (charges against unions). The NLRB receives approximately 15,000 to 20,000 ULP charges per year. The six-month statute of limitations runs from the date the charging party knew or should have known of the alleged violation.
Case type designations reflect which party is charged:
- CA cases: charges against employers. The most common ULP charge type. Employer violations under Section 8(a) include: 8(a)(1) interference with, restraint, or coercion of employees in the exercise of their Section 7 rights (the broadest category, covering threatening statements, interrogations about union activities, unlawful surveillance of organizing meetings, and promulgating overbroad rules restricting protected concerted activity); 8(a)(2) domination or unlawful financial support of a labor organization; 8(a)(3) discrimination in hire, tenure, or conditions of employment to discourage union membership; 8(a)(4) discrimination against employees for filing NLRB charges or testifying in proceedings; and 8(a)(5) refusal to bargain in good faith with the exclusive representative of the employer's employees.
- CB cases: charges against unions for violations under Section 8(b), including: 8(b)(1)(A) restraint or coercion of employees in the exercise of Section 7 rights (including the right not to join a union); 8(b)(2) causing an employer to discriminate against employees; 8(b)(3) refusal to bargain in good faith; 8(b)(4) secondary boycotts and sympathy strikes against neutral employers; 8(b)(5) excessive initiation fees; 8(b)(6) featherbedding (payment for services not performed); and 8(b)(7) recognitional picketing where a competing union is already certified or within 12 months of a valid election.
- CC cases: charges related to secondary boycotts, filed against unions alleged to have engaged in secondary strike or boycott pressure on neutral employers to coerce the primary employer.
- CD cases: charges related to jurisdictional disputes between two unions over which union's members should perform certain work at a jobsite.
After a charge is filed, a regional office investigator takes affidavits from witnesses, obtains relevant documents, and assesses the evidence. If the investigation supports the charge, the Regional Director issues a formal complaint. If not, the Regional Director issues a dismissal letter, which the charging party may appeal to the NLRB Office of Appeals in Washington. Approximately 35% of charges that are not withdrawn are found to have merit; the remainder are dismissed. A significant portion of meritorious charges are settled before complaint issuance through informal adjustment with the employer.
If a complaint issues, the matter proceeds to a hearing before an Administrative Law Judge. The ALJ receives witness testimony, admits documentary evidence, and issues a written decision with factual findings and legal conclusions. Either party may file exceptions with the full Board. A final Board order finding a violation typically includes a cease-and-desist directive, a notice-posting requirement (requiring the employer to post a summary of employees' NLRA rights in a conspicuous workplace location), reinstatement of unlawfully discharged employees, and back pay with interest calculated under the NLRB's compounding formula. Board orders are not self-enforcing; the NLRB must petition the US Court of Appeals for enforcement, or the respondent may seek review and the court will then enforce or modify the order.
The most consequential ULP remedy is the Gissel bargaining order, established by the Supreme Court's 1969 decision in NLRB v. Gissel Packing Co., 395 US 575 (1969). Under Gissel, if an employer has committed ULP violations so severe and pervasive that they have “irremedially tainted” the election atmosphere—rendering a fair election impossible—the Board may order the employer to recognize and bargain with the union on the basis of pre-violation authorization cards showing a majority, without holding an election. Gissel orders are infrequently granted and often contested on appeal; courts apply heightened scrutiny to the Board's findings that violations were sufficiently severe to justify bypassing the election process entirely.
Key doctrinal developments
NLRB doctrine evolves through Board decisions and can be reversed by newly constituted Boards as presidential appointments change membership. This makes NLRB precedent unusually volatile compared to most federal administrative law—employers and unions operating under one Board's regime may find the rules substantially changed within a single presidential term.
The Joy Silk doctrine (1949–1969) required employers to recognize a union and bargain if the union presented authorization cards from a majority of employees, unless the employer had a genuine good-faith doubt about the authenticity of the cards. In practice, Joy Silk created a card-check system in which majority card support was often sufficient for recognition without a secret ballot. The Nixon-era Board effectively abandoned Joy Silk in Gissel Packing (1969), limiting card-based recognition to cases where employer misconduct made a fair election atmosphere impossible.
The successorship doctrine governs whether an employer acquiring a business through an asset purchase inherits the seller's collective bargaining obligations. Fall River Dyeing & Finishing Corp. v. NLRB, 482 US 27 (1987), held that a successor employer must bargain with the incumbent union if there is substantial operational continuity and the successor employs a majority of employees from the predecessor workforce. Successorship is frequently invoked in corporate transactions involving unionized facilities and requires careful due diligence by acquiring parties.
McLaren Macomb, 372 NLRB No. 58 (2023): the Biden-era Board held that severance agreements containing broad confidentiality and non-disparagement clauses are unlawful because they tend to interfere with employees' Section 7 rights to discuss working conditions and engage in concerted activity. Prior Board decisions had permitted such clauses as lawful conditions of voluntary separation. McLaren Macomb dramatically changed severance agreement practice across the US private sector; employers were required to remove or substantially narrow confidentiality and non-disparagement provisions to comply with the ruling.
The independent contractor question has oscillated across administrations. SuperShuttle DFW, 367 NLRB No. 75 (2019), the Trump-era Board restored an entrepreneurial opportunity emphasis in the common-law test that more readily found independent contractor status. Atlanta Opera, Inc., 372 NLRB No. 136 (2023), the Biden-era Board restored a more employee-favoring application of the common-law factors. The question directly determines NLRA coverage for platform economy workers at companies like Uber, Lyft, DoorDash, and Amazon Flex, and is expected to continue shifting with future Board compositions.
NLRB case management system and public data access
The NLRB publishes substantial case data through several channels that support empirical research on labor organizing and employer and union conduct:
- Case search at nlrb.gov/cases-decisions: any case can be searched by case number, party name, region, or case type. Case numbers follow a standardized format: a two-digit region number, a two-letter case type code, and a six-digit sequential docket number, separated by hyphens (for example, 02-RC-123456 for a Region 2 RC case; 13-CA-456789 for a Region 13 CA charge against an employer). The case search returns case status, the parties' names, the date filed, and links to associated documents.
- NLRB Decisions database: published Board decisions are searchable at nlrb.gov/cases-decisions/nlrb-decisions. Decisions are available as PDFs and include the ALJ decision, party exceptions, and the Board's order and rationale. The NLRB publishes weekly “Summary of NLRB Decisions” digests covering significant new decisions.
- Election results data: the NLRB publishes annual election results CSV files on its Reports and Data page at nlrb.gov/reports/graphs-data/recent-election-results. Each file contains one row per election held in the fiscal year, with columns for case number, dates (filing, election, close), regional office, union name, employer name, NAICS industry code, bargaining unit size, vote counts, and outcome. This structured dataset is the primary resource for empirical research on election trends.
- NLRB Data Dashboard: an interactive dashboard at nlrb.gov/reports/graphs-data displays election petitions filed by month, region, and industry alongside ULP charge filing statistics and case processing metrics. Updated periodically.
- Annual Report: the NLRB Annual Report provides comprehensive statistics on case filings, dispositions, election outcomes, complaint issuance rates, back pay awarded, and regional office performance. Annual Reports are available back to the 1940s and are the primary longitudinal source for long-run trend analysis.
- FOIA requests: the NLRB's FOIA office processes requests for case-level data not available publicly, including investigative files (with appropriate redactions), internal correspondence, and detailed statistical breakdowns by region and case type. The NLRB publishes a quarterly FOIA log identifying the volume and subject matter of processed requests.
- Press releases: significant enforcement actions, complaint issuances, 10(j) injunction applications, and Board decisions are announced at nlrb.gov/news-outreach/news-releases. The archive is searchable by keyword and date and provides a narrative record of enforcement milestones including the Amazon and Starbucks complaint proceedings.
The election results CSV is the most analytically useful structured dataset the NLRB publishes. Updated annually, it covers roughly 2,000–3,000 elections per fiscal year and contains enough variables to compute win rates by union, industry, region, bargaining unit size, and fiscal year, as well as petition-to-election lead times that directly measure the impact of each successive rule change on election processing speed.
Union density data: BLS context
NLRB election data captures organizing activity but not the broader stock of organized workers. The definitive source for union membership and density is the Bureau of Labor Statistics Union Membership news release, published each January using data from the Current Population Survey Outgoing Rotation Group supplement. The CPS supplement asks employed wage and salary workers whether they are union members and whether their jobs are covered by a union contract—a distinction that captures non-member employees in union-represented units who pay no dues but receive the benefit of collectively bargained agreements.
Key BLS statistics for 2023: total union membership among wage and salary workers was 14.4 million, representing 10.0% of the employed workforce. Private-sector union membership was 6.3 million workers, a density of 6.0%. Public-sector membership was 7.1 million workers, a density of 33.1%. Peak union density in the United States was approximately 34.8% of the total workforce in 1954; the post-war peak for the private sector specifically reached approximately 39% in the late 1950s. The BLS series beginning in 1983 shows an overall density of 20.1%; the decline from 1983 to 2023 represents a loss of approximately 10 percentage points despite nominal membership remaining relatively stable, because total employment grew substantially over the same period.
Industry variation in union density is large and consequential for understanding where NLRB elections occur. Protective services (fire, police) carry density of approximately 34%; education workers (including private school and university employees) approximately 33%; utilities 22%; transportation and warehousing 16%. At the other extreme, financial services and insurance have density of approximately 1.6%; accommodation and food service (the Starbucks sector) approximately 1.4%; professional and technical services below 2%. The gap between these density levels explains why organizing campaigns in food service, logistics, and technology generate disproportionate public attention even when individual vote counts are small—union wins in historically non-union sectors represent qualitative changes in the organizing landscape regardless of absolute unit size.
Geographic variation is substantial. States with the highest union density are Hawaii (24.2%), New York (22.3%), Alaska (19.0%), and Washington (18.6%). States with the lowest are South Carolina (1.7%), North Carolina (2.6%), Georgia (3.1%), and Utah (3.7%). Approximately 28 states have enacted right-to-work laws under Section 14(b) of the NLRA, which prohibit mandatory union membership or agency fee payments as a condition of employment in a unionized workplace. RTW states have significantly lower union density than non-RTW states, both through the direct effect on union revenue and organizing capacity and because RTW status correlates with other state policy choices that affect union strength such as at-will employment protections and limited public-sector bargaining rights.
Regional office variation and right-to-work geography
The NLRB's 26 regional offices process cases independently, and significant variation in case processing times has been documented in the Board's Annual Reports and in academic literature. The busiest regional offices by case volume are Region 13 (Chicago), Region 2 (New York City), and Region 20 (San Francisco), which collectively process a disproportionate share of national election petition volume and ULP charge filings. These offices also handle many of the highest- profile organizing campaigns in retail, logistics, and technology that have driven the recent uptick in filing activity.
Processing time variation across regions—specifically the number of days from petition filing to election date—has been a persistent management challenge. Even after the 2014 and 2023 rule changes narrowed average pre-election periods, regional variation persists: some offices conduct elections in under 20 days from petition filing; others average over 50 days, even in uncontested cases. This variation translates directly into how much campaign time the employer has before employees vote.
RTW state status is imperfectly correlated with regional office boundaries—a single regional office often covers both RTW and non-RTW states—but RTW states have systematically lower petition-filing rates relative to their covered private-sector workforce. Region 10 (Atlanta), covering Georgia, Alabama, Tennessee, and South Carolina (all RTW states), has among the lowest rates of election petitions per covered worker in the country. Region 13 (Chicago), covering Illinois (non-RTW) and Indiana (RTW), presents a useful natural experiment: the two state populations generate substantially different organizing activity rates despite being administered by the same regional office staff under the same federal legal standards.
Section 10(j) injunctive relief
Section 10(j) of the NLRA authorizes the NLRB General Counsel to petition a US district court for temporary injunctive relief while a ULP case is pending before the Board. The purpose is prophylactic: if an employer is discharging union organizers at a rate that will destroy the organizing committee before the Board can issue a final order years in the future, a 10(j) injunction can require immediate interim reinstatement to preserve the status quo ante.
10(j) petitions require GC approval and are filed in the district court of the circuit where the employer is located. The district court applies a preliminary injunction standard, but the governing test for likelihood of success in 10(j) proceedings is the more lenient “reasonable cause to believe” standard—whether the evidence gives reasonable cause to believe a violation occurred—rather than the ultimately merits-determinative standard applied before the Board. The balance of equities and public interest prongs track heavily toward the NLRB in cases of alleged discriminatory discharge of organizers, given the statutory policy favoring protected concerted activity.
The Biden-era General Counsel Jennifer Abruzzo dramatically increased 10(j) petition filings beginning in 2021. The tool was used aggressively in the Amazon and Starbucks campaigns to obtain interim reinstatement orders for terminated organizers, with the GC arguing that each discharge chilled organizing activity among the remaining workforce in ways that could not be adequately remedied by back pay alone years later. Between 2021 and 2024, NLRB 10(j) filing volume reached levels not seen since the early 2000s. The enhanced use of 10(j) relief was cited by labor advocates as a meaningful deterrent to employer anti-union conduct and by employer-side practitioners as an overreach of the preliminary injunction standard in cases where the underlying merits were genuinely contested.
Python example: analyzing NLRB election results data
The NLRB's publicly available election results CSV files provide a direct-download structured dataset suitable for quantitative research. The following script downloads the most recent annual election results file and produces five analytical outputs: win rates by fiscal year with average and median bargaining unit size; win rates by NAICS industry supersector; top unions by petition volume and win rate; average petition-to-election lead time by regional office (directly measuring the impact of election rule changes); and a monthly filing trend visualization covering the Amazon and Starbucks petition surges. No API key is required; the data is freely accessible on the NLRB Reports and Data page. The filename changes each fiscal year—update the URL suffix to the current FY for the most recent data.
import csv
import io
import time
from collections import Counter, defaultdict
from datetime import datetime, date
from urllib.request import urlopen, Request
# ---------------------------------------------------------------------------
# NLRB Election Results Data Analysis
#
# The NLRB publishes election results as downloadable CSV files at:
# https://www.nlrb.gov/reports/graphs-data/recent-election-results
#
# The primary dataset is "Election Report" (elections conducted in a fiscal
# year). Additional datasets include "RC Petitions" and "ULP Charges."
# Files require no API key and are freely downloadable.
#
# Column reference (election results CSV, FY2019-FY2024):
# case_number - NLRB case number (XX-RC-XXXXXX format)
# date_filed - Date petition was filed
# date_closed - Date case was closed
# election_date - Date of election (if held)
# region - NLRB regional office number (2-99)
# unit_size - Number of eligible voters in the bargaining unit
# votes_for - Votes cast for union representation
# votes_against - Votes cast against union representation
# union_name - Name of petitioning union
# employer_name - Employer name
# naics_code - 6-digit NAICS industry code
# naics_description - NAICS industry description
# election_type - RC (union petition), RM (employer petition), RD (decert)
# outcome - WON, LOST, WITHDRAWN, DISMISSED, etc.
# ---------------------------------------------------------------------------
NLRB_ELECTION_URL = (
"https://www.nlrb.gov/sites/default/files/attachments/pages/"
"node-174/nlrb-election-report-fy2024.csv"
)
# Regional office names keyed by region number (string)
REGION_NAMES = {
"1": "Boston", "2": "New York City",
"3": "Buffalo", "4": "Philadelphia",
"5": "Baltimore", "6": "Pittsburgh",
"7": "Detroit", "8": "Cleveland",
"9": "Cincinnati", "10": "Atlanta",
"11": "Winston-Salem", "12": "Tampa",
"13": "Chicago", "14": "St. Louis",
"15": "New Orleans", "16": "Fort Worth",
"17": "Kansas City", "18": "Minneapolis",
"19": "Seattle", "20": "San Francisco",
"21": "Los Angeles", "22": "Newark",
"24": "Hato Rey (PR)", "25": "Indianapolis",
"26": "Memphis", "28": "Phoenix",
"29": "Brooklyn", "30": "Milwaukee",
"31": "Los Angeles II", "32": "Oakland",
"34": "Hartford",
}
# NAICS 2-digit supersector groupings for aggregation
NAICS_SUPERSECTORS = {
"11": "Agriculture/Forestry",
"21": "Mining/Oil & Gas",
"22": "Utilities",
"23": "Construction",
"31": "Manufacturing",
"32": "Manufacturing",
"33": "Manufacturing",
"42": "Wholesale Trade",
"44": "Retail Trade",
"45": "Retail Trade",
"48": "Transportation/Warehousing",
"49": "Transportation/Warehousing",
"51": "Information",
"52": "Finance/Insurance",
"53": "Real Estate",
"54": "Professional Services",
"55": "Management",
"56": "Administrative Services",
"61": "Education",
"62": "Healthcare/Social Assist",
"71": "Arts/Entertainment",
"72": "Accommodation/Food Service",
"81": "Other Services",
"92": "Public Administration",
}
def fetch_csv(url: str, timeout: int = 60) -> list[dict]:
"""Download an NLRB CSV file and return rows as a list of dicts."""
req = Request(url, headers={"User-Agent": "labor-research/1.0"})
with urlopen(req, timeout=timeout) as resp:
raw = resp.read().decode("utf-8-sig") # strip BOM if present
reader = csv.DictReader(io.StringIO(raw))
return list(reader)
def parse_date(s: str) -> date | None:
"""Parse M/D/YYYY or YYYY-MM-DD date strings; return None on failure."""
s = (s or "").strip()
for fmt in ("%m/%d/%Y", "%Y-%m-%d", "%m/%d/%y"):
try:
return datetime.strptime(s, fmt).date()
except ValueError:
pass
return None
def naics_supersector(naics: str) -> str:
"""Map a 6-digit NAICS code to a broad supersector label."""
prefix = (naics or "")[:2]
return NAICS_SUPERSECTORS.get(prefix, "Unknown")
def days_between(d1: date | None, d2: date | None) -> int | None:
"""Return days between two dates, or None if either is missing."""
if d1 and d2:
return abs((d2 - d1).days)
return None
def analyze_elections(rows: list[dict]) -> None:
"""
Compute and print five tables:
1. Win rate and average unit size by year
2. Win rate by NAICS supersector
3. Top 10 unions by petition volume and win rate
4. Average petition-to-election days by region
5. Monthly petition filing trends (all years combined)
"""
# --- Normalize rows ---
elections = []
for row in rows:
# Normalize column names: lowercase, strip spaces
r = {k.strip().lower().replace(" ", "_"): (v or "").strip()
for k, v in row.items()}
election_type = r.get("election_type", "").upper()
if election_type not in ("RC", "RM", "RD"):
continue # skip non-election petition types
filed_date = parse_date(r.get("date_filed", ""))
elec_date = parse_date(r.get("election_date", ""))
outcome = r.get("outcome", "").upper()
union = r.get("union_name", "Unknown")
naics_raw = r.get("naics_code", "")
region = r.get("region", "").strip()
unit_raw = r.get("unit_size", "0").replace(",", "")
try:
unit_size = int(unit_raw)
except ValueError:
unit_size = 0
try:
votes_for = int(r.get("votes_for", "0").replace(",", ""))
votes_against = int(r.get("votes_against", "0").replace(",", ""))
except ValueError:
votes_for = votes_against = 0
won = outcome == "WON" or votes_for > votes_against
elections.append({
"year": filed_date.year if filed_date else None,
"month": filed_date.month if filed_date else None,
"filed_date": filed_date,
"elec_date": elec_date,
"outcome": outcome,
"won": won,
"union": union,
"naics": naics_raw,
"supersector": naics_supersector(naics_raw),
"region": region,
"unit_size": unit_size,
"votes_for": votes_for,
"votes_against": votes_against,
"lead_days": days_between(filed_date, elec_date),
})
decided = [e for e in elections if e["outcome"] in ("WON", "LOST")]
# --- Table 1: Win rate and unit size by year ---
by_year: dict[int, list] = defaultdict(list)
for e in decided:
if e["year"]:
by_year[e["year"]].append(e)
print("\nNLRB Election Win Rates by Fiscal Year (RC/RM/RD cases only)")
print("=" * 72)
print(f"{'Year':<6} {'Petitions':>10} {'Won':>6} {'Win %':>7} "
f"{'Avg Unit':>9} {'Median Unit':>12}")
print("-" * 72)
for year in sorted(by_year.keys()):
es = by_year[year]
won = sum(1 for e in es if e["won"])
sizes = sorted(e["unit_size"] for e in es if e["unit_size"] > 0)
avg_size = sum(sizes) / len(sizes) if sizes else 0
median_size = sizes[len(sizes) // 2] if sizes else 0
pct = 100 * won / len(es) if es else 0
print(f"{year:<6} {len(es):>10} {won:>6} {pct:>6.1f}% "
f"{avg_size:>9.0f} {median_size:>12}")
# --- Table 2: Win rate by NAICS supersector ---
by_sector: dict[str, list] = defaultdict(list)
for e in decided:
by_sector[e["supersector"]].append(e)
print("\nElection Win Rates by Industry Supersector")
print("=" * 60)
print(f"{'Sector':<28} {'Elections':>10} {'Won':>6} {'Win %':>7}")
print("-" * 60)
ranked = sorted(
by_sector.items(),
key=lambda x: -100 * sum(1 for e in x[1] if e["won"]) / len(x[1])
if x[1] else 0
)
for sector, es in ranked:
won = sum(1 for e in es if e["won"])
pct = 100 * won / len(es) if es else 0
print(f" {sector:<26} {len(es):>10} {won:>6} {pct:>6.1f}%")
# --- Table 3: Top 10 unions by petition volume ---
by_union: dict[str, list] = defaultdict(list)
for e in decided:
name = e["union"][:32] if e["union"] else "Unknown"
by_union[name].append(e)
print("\nTop 10 Unions by Election Volume")
print("=" * 60)
print(f"{'Union':<34} {'Elections':>10} {'Won':>6} {'Win %':>7}")
print("-" * 60)
top_unions = sorted(by_union.items(), key=lambda x: -len(x[1]))[:10]
for union, es in top_unions:
won = sum(1 for e in es if e["won"])
pct = 100 * won / len(es) if es else 0
print(f" {union:<32} {len(es):>10} {won:>6} {pct:>6.1f}%")
# --- Table 4: Average petition-to-election lead time by region ---
by_region: dict[str, list[int]] = defaultdict(list)
for e in elections:
if e["lead_days"] and e["lead_days"] > 0 and e["region"]:
by_region[e["region"]].append(e["lead_days"])
print("\nAverage Petition-to-Election Days by Regional Office")
print("=" * 55)
print(f"{'Rgn':<6} {'Office':<20} {'Elections':>10} {'Avg Days':>10}")
print("-" * 55)
ranked_regions = sorted(
by_region.items(),
key=lambda x: sum(x[1]) / len(x[1])
)
for region, days_list in ranked_regions:
avg = sum(days_list) / len(days_list)
name = REGION_NAMES.get(region, f"Region {region}")
print(f" {region:<4} {name:<20} {len(days_list):>10} {avg:>10.1f}")
# --- Table 5: Monthly filing trend (all years) ---
monthly: Counter = Counter()
for e in elections:
if e["year"] and e["month"]:
monthly[(e["year"], e["month"])] += 1
print("\nMonthly Election Petition Filings")
print("=" * 45)
print(f"{'Month':<12} {'Petitions':>10} Chart")
print("-" * 45)
for (year, month) in sorted(monthly.keys()):
count = monthly[(year, month)]
label = f"{year}-{month:02d}"
bar = "#" * min(count, 60)
print(f" {label:<10} {count:>10} {bar}")
def main() -> None:
print("Downloading NLRB election results data...")
try:
rows = fetch_csv(NLRB_ELECTION_URL)
except Exception as exc:
print(f"Download failed: {exc}")
print("Check https://www.nlrb.gov/reports/graphs-data/recent-election-results")
print("for the current filename; the FY suffix changes each year.")
return
print(f" Downloaded {len(rows):,} rows.")
analyze_elections(rows)
if __name__ == "__main__":
main()
The election results file encodes each organizing campaign's outcome in a single row: case number, petition date, election date, bargaining unit size, vote counts, union name, employer name, NAICS code, and regional office number. Cross-referencing by NAICS supersector reveals that industries with historically low union density—accommodation and food service, retail trade, transportation and warehousing—now account for a growing share of total election petitions, the Amazon and Starbucks effect quantified in structured data. Lead-time analysis by regional office identifies which offices process cases fastest, and year-over-year lead-time trends confirm the directional impact of the 2014 and 2023 rule changes on pre-election periods.
For multi-year trend analysis, the NLRB provides separate annual files for each fiscal year going back to at least FY2000 on its Reports and Data page. Concatenating these files enables long-run analysis of how petition volume, win rates, bargaining unit sizes, and industry composition have shifted since the peak organizing period of the 1970s. The most striking long-run finding is that median unit sizes have shrunk dramatically: the typical election unit in recent years covers approximately 20–30 employees, compared to units of 100 or more that were common in 1970s manufacturing campaigns. This reflects the structural shift from large integrated manufacturing facilities to smaller service-sector workplaces as the primary organizing target— a shift that affects organizing economics, campaign strategy, and the relationship between election wins and aggregate union membership growth.
For the DOJ enforcement context that parallels NLRB proceedings— including how the DOJ Antitrust Division investigates employer no-poach agreements and wage-fixing conspiracies that suppress worker compensation through the same Sherman Act criminal machinery used against price-fixing cartels—see DOJ Antitrust Division: The Federal Merger Review and Cartel Enforcement Database, covering HSR pre-merger notification, HHI concentration thresholds, the corporate leniency program, and public enforcement data access.
For the Federal Register rulemaking process through which the NLRB publishes proposed election rules, final rules, and policy statements for public comment—including how to track NLRB rulemaking dockets on Regulations.gov and read the agency's regulatory agenda under the Unified Agenda—see Federal Register: The Official Rulemaking Journal Behind 90,000 Pages of Annual US Regulatory Activity, covering the APA notice-and-comment sequence, OIRA review, and the Federal Register API.