# SimplyHired Jobs Scraper (`automation-lab/simplyhired-jobs-scraper`) Actor

Scrape SimplyHired job searches by keyword and location, export structured listings, and optionally enrich full descriptions for recruiting and labor-market workflows.

- **URL**: https://apify.com/automation-lab/simplyhired-jobs-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 75.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## SimplyHired Jobs Scraper

Collect structured SimplyHired job listings by keyword and location or from saved SimplyHired search URLs.

The Actor parses SimplyHired’s server-rendered job data, follows pagination, removes duplicate jobs, and can optionally fetch each job page for a full description.

It is designed for recurring recruiting, labor-market research, job aggregation, and hiring-signal lead generation.

### What does SimplyHired Jobs Scraper do?

SimplyHired Jobs Scraper turns public SimplyHired search results into integration-ready dataset rows.

You can:

- search by job keywords and location;
- reuse one or more SimplyHired `/search` URLs;
- cap both pages and output records;
- deduplicate jobs by stable source identifier;
- include salary, job type, requirements, benefits, ratings, and posting metadata;
- optionally enrich every result from its job detail page;
- export results as JSON, CSV, Excel, XML, or RSS through Apify datasets.

The default mode makes one request per result page.

Detail enrichment is explicit because it requires an additional request per job.

### Who is it for?

#### Recruiters and sourcing teams

Build repeatable candidate-market searches and review newly advertised roles by employer, skill, or geography.

#### Job aggregators

Normalize SimplyHired listings into a stable dataset for indexing, matching, or downstream enrichment.

#### Labor-market analysts

Track job titles, locations, salary text, employment types, and hiring organizations over time.

#### Sales and lead-generation teams

Use fresh hiring activity as a company-growth signal and route suitable records to a CRM.

#### Developers and data teams

Schedule searches and connect the results to databases, warehouses, webhooks, Make, Zapier, or custom applications.

### Why use this Actor?

- **Structured output:** no DOM selectors or HTML cleanup required downstream.
- **Two input routes:** use simple keyword/location fields or complete search URLs.
- **Stable deduplication:** repeated and overlapping searches do not produce duplicate job keys within a run.
- **Bounded pagination:** `maxItems` and `maxPages` keep runs predictable.
- **Optional deep data:** detail enrichment can be enabled only when full descriptions are needed.
- **Clear failures:** challenge pages and unsupported responses fail the run instead of returning a misleading empty dataset.
- **US residential sessions:** requests use a coherent session suited to SimplyHired’s protected public pages.

### What SimplyHired job data can I extract?

| Field | Description |
| --- | --- |
| `jobKey` | Stable SimplyHired job identifier |
| `title` | Job title |
| `company` | Hiring company |
| `location` | Displayed job location |
| `snippet` | Search-result summary |
| `descriptionText` | Clean full description when available |
| `descriptionHtml` | Source description HTML when available |
| `salary` | Displayed salary or pay range |
| `jobTypes` | Employment types |
| `requirements` | Requirements exposed by the source |
| `benefits` | Benefits exposed by the source |
| `remoteAttributes` | Remote or work-setting attributes |
| `companyRating` | Displayed company rating |
| `postingDate` | Source posting date or relative age |
| `sponsored` | Whether the listing is sponsored |
| `city`, `state` | Structured location fields when available |
| `latitude`, `longitude` | Coordinates when available |
| `sourceUrl` | Canonical or source job URL |
| `searchQuery`, `searchLocation` | Search context that produced the row |
| `scrapedAt` | Extraction timestamp |

Source fields may be absent for individual jobs.

The dataset schema therefore treats fields as nullable.

### How to scrape SimplyHired jobs

1. Open the Actor in Apify Console.
2. Enter job keywords such as `software engineer`.
3. Enter a location such as `Austin, TX`.
4. Set `maxItems` and `maxPages` for the desired workload.
5. Enable `includeDescription` only when full job-page enrichment is needed.
6. Keep the default US residential proxy configuration.
7. Click **Start**.
8. Open the **Dataset** tab to preview or download records.

