# Seasonal Jobs & Worker Housing Scraper (`alkausari_mujahid/dol-seasonal-jobs-scraper`) Actor

Scrape H-2A and H-2B seasonal job orders from the US Department of Labor, including housing details buried in PDF attachments. Get employer, job title, worker counts, dates, worksite addresses, housing units and occupancy— Export to CSV, schedule runs, pull via API, or connect over MCP for AI agents

- **URL**: https://apify.com/alkausari\_mujahid/dol-seasonal-jobs-scraper.md
- **Developed by:** [Alkausari M](https://apify.com/alkausari_mujahid) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

Collects **U.S. seasonal job postings — including the worker housing details that normal job listings never show** — from the official U.S. Department of Labor [Seasonal Jobs portal](https://seasonaljobs.dol.gov/). For every posting it opens the official government **job-order document** and extracts what's buried inside: worksite address, housing addresses, number of housing units, and how many workers they hold.

**Who it's for**

- **Recruiters and staffing agencies** — track which employers are hiring seasonal workers, where and when
- **Housing, transport and service providers** — know exactly where seasonal workers will live and work
- **Suppliers** — find farms and businesses about to receive seasonal labor in your area
- **Researchers, journalists and advocacy groups** — analyze seasonal labor demand and worker housing across DOL's official H-2A and H-2B job registry

### Key Features

- Reads the **official job-order documents**, not just the public search listing
- Captures **every housing site** on a job order, each with its own address and capacity
- Filter by state, job type (agricultural / non-agricultural), and start date
- One bad document never stops a run: downloads are retried, unreadable files are logged and skipped
- Structured output (JSON, CSV, Excel, XML) ready for spreadsheets and CRMs

### Ready-made tasks

Don't want to work out the filters? These are pre-configured setups — open one, hit **Start**, and you get results. Each is a normal task, so you can change the state, date range or limit and save it as your own.

| Task | What it does | Best for |
|---|---|---|
| [New farm jobs posted this week in Florida](TASK_URL_1) | The last 7 days of H-2A postings in Florida, newest first | Recruiters watching one state for fresh postings |
| [Upcoming worker housing sites in Texas](TASK_URL_2) | Texas H-2A postings starting from today, up to 100 | Housing, transport and service providers — switch the Output tab to **Housing sites** |
| [Non-agricultural (H-2B) postings nationwide](TASK_URL_3) | Every state, H-2B only, last 14 days | Hospitality, landscaping and seafood staffing |
| [Daily new-posting monitor](TASK_URL_4) | Yesterday's new postings — built to run on a schedule | Continuous tracking; wire it to Google Sheets or Slack |
| [Nationwide seasonal labor snapshot](TASK_URL_5) | All states, H-2A and H-2B, last 30 days, up to 500 postings | Researchers and journalists — allow around 5 hours for a full run |

> Tasks remember their settings, so any of them can be put on a **Schedule** — see [Integrations & scheduling](#integrations--scheduling).

### How to Run

> ▶️ **In a hurry?** Start from a [ready-made task](#ready-made-tasks) instead — the filters are already set.

1. Click **Run**, then open the **Input** tab
2. Pick a **Worksite state** and **Job type** (defaults: the 10 most recent agricultural jobs in Florida)
3. **Set Max job posts to `5` on your first run** — enough to see the output shape and measure the cost before committing to a big run
4. **Set the proxy country to United States.** Any proxy configuration works, but the DOL site is unreliable for traffic that doesn't come from a U.S. connection — the default US residential setting is the safe choice
5. Click **Start**. Each posting is reported in the log as it's processed
6. View results in the **Output** tab, or download from **Storage → Dataset**

Each posting means downloading and reading one PDF, so expect **30–50 seconds per posting — roughly 100 per hour**. Postings are processed one at a time on purpose: it keeps the load on a government server modest and makes a single unreadable document harmless.

### Input — Pick a state, a job type, and how many postings to pull

Set these in the **Input** tab. The defaults below fetch the 10 most recent agricultural postings in Florida — change `location` and `jobtype` to match what you're after, and keep `top` low until the filters are right. If you're calling the Actor via API or the CLI, paste this JSON as your input.

```json
{
    "location": "Florida",
    "jobtype": "H-2A",
    "offset": -7,
    "top": 10,
    "skip": 0,
    "order": "accepted_date desc"
}
```

| Field | What it does |
| --- | --- |
| `location` | Where the work takes place — all 50 states, DC, and U.S. territories. Leave empty to search everywhere. |
| `jobtype` | **Agricultural** (H-2A: farm work, harvesting, nursery, livestock), **Non-agricultural** (H-2B: landscaping, hospitality, seafood processing), or **All**. |
| `offset` | How far back to look in days, by the job's start date. `0` = starting today or later; `-7` = also include jobs that started up to a week ago. |
| `top` | How many postings to collect, max `1000`. The main lever on run time and cost. |
| `skip` | Skips the first N results. Use with `top` to page through a larger set: `top: 50, skip: 0`, then `top: 50, skip: 50`. |
| `order` | Most recently posted first (default), oldest begin date first, or best match. |

<details>
<summary><strong>Collecting more than 1000 postings, or running faster</strong></summary>

One run caps at `1000` postings, which takes about 10 hours at the rate above. Two ways to go bigger:

**Page through with `skip`.** Run `top: 500, skip: 0`, then `top: 500, skip: 500`. Keep `order` and `offset` identical across runs so the result set doesn't shift underneath you — and don't overlap your `skip` windows, or postings appear twice in your merged results.

**Run batches in parallel with Tasks.** Click **Create task**, save one task per batch with its own `skip`, then start them together. They run as independent concurrent runs, so five tasks finish in roughly the time one takes — subject to your plan's max concurrent runs. Each writes its own dataset; merge them on download or push them into one named dataset via the API.

**Hit the run timeout?** Open the run and click **Resurrect** with a longer timeout. It picks up where it stopped — already-processed postings aren't reprocessed or duplicated.

</details>

### Output

One record per job posting, with all housing nested inside it. Which fields you get depends on **Include PDF details** (see [Pricing](#pricing)): off gives the job-page fields only; on adds `Total Workers`, `H-2A Workers`, the `Employment *` address fields, `Housing`, and `Additional Housing` from the official PDF.

Employers often house workers at more than one address, but **one job order is always exactly one record** — extra sites live in the `Additional Housing` array. The Output tab has two views: **Overview** (one row per posting) and **Housing sites** (one row per housing location, each carrying its job's details). Your CSV or Excel export follows whichever view you pick.

A real run with **Include PDF details** turned on — job-page fields and PDF fields together:

```json
{
    "Case Number": "H-300-26210-131199",
    "Job Post URL": "https://seasonaljobs.dol.gov/jobs/H-300-26210-131199",
    "Job Title": "Farmworker / Harvester",
    "Status": "ACTIVE",
    "Employer": "Eberry Harvest Company LLC",
    "Employer Email": "joineberryharvest@gmail.com",
    "Employer Phone": "+18636754289",
    "Employment Type": "TEMPORARY",
    "First Date": "9/26/2026",
    "Last Date": "11/29/2026",
    "Job Duties": "The employer is seeking reliable, hardworking individuals to assist with the tomato and satsuma mandarin citrus harvest season. Duties include harvesting and packing...",
    "Worksite Address": "218 N Graves St",
    "Worksite City": "Quincy",
    "Worksite State": "FLORIDA",
    "Worksite Postal Code": "32351",
    "Pay Rate Min": 14,
    "Pay Rate Max": 0,
    "Pay Unit": "HOUR",
    "Pay Currency": "USD",
    "Telephone Number to Apply": "+18636754289",
    "Email address to Apply": "joineberryharvest@gmail.com",
    "Full Time": "Yes",
    "Number of Workers Requested": "98",
    "Job Classification": "45-2092.00 - Farmworkers and Laborers, Crop, Nursery, and Greenhouse",
    "Experience Required": "Yes",
    "Months of Experience Required": "2",
    "Special Requirements": "Workers must be dependable and punctual and have the ability to stand, bend, and work for long periods outdoors...",
    "Number of Hours Per Week": "48",
    "Work Schedule (Start/End time)": "7:30 A.M. - 4:00 P.M.",
    "Company Name": "Eberry Harvest Company LLC",
    "Location": "LaBelle, FL 33935",
    "Address": "218 N Graves St, Quincy, FL 32351",
    "ETA Case Number": "H-300-26210-131199",
    "Multiple Worksites": "No",
    "Additional Wage Information": "Per 24-quart bucket. (See Addendum A.)",
    "Date Posted": "8/17/2026",
    "Piece Rate Offer": "$0.70",
    "Total Workers": "98",
    "H-2A Workers": "98",
    "Place of Employment Address": "218 N Graves St",
    "Employment City": "Quincy",
    "Employment State": "Florida",
    "Employment Postal Code": "32351",
    "Employment County": "Gadsden County",
    "Housing": {
        "Address/Location": "371 Centenary Camp Rd",
        "City": "Quincy",
        "State": "Florida",
        "Postal Code": "32352",
        "County": "Gadsden County",
        "Total Units": "7",
        "Total Occupancy": "80"
    },
    "Additional Housing": [
        {
            "Physical Location": "39 Rose Ct\nQuincy, Florida 32352\nGADSDEN COUNTY",
            "Information": "Big Wish LLC Trailer Park",
            "Total Units": "6",
            "Total Occupancy": "20",
            "Address/Location": "39 Rose Ct",
            "City": "Quincy",
            "State": "Florida",
            "Postal Code": "32352",
            "County": "GADSDEN COUNTY"
        }
    ]
}
```

> **An empty value always means the job order genuinely didn't carry that detail** — never "not collected". Where a field couldn't be read reliably off the scanned PDF, the Actor leaves it blank rather than guessing.

Most fields are self-explanatory — DOL's own labels come straight from the job page (`Job Classification`, `Additional Wage Information`, `Special Requirements`, and similar are exactly as published, not renamed). The ones worth a note:

| Field | Description |
| --- | --- |
| `Job Duties` / `Status` / `Worksite *` / `Pay Rate *` | From the public job page, always present regardless of the PDF toggle. |
| `Total Workers` / `H-2A Workers` | PDF-only. Worker counts exactly as printed on the job order form: the total requested, and how many of those are H-2A workers. |
| `Housing` | PDF-only. The primary worker housing site: address fields plus `Total Units` and `Total Occupancy`. |
| `Additional Housing` | PDF-only. One entry per extra housing site — same address fields as `Housing`, plus `Physical Location` (the raw address block as printed) and `Information` (notes from the form). Empty when the job order lists no extra sites. |

### Pricing

Two tiers, controlled by **Include PDF details**:

| Tier | What you get | Cost driver |
| --- | --- | --- |
| Off (default) | Job page data only — title, dates, employer contact, worksite address, pay, duties, requirements | One page fetch per posting — fast, light on proxy traffic |
| On | Everything above, plus housing (addresses, units, occupancy) and exact worker counts from the official job-order PDF | One extra PDF download per posting — the larger cost, billed per gigabyte of residential proxy traffic |

The PDF tier is only charged for postings whose PDF actually downloaded and parsed successfully — a failed or unreadable PDF costs nothing, and the run keeps going with the job-page data for that posting.

Budget by run time: roughly 30–50 seconds per posting when PDFs are on, faster with them off. The reliable estimate is your own: run once with **Max job posts** set to `5` (PDFs on or off, matching how you plan to run it), check that run's cost in the Console, and multiply.

### Integrations & scheduling

Results don't have to stay on Apify. Without writing any code you can:

- **Send postings to Google Sheets, Airtable or Slack** — pick the integration on the Actor's Integrations tab and every run appends its results automatically
- **Connect anything else via Zapier or Make** — thousands of apps, triggered when a run finishes
- **Fire a webhook** to your own server the moment a run completes, with a link to the fresh dataset
- **Pull the data over the API** in JSON, CSV, Excel or XML — one URL, ideal for a script or notebook
- **Call it from an AI agent over MCP** — Apify's [MCP server](https://mcp.apify.com) exposes this Actor as a tool for any MCP-compatible agent (Claude, and others), so an agent can look up seasonal job postings mid-conversation instead of you writing integration code

**Run it on a schedule.** Save a task with `offset: -1`, set it to run every morning, and send the output to a sheet — that's a working new-posting alert with no code at all. Because `offset` is date-based, each run picks up only what's new, so your sheet grows without duplicating yesterday's postings.

### FAQ

**My run failed, or every posting errored.**
Almost always the proxy — set the country to United States.

**My run returned no jobs.**
Filters too narrow. Widen the day offset to `-30`, switch job type to **All**, or clear the location. The log prints the filter used.

**Some housing or address fields are empty.**
The source documents are scanned forms; the Actor leaves a field blank rather than guessing. Unsplittable addresses are kept whole in `Physical Location`.

**Some postings are missing.**
A PDF that can't be read is skipped and logged — the run summary lists those case numbers so you can re-run just them.

**Is this legal?**
The Seasonal Jobs portal is a public U.S. government transparency resource. No authentication, no private data. Comply with the laws in your jurisdiction.

### Support

Bugs, feature requests, or custom work — more states, extra fields, scheduled pipelines — open an issue on Apify or email **<alkausarimujahid@gmail.com>**.

***

<sub>This Actor is independent and is not affiliated with, endorsed by, or sponsored by the U.S. Department of Labor or any government agency. It collects only publicly available data from the DOL Seasonal Jobs portal. Use the data responsibly and in accordance with applicable law.</sub>

# Actor input Schema

## `location` (type: `string`):

State, district or territory where the work takes place. Leave empty to search every location.

## `jobtype` (type: `string`):

Type of seasonal work to fetch. Agricultural covers farm, crop, nursery and livestock work; non-agricultural covers other seasonal roles.

## `offset` (type: `integer`):

Day offset applied to today's date (US Eastern) to compute the minimum job begin date. Example: -7 includes jobs beginning up to 7 days ago; 0 means jobs beginning today or later.

## `top` (type: `integer`):

Maximum number of job posts to fetch and process.

## `skip` (type: `integer`):

Number of matching job posts to skip (use together with 'Max job posts' for pagination).

## `order` (type: `string`):

Order in which matching job posts are returned by the DOL search API.

## `fetchJobOrderPdf` (type: `boolean`):

Off (default): extract each job from its public posting page only - title, dates, employer contact, worksite address, pay, duties and requirements. Turn ON to also download and read the official job-order PDF for housing details (addresses, units, occupancy) and exact worker counts. This adds one PDF download per job, using significantly more residential proxy data - priced accordingly.

## `proxyConfiguration` (type: `object`):

Proxy used for requests to the DOL APIs. US residential proxies are recommended.

## Actor input object example

```json
{
  "location": "Florida",
  "jobtype": "H-2A",
  "offset": 0,
  "top": 10,
  "skip": 0,
  "order": "accepted_date desc",
  "fetchJobOrderPdf": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("alkausari_mujahid/dol-seasonal-jobs-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    } }

# Run the Actor and wait for it to finish
run = client.actor("alkausari_mujahid/dol-seasonal-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call alkausari_mujahid/dol-seasonal-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,alkausari_mujahid/dol-seasonal-jobs-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/syddOjPyZi6HdETcT/builds/Bw1BeJGlsdXnu5ibK/openapi.json
