# Dice Jobs Scraper (`solidcode/dice-scraper`) Actor

\[💰 $0.8 / 1K] Extract US tech job listings from Dice.com. Search by keyword, location, employment type, and remote/sponsorship filters to get structured data including titles, companies, salaries, descriptions, and apply links.

- **URL**: https://apify.com/solidcode/dice-scraper.md
- **Developed by:** [SolidCode](https://apify.com/solidcode) (community)
- **Categories:** Jobs, Automation, Developer tools
- **Stats:** 41 total users, 9 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 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

## Dice Tech Jobs Scraper

Extract US tech job listings from Dice.com at scale — titles, companies, locations, parsed salaries, full descriptions, employer skill tags, remote and hybrid workplace flags, and direct apply links, for any keyword, location, or pasted Dice search URL. Built for recruiters, sourcers, and labor-market analysts who need Dice's tech-hiring feed as a clean spreadsheet, without paging through listings by hand.

### Why This Scraper?

- **28 structured fields on every job** — 5 compensation fields, 4 workplace-type fields, employer skill tags, HTML and plain-text descriptions, employer classification, and a direct apply link, all pre-parsed
- **Salary broken out into 4 sortable fields** — `salaryMin`, `salaryMax`, `salaryCurrency` and `salaryPeriod` alongside the raw string, and every extracted figure carries its pay period, so a $95/hour contract never lands in the same column as a $190,000 salary
- **Full job descriptions on every row** — the complete posting text from each job's own detail page, in both HTML and plain text, not the two-line search-results snippet
- **The employer's own skill tags** — the exact technology tags attached to each posting (`Python`, `Kubernetes`, `Terraform`, `PostgreSQL`), so you can measure stack-level demand without keyword-matching a wall of description text
- **8 structured filters, zero URL crafting** — keyword, location, radius (1-100 miles), posted-within window, employment type, remote-only, easy-apply, and willing-to-sponsor are all proper input fields
- **Visa-sponsorship filtering that genuinely narrows** — switching `willingToSponsor` on typically cuts a broad keyword search to under a tenth of its listings, turning manual triage into a single run
- **Re-listings never billed twice** — Dice re-posts the same role across pages and under fresh IDs; identical copies are filtered out by content, not just by ID, and your result budget keeps going until it holds that many distinct jobs
- **Employer type on every row** — `Direct Hire`, `Recruiter`, or `Other`, exactly as Dice classifies it, so agency reposts drop out of a sourcing list with one filter

### Use Cases

**Recruiting & Sourcing**

- Build candidate pipelines by tracking which companies are hiring for specific tech stacks in your region
- Identify staffing firms vs direct employers via the `employerType` field
- Spot easy-apply roles in seconds for high-volume sourcing campaigns

**Lead Generation**

- Surface companies actively hiring engineers — strong intent signal for B2B SaaS, recruiting tools, dev-tool vendors, and benefits providers
- Switch on the willing-to-sponsor filter to find employers open to international candidates and partner with immigration services
- Generate prospect lists of companies posting frequently in your category

**Market & Compensation Research**

- Track salary trends across cities, roles, and seniorities using parsed `salaryMin`/`salaryMax`
- Analyze remote-vs-hybrid-vs-onsite mix by location or employer
- Map demand for specific technologies (e.g. Rust, Kubernetes, LLMs) by volume and posted date

**Job Aggregation & Niche Boards**

- Power a tech-only or remote-only job board with fresh Dice listings
- Build niche aggregators (e.g. visa-sponsorship boards, contract-only boards, easy-apply boards) using the filter set
- Enrich existing job-board records with full descriptions and direct apply links

**Academic & Labor-Market Research**

- Build longitudinal datasets of tech-hiring activity by region and skill
- Study employer behavior around remote work, sponsorship, and contract employment
- Track posting volume against macro hiring trends

### Getting Started

#### Simple Keyword Search

The fastest way to get started — one keyword, sensible defaults:

```json
{
    "searchQueries": ["python developer"],
    "maxResultsPerQuery": 100
}
```

#### Filtered Search — Recent Remote Roles

Narrow down to fresh, remote, easy-apply jobs in a specific market:

```json
{
    "searchQueries": ["data engineer", "machine learning engineer"],
    "location": "Austin, TX",
    "radiusMiles": 50,
    "postedWithinDays": "SEVEN",
    "employmentType": "FULLTIME",
    "remoteOnly": true,
    "easyApply": true,
    "maxResultsPerQuery": 200
}
```

#### Visa-Sponsorship Search

Surface only roles whose employers are willing to sponsor a work visa:

```json
{
    "searchQueries": ["software engineer", "backend engineer"],
    "location": "New York, NY",
    "willingToSponsor": true,
    "postedWithinDays": "THREE",
    "maxResultsPerQuery": 150
}
```

#### Direct Dice URL + Keyword Combo

Already have a search tuned on the Dice website? Paste the URL alongside your own keywords for a mixed batch:

```json
{
    "searchQueries": ["DevOps engineer"],
    "startUrls": [
        "https://www.dice.com/jobs?q=site+reliability+engineer&location=Seattle%2C+WA&filters.employmentType=CONTRACTS&filters.easyApply=true"
    ],
    "maxResultsPerQuery": 250
}
```

### Input Reference

#### Search

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `searchQueries` | string\[] | `["python developer"]` | Job titles or keywords to search for, such as `"python developer"` or `"data scientist"`. Each keyword runs a separate search. |
| `location` | string | `""` | Where to search for jobs. Enter a city, state, ZIP code, or `"Remote"`. Example: `"Austin, TX"`. Dice is US-only — locations outside the US fall back to nationwide results. |
| `radiusMiles` | integer | `30` | How far from the location to search, in miles (1-100). Ignored when location is empty. |
| `startUrls` | string\[] | `[]` | Paste full Dice search result URLs (e.g. `https://www.dice.com/jobs?q=...`) to scrape them directly. Useful when you already have a search dialed in on the Dice website. |

#### Filters & Limits

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `maxResultsPerQuery` | integer | `100` | Maximum number of job listings to collect per search keyword (1-500). 500 is the most this scraper collects from any one search. Use a tighter location or filters to reach more unique jobs. |
| `postedWithinDays` | string | `""` (Any time) | Only show jobs posted within this time period. Options: `"Any time"`, `"Last 24 hours"` (`ONE`), `"Last 3 days"` (`THREE`), `"Last 7 days"` (`SEVEN`). |
| `employmentType` | string | `""` (Any) | Filter by job type. Pick one or leave on `"Any"` for all types. Options: `"Any"`, `"Full-time"` (`FULLTIME`), `"Part-time"` (`PARTTIME`), `"Contract"` (`CONTRACTS`), `"Third-party"` (`THIRD_PARTY`). |
| `remoteOnly` | boolean | `false` | Only show jobs marked remote / work-from-home. |
| `easyApply` | boolean | `false` | Only show jobs that support Dice's easy-apply flow. |
| `willingToSponsor` | boolean | `false` | Only show jobs whose employer is willing to sponsor work visas. |

#### Advanced

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `fetchDescription` | boolean | `true` | Collect the full job description from each listing's detail page. Leave on for the most complete data. Turn it off to make runs about 3x faster, but `description`, `descriptionHtml` and `skills` come back empty, and `isExpired` can no longer tell you whether a posting is still open. Either way, postings Dice has already closed are still returned and still count toward your result total. |

### Output

Each record is one job posting with the full set of structured fields:

```json
{
    "jobId": "5b2d4f7c-9a3e-4d12-b7e8-1f0c2a9b8d54",
    "title": "Senior Python Developer",
    "company": "Acme Cloud Systems",
    "companyUrl": "https://www.dice.com/company-profile/97aa1566-053c-49e9-be3c-1ee6499511b5",
    "companyLogoUrl": "https://d3qscgr6xsioh.cloudfront.net/jLZGbw1aTAehDYuxFRDm_transformed.png?format=webp",
    "location": "Austin, Texas, USA",
    "postedDate": "2026-07-22T00:02:43Z",
    "modifiedDate": "2026-08-14T12:07:18Z",
    "salary": "$140,000 - $170,000 per year",
    "salaryMin": 140000,
    "salaryMax": 170000,
    "salaryCurrency": "USD",
    "salaryPeriod": "year",
    "employmentType": "Full-time",
    "employmentTypes": ["Full-time"],
    "isRemote": false,
    "workFromHomeAvailability": "No",
    "workplaceTypes": ["On-Site"],
    "easyApply": true,
    "employerType": "Direct Hire",
    "summary": "Build and scale data pipelines for a fast-growing fintech...",
    "description": "We're looking for a Senior Python Developer to join our platform team...",
    "descriptionHtml": "<p>We're looking for a Senior Python Developer...</p>",
    "skills": ["Python", "AWS", "Kubernetes", "PostgreSQL"],
    "isExpired": false,
    "jobUrl": "https://www.dice.com/job-detail/5b2d4f7c-9a3e-4d12-b7e8-1f0c2a9b8d54",
    "searchQuery": "python developer",
    "searchLocation": "Austin, TX",
    "scrapedAt": "2026-08-14T19:59:02Z"
}
```

A fully remote posting comes back in the same shape with `"location": "Remote"`, `"isRemote": true`, `"workFromHomeAvailability": "Yes"` and `"workplaceTypes": ["Remote"]`.

#### Job & Employer

| Field | Type | Description |
|-------|------|-------------|
| `jobId` | string | Dice's internal job identifier (GUID). |
| `title` | string | Job title, exactly as the employer wrote it. |
| `company` | string | Employer name. |
| `companyUrl` | string | Link to the employer's own Dice company profile page. Empty on the small share of rows where Dice publishes no profile for that employer. |
| `companyLogoUrl` | string | Employer logo image URL. |
| `employerType` | string | null | How Dice classifies the poster: `"Direct Hire"`, `"Recruiter"`, or `"Other"`. |
| `jobUrl` | string | Public Dice detail URL for the job. |

#### Location & Workplace

| Field | Type | Description |
|-------|------|-------------|
| `location` | string | City, state and country as Dice lists them, e.g. `"Austin, Texas, USA"`. Fully remote postings carry no city on Dice, so these read `"Remote"`. |
| `isRemote` | boolean | `true` if the job is remote-eligible. |
| `workFromHomeAvailability` | string | Work-from-home availability: `"Yes"` (remote), `"Hybrid"`, or `"No"` (on-site). Always agrees with `isRemote` and `workplaceTypes`. |
| `workplaceTypes` | string\[] | Workplace tags such as `"Remote"`, `"On-Site"`, `"Hybrid"`. |

#### Compensation

| Field | Type | Description |
|-------|------|-------------|
| `salary` | string | Raw salary string exactly as shown on Dice, e.g. `"$120k"`, `"$60-80/hour"`, `"Depends on Experience"`. |
| `salaryMin` | number | null | Minimum compensation, when the format is clean enough to read with confidence. Always paired with a `salaryPeriod`. |
| `salaryMax` | number | null | Maximum compensation, on the same pay period as `salaryMin`. |
| `salaryCurrency` | string | null | ISO 4217 currency code, e.g. `"USD"`. |
| `salaryPeriod` | string | null | `"hour"`, `"day"`, `"week"`, `"month"`, or `"year"`. Never `null` when `salaryMin` has a value, so hourly contract rates always sort apart from annual salaries. |

#### Employment Type & Dates

| Field | Type | Description |
|-------|------|-------------|
| `employmentType` | string | Comma-joined employment types as Dice displays them, e.g. `"Full-time, Contract"`. |
| `employmentTypes` | string\[] | The same data pre-split into an array for easier filtering. |
| `easyApply` | boolean | Whether the job supports Dice's easy-apply flow. |
| `postedDate` | string | ISO 8601 timestamp of when the posting was first listed. |
| `modifiedDate` | string | ISO 8601 timestamp of the last time the posting was updated. |

#### Description & Skills

| Field | Type | Description |
|-------|------|-------------|
| `summary` | string | Short summary as shown on the search-results card. |
| `description` | string | Full job description with HTML stripped, ideal for plain-text indexing or LLM input. |
| `descriptionHtml` | string | Full description with the original HTML preserved. |
| `skills` | string\[] | The skill tags the employer attached to the posting, e.g. `["Python", "Kubernetes", "Terraform"]`. Arrives with the description, so leave `fetchDescription` on. Empty `[]` when the employer tagged none, or when `fetchDescription` is off. |
| `isExpired` | boolean | `true` when the employer has closed the posting. Dice keeps closed jobs in its search results, so a small share of every run is no longer open — between 0% and 1.3% of rows across our test runs. The full description is still collected, so you keep the row for market analysis and can filter it out for applications, and it counts toward your result total like any other row. Shown in the default output table. Only determined when `fetchDescription` is on; with it off every row reads `false`. |

#### Run Provenance

| Field | Type | Description |
|-------|------|-------------|
| `searchQuery` | string | The keyword that surfaced this row. |
| `searchLocation` | string | The location used for the search. |
| `scrapedAt` | string | ISO 8601 timestamp of when the record was captured. |

### Tips for Best Results

- **Use specific keywords** — `"senior react developer"` returns far cleaner results than `"developer"`, because Dice ranks broad terms loosely. The keyword also drives how dense the `skills` column comes back: a specific role phrase like `"business development manager"` carries employer tags on around 98% of matches, while a broad phrase like `"security clearance"` thins out the deeper it goes and can land nearer 45%. Tighten the keyword when you need those tags dense, and leave `fetchDescription` on, since the tags arrive with the description.
- **Split broad searches instead of raising the cap** — every single search stops at 500 jobs no matter how many matches exist. Splitting a broad query into narrower ones by city, role or seniority, then running them as one batch, reaches far more unique jobs than one wide query ever will.
- **Batch related titles in one run** — put several variants in `searchQueries` (e.g. `["backend engineer", "platform engineer", "infrastructure engineer"]`) and duplicates are removed across queries automatically, so you are never billed twice for the same posting. A run that finishes under your cap means the search genuinely ran out of unique jobs, and the final message says so explicitly.
- **Set `postedWithinDays: "ONE"` for fresh listings** — ideal for daily candidate-sourcing pipelines or new-job alerting.
- **Combine `remoteOnly` with a metro location** — Dice returns remote roles whose employers are headquartered in or hiring for that metro, which is what you want for time-zone or compliance-aware searches.
- **Check the `isExpired` column before a list goes to candidates** — Dice keeps closed postings in its search results, so a small share of every run is a job that no longer accepts applications: 0% to 1.3% of rows across our test runs. Those rows still arrive with the full description, they show up flagged in the default output table, and they count toward your result total like every other row. Keep them for market analysis, drop them for outreach.
- **Group by `salaryPeriod` before averaging anything** — Dice mixes hourly contract rates and annual salaries in one column, and the mix swings hard between searches. `salaryPeriod` is always filled whenever `salaryMin` is, so grouping on it is safe. Free-text values like `"Depends on Experience"` leave the parsed fields `null` while the raw `salary` string is always preserved.

### Pricing

**From $0.80 per 1,000 results** — one flat rate per job returned, whatever filters you use. No compute or time-based charges: you pay per result, plus a small fixed start fee each time a run begins. Bronze, Silver, and Gold subscribers pay progressively less, and the table below shows the total cost at each discount tier.

| Results | No discount | Bronze | Silver | Gold |
|---------|-------------|--------|--------|------|
| 100 | $0.096 | $0.091 | $0.085 | $0.080 |
| 1,000 | $0.96 | $0.91 | $0.85 | $0.80 |
| 10,000 | $9.60 | $9.10 | $8.50 | $8.00 |
| 100,000 | $96.00 | $91.00 | $85.00 | $80.00 |

A "result" is one job row in your dataset, including the small share of postings Dice has already closed — those arrive flagged as expired so you can filter them out. Standard Apify platform fees apply on top. No monthly rental, no tiered plans.

### Integrations

Export data in JSON, CSV, Excel, or XML. Connect to 1,500+ apps via:

- **Zapier** / **Make** / **n8n** — Workflow automation
- **Google Sheets** — Direct spreadsheet export
- **Slack** / **Email** — Notifications on new results
- **Webhooks** — Get notified when a run completes
- **Apify API** — Full programmatic access

### Legal & Ethical Use

This actor is designed for legitimate recruiting, market research, lead generation, and labor-market analysis. Only public job listings are collected — no private employer dashboards, applicant data, or personal contact details. Users are responsible for complying with applicable laws and Dice's Terms of Service. Do not redistribute scraped listings as a substitute for Dice's own product, and do not use collected data for spam, harassment, candidate impersonation, or any unlawful purpose.

# Actor input Schema

## `searchQueries` (type: `array`):

Job titles or keywords to search for, such as 'python developer' or 'data scientist'. Each keyword runs a separate search. Up to 50 keywords per run.

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

Where to search for jobs. Enter a city, state, ZIP code, or 'Remote'. Example: 'Austin, TX'. Dice is US-only — locations outside the US fall back to nationwide results.

## `radiusMiles` (type: `integer`):

How far from the location to search, in miles. Ignored when location is empty.

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

Paste full Dice search result URLs (e.g., https://www.dice.com/jobs?q=...) to scrape them directly. Useful when you already have a search dialed in on the Dice website. Up to 50 URLs per run.

## `maxResultsPerQuery` (type: `integer`):

Maximum number of job listings to collect per search keyword. 500 is the most this scraper will collect from any one search. Use a tighter location or filters to reach more unique jobs. Note: Dice repeats jobs across pages and re-lists the same role more than once. We keep collecting past those repeats until your cap is met, so a lower count means the search itself has no more unique jobs to give.

## `postedWithinDays` (type: `string`):

Only show jobs posted within this time period.

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

Filter by job type. Pick one or leave on 'Any' for all types.

## `remoteOnly` (type: `boolean`):

Only show jobs marked remote / work-from-home.

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

Only show jobs that support Dice's easy-apply flow.

## `willingToSponsor` (type: `boolean`):

Only show jobs whose employer is willing to sponsor work visas.

## `fetchDescription` (type: `boolean`):

Fetch the full job description from each listing's detail page. Leave on for the most complete data. Turn off to make runs about 3x faster — but the description, descriptionHtml, and skills fields will be empty, and isExpired can no longer tell you whether a posting is still open. Either way, Dice keeps closed postings in its search results, so a small share of every run is a job that no longer accepts applications; those rows are returned with the rest and count toward your results.

## Actor input object example

```json
{
  "searchQueries": [
    "python developer"
  ],
  "radiusMiles": 30,
  "startUrls": [],
  "maxResultsPerQuery": 100,
  "postedWithinDays": "",
  "employmentType": "",
  "remoteOnly": false,
  "easyApply": false,
  "willingToSponsor": false,
  "fetchDescription": true
}
```

# Actor output Schema

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

Table of scraped job listings with key fields, including an expired flag marking postings Dice still lists but no longer accepts applications for.

## `detail` (type: `string`):

Complete job data including descriptions, skills, parsed salary fields, and an expired flag marking postings Dice still lists but no longer accepts applications for.

# 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 = {
    "searchQueries": [
        "python developer"
    ],
    "location": "",
    "radiusMiles": 30,
    "startUrls": [],
    "maxResultsPerQuery": 100,
    "postedWithinDays": "",
    "employmentType": "",
    "remoteOnly": false,
    "easyApply": false,
    "willingToSponsor": false,
    "fetchDescription": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("solidcode/dice-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 = {
    "searchQueries": ["python developer"],
    "location": "",
    "radiusMiles": 30,
    "startUrls": [],
    "maxResultsPerQuery": 100,
    "postedWithinDays": "",
    "employmentType": "",
    "remoteOnly": False,
    "easyApply": False,
    "willingToSponsor": False,
    "fetchDescription": True,
}

# Run the Actor and wait for it to finish
run = client.actor("solidcode/dice-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 '{
  "searchQueries": [
    "python developer"
  ],
  "location": "",
  "radiusMiles": 30,
  "startUrls": [],
  "maxResultsPerQuery": 100,
  "postedWithinDays": "",
  "employmentType": "",
  "remoteOnly": false,
  "easyApply": false,
  "willingToSponsor": false,
  "fetchDescription": true
}' |
apify call solidcode/dice-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,solidcode/dice-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/OU9FGIiywIVyDbcVp/builds/fI5cdIL4tevyQyVOV/openapi.json