For a saved SimplyHired search, place its complete `/search` URL in `startUrls` instead of using structured fields.

### Input parameters

| Parameter | Type | Default | Purpose |
| --- | --- | --- | --- |
| `query` | string | `software engineer` prefill | Job title, employer, or skill keywords |
| `location` | string | `Austin, TX` prefill | City, state, or location accepted by SimplyHired |
| `startUrls` | array | optional | One or more SimplyHired `/search` URLs |
| `maxItems` | integer | `100` | Maximum unique jobs saved across all searches |
| `maxPages` | integer | `10` | Maximum pages fetched per search |
| `includeDescription` | boolean | `false` | Fetch each job page for full description data |
| `proxyConfiguration` | object | US Residential | Apify proxy settings |

Provide either `query` or at least one `startUrls` entry.

Only `simplyhired.com/search` URLs are accepted.

The Actor rejects malformed limits and unsupported URLs before scraping.

### Input examples

A small keyword search:

```json
{
  "query": "software engineer",
  "location": "Austin, TX",
  "maxItems": 20,
  "maxPages": 2,
  "includeDescription": false
}
```

A saved source-specific search:

```json
{
  "startUrls": [
    {
      "url": "https://www.simplyhired.com/search?q=registered+nurse&l=Chicago%2C+IL"
    }
  ],
  "maxItems": 50,
  "maxPages": 5
}
```

A description-enrichment workflow:

```json
{
  "query": "data analyst",
  "location": "Remote",
  "maxItems": 100,
  "maxPages": 10,
  "includeDescription": true
}
```

### Output example

A representative dataset row has this shape:

```json
{
  "jobKey": "abc123jobkey",
  "title": "Software Engineer",
  "company": "Example Technology Company",
  "location": "Austin, TX",
  "snippet": "Build reliable services for a growing product team.",
  "descriptionText": null,
  "descriptionHtml": null,
  "salary": "$100,000 - $130,000 a year",
  "jobTypes": ["Full-time"],
  "requirements": [],
  "benefits": ["Health insurance", "Paid time off"],
  "remoteAttributes": ["Hybrid work"],
  "companyRating": 4.2,
  "postingDate": "2 days ago",
  "sponsored": false,
  "city": "Austin",
  "state": "TX",
  "latitude": 30.2672,
  "longitude": -97.7431,
  "sourceUrl": "https://www.simplyhired.com/job/abc123jobkey",
  "searchQuery": "software engineer",
  "searchLocation": "Austin, TX",
  "scrapedAt": "2026-01-15T12:00:00.000Z"
}
```

Exact field availability depends on each listing and whether enrichment is enabled.

### How much does it cost to scrape SimplyHired jobs?

The Actor uses pay-per-event pricing:

- a **$0.0005 start fee** per run;
- **$0.00115 per saved job** on the FREE tier;
- decreasing per-job prices on higher Apify subscription tiers.

At the FREE-tier price, excluding variable platform and proxy consumption already handled by Apify’s PPE model:

| Jobs | FREE-tier calculation | Actor charge (USD) |
| ---: | --- | ---: |
| 10 | `0.0005 + 10 × 0.00115` | 0.0120 |
| 100 | `0.0005 + 100 × 0.00115` | 0.1155 |
| 1,000 | `0.0005 + 1,000 × 0.00115` | 1.1505 |

Detail enrichment produces the same number of charged dataset items, but it makes more residential requests and can take longer.

Prices shown here must match the active Actor pricing displayed by Apify.

### Pagination, limits, and deduplication

The Actor stops when any of these conditions is reached:

- `maxItems` unique jobs have been saved;
- `maxPages` pages have been visited for the current search;
- SimplyHired indicates that no next page exists;
- a valid page contains no job cards.

Jobs are deduplicated by `jobKey` across all input searches in the run.

This is useful when locations or keyword searches overlap.

### Detail enrichment

With `includeDescription: false`, the Actor uses data embedded in search-result pages.

This is the fastest and least expensive mode.

With `includeDescription: true`, each accepted job’s detail page is fetched before the row is saved.

Use enrichment when your workflow needs:

