# Dice Jobs Scraper – Pay Per Job, No Browser (`murmuring_headlamp/dice-jobs-fast`) Actor

Scrapes Dice.com job postings (US tech jobs) over plain HTTP. Input: queries plus optional location, posted date, employment, workplace and employer filters. Output per job: id, title, company, location, salary, dates and, with fetchDetails, description, skills and apply URL. $4 per 1,000 jobs.

- **URL**: https://apify.com/murmuring_headlamp/dice-jobs-fast.md
- **Developed by:** [Ivan Alexeev](https://apify.com/murmuring_headlamp) (community)
- **Categories:** Jobs
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.80 / 1,000 jobs

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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does Dice Jobs Scraper do?

It collects job postings from the **Dice.com job search** (dice.com/jobs), the US job board for software, data, cloud, security and other tech roles, for the queries you give it, optionally limited to a location, a posting period, an employment type, a workplace type, an employer type or Easy Apply postings. For each job you get:

- **Title, company, company profile link, logo, location** (city, state, country) and whether the job is remote, hybrid or on-site
- **Employment type** (Full-time, Contract, Third Party, …), **employer type** (direct hire or recruiter), the **salary text** as the employer wrote it, the posting and last-modified dates and the card summary
- With **Fetch job pages** on: the **full description** (plain text and HTML), the **skills** list, the structured **salary range**, the **apply URL** on the employer's site or the **apply e-mail**, the position id, the employer's Dice id and the posting's expiry date
- A stable `jobId` plus the search metadata: query, rank in the search, total results and the location Dice actually searched

It is made for recruiters and staffing agencies watching the US tech market, job boards and aggregators that need fresh Dice postings, salary and skills researchers, and anyone who wants a daily CSV of new jobs for a few search terms.

### Why this Dice scraper?

- **No browser.** Dice renders its search and job pages on the server, so the scraper reads them with plain HTTP requests. Ten jobs with full details take a few seconds on 256 MB of memory.
- **Datacenter proxy by default.** The pages are served to Apify's default datacenter pool, so the platform cost per job is a fraction of a cent. Residential proxy stays available as an option.
- **Pay per job, nothing else.** You pay for jobs written to the dataset plus one actor-start event of $0.00005 per run. Failed requests, duplicates and empty searches cost nothing.
- **Honest failures.** If every search fails the run fails, so a scheduled job can't quietly return nothing. Pages without the expected markup are saved as `DEBUG_*.html` in the run's key-value store.

### How to use it

| Input | Description |
|---|---|
| `queries` | Job searches as typed on dice.com, one search per entry, up to 100. Example: `["python", "data engineer"]`. |
| `location` | Optional free text such as `"Austin, TX, USA"`, `"New York, NY"` or `"USA"`. Empty means all of Dice. |
| `maxItemsPerSearch` | Unique jobs per query (1–750). Dice serves at most 25 pages of 30 jobs per search. |
| `fetchDetails` | Open every job page for the description, skills, salary range, apply URL and the other detail fields. Default on. |
| `postedDate` | `ONE` (today), `THREE` (last 3 days) or `SEVEN` (last 7 days). |
| `employmentType` | `FULLTIME`, `PARTTIME`, `CONTRACTS` or `THIRD_PARTY`. |
| `workplaceType` | `On-Site`, `Hybrid` or `Remote`. |
| `employerType` | `Direct Hire`, `Recruiter` or `Other`. |
| `easyApply` | Only postings that take applications on Dice itself. |
| `maxConcurrency`, `maxRetries` | Parallel requests (1–5) and attempts per page (1–3). |
| `proxyConfiguration` | Apify Proxy, datacenter pool by default. |

```json
{
  "queries": ["python", "data engineer"],
  "location": "Austin, TX, USA",
  "maxItemsPerSearch": 100,
  "fetchDetails": true,
  "postedDate": "SEVEN",
  "workplaceType": "Remote"
}
```

Each filter takes a single value per run, as on the site. To cover both Contract and Full-time, run two tasks.

### Output fields

| Field | Type | Notes |
|---|---|---|
| `jobId`, `diceId` | string | Dice's UUID of the posting (stable across runs) and the 32-character legacy id |
| `url`, `title`, `companyName` | string | Always filled; `url` is the job page on Dice |
| `companyProfileUrl`, `logoUrl` | string or null | Company profile on Dice and logo image |
| `location`, `city`, `state`, `country` | string or null | As shown on the card, e.g. `McLean, Virginia, USA`; null for remote-only postings |
| `isRemote`, `workplaceTypes` | boolean, array | Remote flag and the workplace types the posting allows: `On-Site`, `Hybrid`, `Remote` (may list several) |
| `employmentType`, `employerType` | string or null | As on the site, e.g. `Contract, Third Party` and `Direct Hire`, `Recruiter` or `Other` |
| `easyApply` | boolean or null | True when the application runs on Dice; null when the site did not say |
| `salary` | string or null | Free text as the employer wrote it, e.g. `$63 - $65 per hour` or `Depends on Experience`; null when the card shows none |
| `postedAt`, `modifiedAt` | string | ISO 8601 timestamps of the posting and its last update |
| `summary`, `score` | string or null, number | The card's excerpt and Dice's relevance score |
| `description`, `descriptionHtml` | string or null | Full description as text (lists as `- ` bullets) and as HTML; job page only |
| `skills` | array | Skills the employer tagged; empty without the job page |
| `baseSalary` | object or null | `{currency, min, max}` from the posting's structured data; a single amount gives `min == max`; null when the employer stated none; job page only |
| `validThrough` | string or null | When the posting expires; job page only |
| `applyType`, `applyUrl`, `applyEmail` | string or null | `External` with the employer's apply URL, or `Internal` (Easy Apply) with an e-mail when the employer gave one; job page only |
| `positionId`, `employerDiceId` | string or null | The employer's own reference and its Dice id; job page only |
| `detailError` | string or null | Set when the job page could not be fetched or parsed, or the job was removed; the card fields are still filled |
| `query`, `position`, `totalResults` | string, integer, integer | The query, the job's rank in that search (1 = first) and Dice's result count |
| `searchedLocation`, `locationPrecision` | string or null | How Dice geocoded your location text, e.g. `Austin, TX, USA` with precision `City` |
| `scrapedAt` | string | ISO 8601 UTC |

```json
{
  "query": "python",
  "position": 1,
  "totalResults": 29060,
  "searchedLocation": "United States",
  "locationPrecision": "Country",
  "jobId": "56bfa0f0-8d70-4033-8bde-f962d9919761",
  "url": "https://www.dice.com/job-detail/56bfa0f0-8d70-4033-8bde-f962d9919761",
  "title": "Full-stack Engineer 4 (Manager, IC - Python, JavaScript/TypeScript)",
  "companyName": "Capital One",
  "location": "McLean, Virginia, USA",
  "isRemote": false,
  "workplaceTypes": ["On-Site"],
  "employmentType": "Full-time",
  "employerType": "Direct Hire",
  "salary": "USD 197,300.00 - 225,100.00 per year",
  "postedAt": "2026-10-02T21:02:28Z",
  "skills": ["Microservices", "Python", "TypeScript"],
  "baseSalary": {"currency": "USD", "min": 197300, "max": 197300},
  "applyType": "External",
  "applyUrl": "https://www.capitalonecareers.com/job/-/-/234/101404679360",
  "description": "Do you love building and pioneering in the technology space? …",
  "scrapedAt": "2026-10-30T16:20:21Z"
}
```

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

You pay per job written to the dataset. Platform usage (compute and the datacenter proxy) is included in that price; without a browser it amounts to a few cents per thousand jobs anyway.

| Plan | Price per 1,000 jobs |
|---|---|
| Free | $4.00 |
| Starter (Bronze) | $3.60 |
| Scale (Silver) | $3.20 |
| Business (Gold) and above | $2.80 |

Each run also charges $0.00005 for the actor start. Example: 1,000 jobs with full details on the free plan cost $4.00 for the jobs plus $0.00005 for the start; the few cents of platform usage for the roughly 1,035 requests are already covered. Set a maximum total charge on the run and the scraper stops once it is used up: it checks the remaining budget before every search page and every job page.

### Use the data in Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("murmuring_headlamp/dice-jobs-fast").call(
    run_input={"queries": ["data engineer"], "location": "Austin, TX, USA", "maxItemsPerSearch": 100}
)
jobs = client.dataset(run["defaultDatasetId"]).list_items().items
```

### FAQ

**Why do I get at most 750 jobs per query?** Dice serves 25 pages of 30 jobs and answers any deeper page with page 25 again, so the scraper stops there. To go deeper, split the search: one query per city or state, per posting period (`postedDate`) or per employment type, and merge on `jobId`.

**My location gave results from the whole country.** Dice geocodes the location text on its servers and falls back to a wider area when it does not recognise the text. Check `searchedLocation` and `locationPrecision` (`City`, `Country`, …) in the output and use the spelling Dice suggests, such as `Austin, TX, USA`.

**Why is `salary` missing or so varied?** It is the free text the employer typed on the card (`$63 - $65 per hour`, `Depends on Experience`), and many postings have none. `baseSalary` from the job page is the structured amount when the employer gave one.

**Why is `applyUrl` empty?** It is filled only for `applyType: "External"`, where the application runs on the employer's site. Easy Apply postings (`Internal`) keep candidates on Dice; the job `url` is the place to send them, and `applyEmail` is set when the employer listed one.

**The card said "posted 2 days ago" but `postedAt` is older.** The relative date on the search card tracks the last update of the posting, which is `modifiedAt`. `postedAt` is the original posting date from the data behind the card.

**A job page failed.** The item keeps its search card fields and `detailError` says why, for example a posting removed between the search and the fetch. Such items are still charged, since the job was found.

**Is it legal?** The scraper reads public job postings, does not log in and collects no candidate data. It is not affiliated with Dice or DHI Group. Respect the site's terms and robots rules, and you are responsible for how you use the results.

### Related actors

- [Google Jobs Scraper](https://apify.com/murmuring_headlamp/google-jobs-fast): job postings aggregated by Google, any country.
- [Xing Jobs Scraper](https://apify.com/murmuring_headlamp/xing-jobs-fast): job offers from Germany, Austria and Switzerland.

*This Actor is not affiliated with Dice or DHI Group.*

# Actor input Schema

## `queries` (type: `array`):

Job searches as you would type them on dice.com, e.g. "python", "data engineer" or "devops aws". One search per entry, up to 100; duplicates are searched once.

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

Optional location as free text, e.g. "Austin, TX, USA", "New York, NY" or "USA". Dice geocodes it on the server (a city covers a 30-mile radius); empty means all of Dice. The output tells you what the site understood in searchedLocation and locationPrecision.

## `maxItemsPerSearch` (type: `integer`):

Upper limit of unique jobs for each query, 1–750. Dice serves 30 jobs per page and at most 25 pages per search, so one query yields up to 750 jobs; split by location or filters to go deeper.

## `fetchDetails` (type: `boolean`):

Open every job's page for the full description (text and HTML), skills, salary range, apply URL or e-mail, position id and the employer's Dice id. One extra request per job. Off, you get the search card fields only.

## `postedDate` (type: `string`):

Only jobs posted today, in the last 3 days or in the last 7 days.

## `employmentType` (type: `string`):

One employment type as Dice filters it. A posting can list several types (e.g. "Contract, Third Party"); the filter keeps postings that include the chosen one.

## `workplaceType` (type: `string`):

Only on-site, hybrid or remote postings.

## `employerType` (type: `string`):

Postings by the hiring company itself (direct hire), by recruiters or by other employers.

## `easyApply` (type: `boolean`):

Only postings that take applications on Dice itself (Easy Apply). These have no external applyUrl.

## `maxConcurrency` (type: `integer`):

Pages fetched in parallel (search pages and job pages).

## `maxRetries` (type: `integer`):

Attempts per page, each with a fresh proxy session.

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

Dice serves its pages to the default datacenter proxy, which keeps the platform cost per job near zero. Switch to residential only if your runs get blocked.

## Actor input object example

```json
{
  "queries": [
    "python"
  ],
  "maxItemsPerSearch": 10,
  "fetchDetails": true,
  "postedDate": "",
  "employmentType": "",
  "workplaceType": "",
  "employerType": "",
  "easyApply": false,
  "maxConcurrency": 3,
  "maxRetries": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": []
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One item per 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 = {
    "queries": [
        "python"
    ],
    "maxItemsPerSearch": 10,
    "fetchDetails": true,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": []
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("murmuring_headlamp/dice-jobs-fast").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 = {
    "queries": ["python"],
    "maxItemsPerSearch": 10,
    "fetchDetails": True,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": [],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("murmuring_headlamp/dice-jobs-fast").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 '{
  "queries": [
    "python"
  ],
  "maxItemsPerSearch": 10,
  "fetchDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": []
  }
}' |
apify call murmuring_headlamp/dice-jobs-fast --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,murmuring_headlamp/dice-jobs-fast"
        }
    }
}
```

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/iD8qTglOGi6krVnBA/builds/1R9ZkQVBIKyU8l8q7/openapi.json
