Data collection last run: 2025-07-08
⚠️ This is not an official USAJobs project
Year | Jobs Opened | Jobs Closed | Coverage Notes |
---|---|---|---|
2013 | 5 | 0 | Very limited |
2014 | 24 | 19 | Very limited |
2015 | 140 | 131 | Very limited |
2016 | 3,879 | 1,633 | Very limited |
2017 | 237,145 | 226,248 | ✅ Complete year |
2018 | 328,111 | 315,729 | ✅ Complete year |
2019 | 349,256 | 336,608 | ✅ Complete year |
2020 | 327,545 | 315,161 | ✅ Complete year |
2021 | 369,151 | 352,375 | ✅ Complete year |
2022 | 441,604 | 419,295 | ✅ Complete year |
2023 | 454,652 | 434,527 | ✅ Complete year |
2024 | 367,744 | 352,296 | ✅ Complete year |
2025 | 96,430 | 95,337 | Current through July 08, 2025 |
Note: This table shows fields from historical jobs data. Current jobs API contains additional fields that are preserved in the original nested structure but not included in this rationalized view.
Field | Type | Examples | Completeness |
---|---|---|---|
HiringPaths |
JSON Array | [{"hiringPath": "Custom announcement"}], [{"hiringPath": "The public"}] (75896 unique combinations) | 100% |
JobCategories |
JSON Array | [{"series": "1320"}, {"series": "1310"}, {"series": "1301"}, {"series": "0801"}], [{"series": "0401"}, {"series": "1301"}, {"series": "0801"}, {"series": "0819"}, {"series": "0020"}], [{"series": "5767"}], [{"series": "1350"}, {"series": "0850"}, {"series": "0810"}, {"series": "0808"}, {"series": "0830"}] (3060 unique) | 100% |
PositionLocations |
JSON Array | [{"positionLocationCity": "Urbana", "positionLocationState": "Maryland", "positionLocationCountry": "United States"}, {"positionLocationCity": "Falls Church", "positionLocationState": "Virginia", "positionLocationCountry": "United States"}, {"positionLocationCity": "Woodlawn", "positionLocationState": "Maryland", "positionLocationCountry": "United States"}, {"positionLocationCity": "Baltimore", "positionLocationState": "Maryland", "positionLocationCountry": "United States"}, {"positionLocationCity": "Durham", "positionLocationState": "North Carolina", "positionLocationCountry": "United States"}, {"positionLocationCity": "Washington", "positionLocationState": "District of Columbia", "positionLocationCountry": "United States"}, {"positionLocationCity": "Alexandria", "positionLocationState": "Virginia", "positionLocationCountry": "United States"}, {"positionLocationCity": "Springfield", "positionLocationState": "Virginia", "positionLocationCountry": "United States"}, {"positionLocationCity": "Arlington", "positionLocationState": "Virginia", "positionLocationCountry": "United States"}], [{"positionLocationCity": "China Lake", "positionLocationState": "California", "positionLocationCountry": "United States"}] (26311 unique combinations) | 100% |
agencyLevel |
Integer | 1, 2 | 100% |
agencyLevelSort |
String | Department of Justice\Offices, Boards and Divisions, Department of Education\Office of the General Counsel, Department of the Air Force\Air Force Medical Command, Department of Labor\Office of Federal Contract Compliance Programs (542 unique) | 100% |
announcementClosingTypeCode |
String | 01, 03, 02 | 100% |
announcementClosingTypeDescription |
String | Closing Date, Applicant Cut-Off, Open Continuous | 100% |
announcementNumber |
String | MCFS249766104342, DECA-24-12348385-MP, MCGK247968088011, NV-Merit-25-12572459-JP (363801 unique) | 100% |
appointmentType |
String | Recent graduates, Temporary Promotion, Multiple, Intermittent (15 unique) | 100% |
disableApplyOnline |
String | N, Y | 100% |
drugTestRequired |
String | N | 100% |
hiringAgencyCode |
String | ARAE, VAPA, TN00, HE33 (528 unique) | 100% |
hiringAgencyName |
String | Office of the Assistant Secretary for Public and Intergovernmental Affairs, Cybersecurity and Infrastructure Security Agency, United States Army Futures Command, Office of Federal Contract Compliance Programs (502 unique) | 99% |
hiringDepartmentCode |
String | NM, FT, MI, FL (122 unique) | 100% |
hiringDepartmentName |
String | Department of Labor, Other Agencies and Independent Organizations, Department of Commerce, Department of State (26 unique) | 100% |
hiringSubelementName |
String | National Institute on Disability, Independent Living, and Rehabilitation Research (NIDILRR), TF VIPR Contracting Division, TF VIPR Execution Branch, Omaha District - Omaha Safety and Occupational Health Office, Orlando VA Healthcare System (59973 unique) | 62% |
inserted_at |
String | 2025-07-05T15:37:35.666806, 2025-07-05T14:04:05.156353, 2025-07-05T14:29:28.730118, 2025-07-05T15:31:46.130319 (367177 unique) | 100% |
maximumGrade |
String | 2, 35, G, 60 (127 unique) | 100% |
maximumSalary |
Number | $0, $105,612, $470,281 (range: $0-$470,281) (15671 unique) | 100% |
minimumGrade |
String | KH, B, 18, EI (125 unique) | 100% |
minimumSalary |
Number | $0, $72,553, $400,000 (range: $0-$400,000) (15409 unique) | 100% |
payScale |
String | IS, DX, KI, NY (191 unique) | 100% |
positionCloseDate |
String | 2025-06-21, 2025-11-03, 2025-11-24, 2024-07-24 (672 unique) | 100% |
positionExpireDate |
String | 2024-11-07, 2025-02-17, 2024-01-21, 2025-05-05 (550 unique) | 9% |
positionOpenDate |
String | 2024-01-12, 2024-01-13, 2024-08-28, 2024-07-10 (365 unique) | 100% |
positionOpeningStatus |
String | Applications under review, Job closed, Job canceled, Candidate selected (5 unique) | 100% |
positionTitle |
String | Physician Assistant (Surgical Service- Gynecology), Attorney (Senior CLC Attorney), Senior Anti-Money Laundering Examiner, CG-0570-14, Chief Resident Services (77986 unique) | 100% |
promotionPotential |
String | 72, 41, FPMC, NO (115 unique) | 100% |
relocationExpensesReimbursed |
String | N | 100% |
salaryType |
String | Per Year, Per Hour, Without Compensation, Per Day (9 unique) | 100% |
securityClearance |
String | Not Required, Secret, Other, L Access Authorization (8 unique) | 100% |
securityClearanceRequired |
String | N, Y | 100% |
serviceType |
String | Competitive, Excepted, Senior Executive | 100% |
supervisoryStatus |
String | N, Y | 100% |
teleworkEligible |
String | N | 100% |
totalOpenings |
String | 165, 38, 55, 100 (157 unique) | 90% |
travelRequirement |
String | Not required, Occasional travel, 25% or less, 75% or less (6 unique) | 100% |
usajobsControlNumber |
Integer | 593449300, 693894500, 702096500 (367177 unique) | 100% |
usajobs_control_number |
String | 593449300, 693894500, 702096500 (367177 unique) | 100% |
vendor |
String | USASTAFFING, Monster - Hiring Management, FAA - SWIFT, HQMC MCCS (PeopleSoft) (8 unique) | 100% |
whoMayApply |
String | Status Candidates (Merit Promotion and VEOA Eligibles) | 0% |
workSchedule |
String | Full-time, Intermittent, Part-time, Multiple Schedules (6 unique) | 100% |
This dataset combines data from two USAJobs APIs with field rationalization for consistent querying:
/api/historicjoa
): Past job announcements by date range /api/Search
): Currently active job postings Note: There is overlap between the APIs (2024-2025 jobs appear in both), but we collect from both APIs for completeness.
Historical Field Name | Historical API Source | Current API Source | Notes |
---|---|---|---|
usajobsControlNumber |
usajobsControlNumber |
Extracted from PositionURI |
Numeric job identifier |
announcementNumber |
announcementNumber |
PositionID |
Public announcement ID |
hiringAgencyName |
hiringAgencyName |
DepartmentName |
Agency name |
hiringAgencyCode |
hiringAgencyCode |
OrganizationCodes (first part) |
Agency code |
positionTitle |
positionTitle |
PositionTitle |
Job title |
minimumGrade |
minimumGrade |
JobGrade[0].Code |
Minimum grade level |
maximumGrade |
maximumGrade |
JobGrade[-1].Code |
Maximum grade level |
minimumSalary |
minimumSalary |
PositionRemuneration[0].MinimumRange |
Minimum salary |
maximumSalary |
maximumSalary |
PositionRemuneration[0].MaximumRange |
Maximum salary |
positionOpenDate |
positionOpenDate |
PositionStartDate |
Position open date |
positionCloseDate |
positionCloseDate |
PositionEndDate |
Position close date |
usajobsControlNumber
to identify records appearing in both APIs when neededHiringPaths
, JobCategories
, PositionLocations
)MatchedObjectDescriptor
, etc.)hiringAgencyName
, positionTitle
) while retaining access to original nested structuresThe examples.py script demonstrates both local file access and direct GitHub downloads. It runs complete analysis on 2.97M job postings and automatically cleans up downloaded files.
import pandas as pd # Load a single year df_2024 = pd.read_parquet('data/historical_jobs_2024.parquet') print(f"✓ Successfully loaded {len(df_2024):,} job postings from 2024")
import pandas as pd import requests # Download directly from GitHub url = 'https://github.com/abigailhaddad/usajobs_historical/raw/main/data/historical_jobs_2024.parquet' df = pd.read_parquet(url) print(f"✓ Downloaded {len(df):,} job postings")
# 1. TOP 15 HIRING AGENCIES (2024 DATA) top_agencies = df_2024['hiringAgencyName'].value_counts().head(15) for i, (agency, count) in enumerate(top_agencies.items(), 1): percentage = count / len(df_2024) * 100 print(f"{i:2d}. {agency}: {count:,} jobs ({percentage:.1f}%)")
# Salary statistics records_with_salary = df_2024[df_2024['maximumSalary'].notna()] print(f"Records with salary data: {len(records_with_salary):,} ({len(records_with_salary)/len(df_2024)*100:.1f}%)") # Salary ranges min_range = f"${records_with_salary['minimumSalary'].min():,.0f} - ${records_with_salary['minimumSalary'].max():,.0f}" max_range = f"${records_with_salary['maximumSalary'].min():,.0f} - ${records_with_salary['maximumSalary'].max():,.0f}" median_range = f"${records_with_salary['minimumSalary'].median():,.0f} - ${records_with_salary['maximumSalary'].median():,.0f}" print(f"Minimum salary range: {min_range}") print(f"Maximum salary range: {max_range}") print(f"Median salary range: {median_range}")
import duckdb # Create DuckDB connection and register multiple Parquet files conn = duckdb.connect('download/usajobs.duckdb') # Register Parquet files as external tables years = ['2022', '2023', '2024'] for year in years: file_path = f'data/historical_jobs_{year}.parquet' conn.execute(f"CREATE OR REPLACE VIEW jobs_{year} AS SELECT * FROM '{file_path}'") # Create unified view conn.execute(""" CREATE OR REPLACE VIEW all_jobs AS SELECT * FROM jobs_2024 UNION ALL SELECT * FROM jobs_2023 UNION ALL SELECT * FROM jobs_2022 """) # Query salary trends by year salary_trends = conn.execute(""" SELECT EXTRACT(year FROM positionOpenDate) as year, ROUND(AVG(minimumSalary)) as avg_min, ROUND(AVG(maximumSalary)) as avg_max, ROUND(percentile_cont(0.5) WITHIN GROUP (ORDER BY minimumSalary)) as median_min, ROUND(percentile_cont(0.5) WITHIN GROUP (ORDER BY maximumSalary)) as median_max, COUNT(*) as jobs FROM all_jobs WHERE minimumSalary IS NOT NULL GROUP BY EXTRACT(year FROM positionOpenDate) ORDER BY year DESC """).fetchdf() print(salary_trends)
# Monthly posting patterns monthly_posts = df_2024.groupby(df_2024['positionOpenDate'].dt.month).size() print("Monthly posting patterns:") month_names = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] for month, count in monthly_posts.items(): percentage = count / len(df_2024) * 100 print(f" {month_names[month-1]}: {count:,} jobs ({percentage:.1f}%)")
# Most common position titles common_titles = df_2024['positionTitle'].value_counts().head(10) print("Most common position titles:") for i, (title, count) in enumerate(common_titles.items(), 1): percentage = count / len(df_2024) * 100 print(f" {i:2d}. {title}: {count:,} ({percentage:.1f}%)")