- full description HTML;
- clean description text;
- extra requirements or benefits;
- structured city, state, or coordinates that are absent from a card.

Avoid enrichment when list-page fields are sufficient.

### Proxy behavior and anti-bot protection

SimplyHired blocks ordinary datacenter requests with Cloudflare.

The Actor defaults to a sticky US Apify Residential proxy session.

A sticky session keeps proxy identity, TLS behavior, and request headers coherent across pagination and details.

Transient network errors, HTTP 429 responses, and temporary server failures are retried with bounded backoff.

A challenge page is treated as an error, not as a no-results search.

Custom proxies may work, but the default route is the tested product configuration.

### Scheduled monitoring workflow

To monitor new jobs:

1. Save one narrow keyword/location input.
2. Run it once and confirm the output.
3. Create an Apify schedule for the desired interval.
4. Export `jobKey` and `postingDate` to your database.
5. Upsert by `jobKey` to identify new or changed listings.
6. Trigger a webhook for new records.

The Actor deduplicates within one run.

Cross-run history belongs in your destination database or automation.

### Integration ideas

- Send new matching roles to Slack or Microsoft Teams.
- Add hiring companies to a CRM for sales research.
- Load jobs into BigQuery, Snowflake, or PostgreSQL.
- Feed descriptions into a skill or salary classification pipeline.
- Compare job counts by geography on a schedule.
- Monitor selected employers through source-specific searches.
- Use Make or Zapier to route new rows without custom code.

### Run with the Apify API using cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~simplyhired-jobs-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "software engineer",
    "location": "Austin, TX",
    "maxItems": 20,
    "maxPages": 2
  }'
```

Do not commit API tokens to source control.

### Run with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor('automation-lab/simplyhired-jobs-scraper').call({
    query: 'software engineer',
    location: 'Austin, TX',
    maxItems: 20,
    maxPages: 2,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Run with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

run = client.actor("automation-lab/simplyhired-jobs-scraper").call(run_input={
    "query": "software engineer",
    "location": "Austin, TX",
    "maxItems": 20,
    "maxPages": 2,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

### Use with Apify MCP

#### Claude Code setup

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/simplyhired-jobs-scraper"
```

#### Claude Desktop setup

Claude Desktop clients can use:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/simplyhired-jobs-scraper"
    }
  }
}
```

#### Cursor setup

Add the same JSON MCP server entry in Cursor’s MCP settings.

#### VS Code setup

Add the same HTTP MCP server URL in VS Code’s MCP server configuration.

Example prompts:

- “Find up to 50 software engineering jobs around Austin on SimplyHired.”
- “Extract this SimplyHired nurse search URL and return company, salary, and posting date.”
- “Enrich remote data analyst listings and summarize recurring required skills.”

### Reliability and failure behavior

The Actor validates the response status, content type, and embedded `__NEXT_DATA__` payload.

It retries only failures that can be transient.

The run fails clearly after retry exhaustion rather than silently producing zero records.

A valid search with no matching jobs succeeds with an empty dataset.

If SimplyHired changes its embedded data structure, inspect the run log and report the affected input and run ID.

### Limitations

- SimplyHired can change its public pages and anti-bot controls without notice.
- The Actor supports public `/search` pages, not account-only pages.
- A job can omit salary, rating, benefits, requirements, coordinates, or other fields.
- Relative posting dates are preserved as supplied by the source.
- Search results can vary by geography, time, and SimplyHired ranking.
- Removed jobs cannot be recovered after the source stops serving them.
- High enrichment limits increase duration and residential transfer.
- The Actor does not contact employers or candidates.

### Responsible use and legality

This Actor extracts publicly accessible job information.

You are responsible for ensuring that your use complies with SimplyHired’s terms, applicable laws, and your organization’s policies.

Do not use output to discriminate, harass, spam, or make automated high-impact decisions about individuals.

Minimize collection, retention, and redistribution of personal data.

Respect deletion requests and applicable database rights.

### Troubleshooting

#### The run says a challenge or unsupported page was returned

Keep the default US residential proxy configuration and retry later.

Do not switch to a direct or datacenter route for SimplyHired.

Include the run ID when reporting a persistent source change.

#### The dataset is empty

Confirm the same search currently has public results on SimplyHired.

Check spelling and broaden either the keyword or location.

A valid no-result search is not an extraction failure.

#### Full descriptions are null

Set `includeDescription` to `true`.

Some source jobs still omit individual detail fields.

#### The run stops earlier than expected

Check both `maxItems` and `maxPages`.

Source pagination can also end before either user limit.

### Related Automation Lab Actors

- [Indeed Scraper](https://apify.com/automation-lab/indeed-scraper) for another broad job-search source.
- [LinkedIn Jobs Scraper](https://apify.com/automation-lab/linkedin-jobs-scraper) for LinkedIn job research.
- [Remote OK Jobs Scraper](https://apify.com/automation-lab/remoteok-jobs-scraper) for remote-focused roles.
- [Workday Jobs Scraper](https://apify.com/automation-lab/workday-jobs-scraper) for employer career sites hosted on Workday.

Combine source-specific Actors only when your workflow needs broader coverage.

### FAQ

#### Does the Actor require a SimplyHired account?

No.

It processes public search and job pages without source credentials.

#### Can I scrape more than one search?

Yes.

Add multiple SimplyHired search URLs to `startUrls`; `maxItems` applies across the entire run.

#### Are duplicate jobs removed?

Yes, within each run.

Records are deduplicated by stable `jobKey` across searches and pages.

#### Can I get HTML and plain-text descriptions?

Yes.

Enable detail enrichment; the Actor emits both `descriptionHtml` and `descriptionText` when the source provides a description.

#### Can I use my own proxy?

The input supports Apify proxy configuration.

The default US Residential configuration is recommended because direct datacenter requests are blocked.

#### How fresh are results?

Rows reflect what SimplyHired served during the run.

Use an Apify schedule for recurring monitoring.

# Actor input Schema

## `query` (type: `string`):

Job title, skill, or employer keywords, for example software engineer.

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

City, state, or other location accepted by SimplyHired.

## `startUrls` (type: `array`):

Optional SimplyHired /search URLs. Use these for saved searches with source-specific filters.

## `maxItems` (type: `integer`):

Maximum unique job records saved across all searches.

## `maxPages` (type: `integer`):

Safety limit for pagination of each search URL.

## `includeDescription` (type: `boolean`):

Fetch each job detail page for full description and additional fields. This uses more residential proxy traffic.

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

SimplyHired requires a US residential proxy. The default is Apify Residential in the United States.

## Actor input object example

```json
{
  "query": "software engineer",
  "location": "Austin, TX",
  "startUrls": [
    {
      "url": "https://www.simplyhired.com/search?q=registered+nurse&l=Chicago%2C+IL"
    }
  ],
  "maxItems": 20,
  "maxPages": 10,
  "includeDescription": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

Dataset containing one normalized record per unique SimplyHired job.

# 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 = {
    "query": "software engineer",
    "location": "Austin, TX",
    "startUrls": [
        {
            "url": "https://www.simplyhired.com/search?q=registered+nurse&l=Chicago%2C+IL"
        }
    ],
    "maxItems": 20,
    "maxPages": 10,
    "includeDescription": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/simplyhired-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 = {
    "query": "software engineer",
    "location": "Austin, TX",
    "startUrls": [{ "url": "https://www.simplyhired.com/search?q=registered+nurse&l=Chicago%2C+IL" }],
    "maxItems": 20,
    "maxPages": 10,
    "includeDescription": False,
}

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

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

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

```

## CLI example

```bash
echo '{
  "query": "software engineer",
  "location": "Austin, TX",
  "startUrls": [
    {
      "url": "https://www.simplyhired.com/search?q=registered+nurse&l=Chicago%2C+IL"
    }
  ],
  "maxItems": 20,
  "maxPages": 10,
  "includeDescription": false
}' |
apify call automation-lab/simplyhired-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=automation-lab/simplyhired-jobs-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/lo9xdsvqLWcRw6eSa/builds/CB0SxkxjYdXodqWE3/openapi.json
