# Dice Scraper — Tech Jobs, Salaries & Companies (`tortuga/dice-scraper`) Actor

Scrape Dice.com tech jobs by keyword, location, filters or URL: title, company, location, remote/hybrid, employment type, salary range, posted date; optional full description, skills, recruiter.

- **URL**: https://apify.com/tortuga/dice-scraper.md
- **Developed by:** [Trevor Ortega](https://apify.com/tortuga) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.60 / 1,000 job scrapeds

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?

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

## Dice Scraper — Tech Jobs, Salaries & Companies

Scrape job ads from **Dice** (dice.com), the main US job board for software, IT and data roles, by keyword and
location, with Dice's own filters (posted date, employment type, remote / hybrid / on-site, employer type, Easy Apply,
willing to sponsor, company, radius), or from any Dice search URL. For every job you get the title, company with logo
and Dice company profile link, location split into city / state, workplace type, employment type (full-time,
contract, third party...), whether the employer is a direct hire or a recruiter, the pay text **and** a parsed
min / max / period, posted and updated dates, Easy Apply and visa sponsorship flags and the summary. Optionally it
also opens each job page for the **full description**, the **skills list**, contract types (W2, Corp-to-Corp,
Independent) and term, travel, Dice position id and the **recruiter** shown on the page.

No Dice account, no cookies, no browser. Fast: 100 jobs per request. Export to JSON, CSV, Excel or use the API.

### What data does the Dice Scraper return?

| Field | Example | Notes |
|---|---|---|
| `jobId`, `url` | `d2f2fe21-63b1-43fa-ad08-1bf12d65364f`, `https://www.dice.com/job-detail/d2f2fe21-...` | `legacyJobId` = Dice's older 32-character id |
| `title` | `Senior Python Developer` | |
| `company`, `companyId` | `Randstad Digital`, `cxsapwma1` | `companyId` is the "Dice Id" of the employer account |
| `companyProfileUrl`, `companyLogoUrl` | `https://www.dice.com/company-profile/ee3855f3-...` | when the company has a Dice profile / logo |
| `location`, `city`, `state`, `stateCode`, `country` | `Jersey City, New Jersey, USA`, `Jersey City`, `New Jersey`, `NJ`, `USA` | remote jobs without a place read `Remote` |
| `workplaceType`, `isRemote` | `Remote, On-Site`, `true` | Remote, Hybrid, On-Site (a job can have several) |
| `employmentType` | `Contract, Third Party` | Full-time, Part-time, Contract, Third Party |
| `employerType` | `Recruiter` | Direct Hire, Recruiter or Other |
| `salaryText` | `USD 156,750.00 - 215,000.00 per year` | exactly as the employer entered it; about 85% of jobs show something, about half a number |
| `salaryMin`, `salaryMax`, `salaryPeriod`, `salaryCurrency` | `156750`, `215000`, `year`, `USD` | parsed: hour, day, week, month, year; "DOE" / "Depends on Experience" give nulls |
| `postedAt`, `updatedAt` | `2026-09-28T21:04:03Z`, `2026-10-10T00:02:27Z` | Dice's "Today / 3d ago" label is based on `updatedAt` |
| `easyApply`, `willingToSponsor`, `isFeatured` | `true`, `false`, `false` | |
| `summary` | `Position will be a Senior Python Developer who ...` | first ~500 characters of the description |
| `searchKeyword`, `searchLocation`, `searchUrl`, `scrapedAt`, `detailsFetched` | | where and when the job was found |
| `description`, `descriptionHtml` | `Job Title: Python AI Developer ...` | with **Include full job description** |
| `skills` | `["Python", "Playwright", "API Automation"]` | the skills list the employer tagged, with details |
| `contractTypes`, `contractTerm` | `["Contract W2", "Contract Corp-To-Corp"]`, `Contract 30 Months` | contract jobs, with details |
| `travelRequirement`, `positionId`, `postalCode`, `validThrough` | `No Travel Required`, `9111034`, `11714`, `2026-11-09T22:43:31.000Z` | with details |
| `isExpired` | `false` | with details: `true` when Dice shows the ad as "no longer available" |
| `recruiterName`, `recruiterTitle`, `recruiterProfileUrl` | `Shubha P R`, `Recruiter`, `https://dice.com/recruiter-profile?id=...` | the "Contact the job poster" card, when the job page shows one |

### How to scrape Dice jobs by keyword and location

1. Enter one or more **Keywords** (job title, skill or company) and a **Location** such as `New York, NY`,
   `Austin, TX`, `California` or a ZIP code like `10001`. Leave the location empty for the whole US, or type `Remote`
   for remote jobs only.
2. Optionally set filters: radius, posted in the last day / 3 days / 7 days, employment type, workplace (remote,
   hybrid, on-site), employer type (direct hire / recruiter), Easy Apply only, willing to sponsor only, company,
   and sort by date.
3. Set **Max jobs** and run.

```json
{
  "keywords": ["data engineer", "python developer"],
  "location": "Austin, TX",
  "radius": 50,
  "postedDate": "SEVEN",
  "employmentTypes": ["CONTRACTS"],
  "workplaceTypes": ["Remote", "Hybrid"],
  "maxItems": 500
}
```

Like the Dice website, a city or state search also includes remote jobs from anywhere; turn off **Include remote jobs
in location searches** to get only jobs in or near the location.

You can also paste Dice URLs into **Start URLs**: search pages with any filters you set on the site (both
`https://www.dice.com/jobs?q=...` and `https://www.dice.com/jobs/q-python-l-new+york%2c+ny-jobs` style), and single
job pages, which are returned with full details:

```json
{
  "startUrls": [
    { "url": "https://www.dice.com/jobs?q=devops&location=Chicago,%20IL&filters.employmentType=CONTRACTS&filters.postedDate=THREE" },
    { "url": "https://www.dice.com/jobs/q-golang-jobs" },
    { "url": "https://www.dice.com/job-detail/d2f2fe21-63b1-43fa-ad08-1bf12d65364f" }
  ],
  "maxItems": 300
}
```

#### Output example

```json
{
  "jobId": "f17832e4-4867-4d77-9934-405dd52ab44c",
  "url": "https://www.dice.com/job-detail/f17832e4-4867-4d77-9934-405dd52ab44c",
  "title": "Data Engineer",
  "company": "Apex Systems",
  "companyProfileUrl": "https://www.dice.com/company-profile/a1d7df75-e170-5701-a217-dd7e780f4b48",
  "location": "Austin, Texas, USA",
  "city": "Austin",
  "state": "Texas",
  "stateCode": "TX",
  "workplaceType": "On-Site",
  "isRemote": false,
  "employmentType": "Full-time",
  "employerType": "Recruiter",
  "salaryText": "$100,000 - $130,000",
  "salaryMin": 100000,
  "salaryMax": 130000,
  "salaryPeriod": "year",
  "salaryCurrency": "USD",
  "postedAt": "2026-08-26T20:30:19Z",
  "updatedAt": "2026-10-09T20:23:44Z",
  "easyApply": true,
  "willingToSponsor": false,
  "detailsFetched": true,
  "description": "Job#: 3047926\n\nJob Description:\nData Engineer\n\nLocation: Austin, Texas (Onsite) ...",
  "skills": ["SQL", "Python", "Data Engineering", "Data Warehouse", "Data Modeling"],
  "positionId": "BHJOB2374_3047926",
  "postalCode": "73301",
  "validThrough": "2026-11-09T21:23:44.000Z"
}
```

### How many jobs can I get per search?

Dice serves at most **10,000 jobs for any one search** (positions beyond that are refused). With **Get more than
Dice's 10,000 results per search** (on by default) the actor splits a bigger search into narrower ones that together
cover it: by employer type, Easy Apply, remote / not remote, employment type and, for searches without a location,
US state; a slice that is still too big is read in both sort orders. Duplicates are removed. In tests, "java" across
the US (Dice: 12,541 matches) returned **12,494 distinct jobs** from 129 requests in 17 seconds, and every job in
California (Dice: 28,004 including remote) returned **26,352** from 373 requests in under a minute.

### Can I get the full job description, skills and recruiter?

Yes. Turn on **Include full job description**. For each job the actor opens the public job page and adds the full
description (plain text and HTML), the skills list, contract types (W2, Corp-to-Corp, Independent) and contract
term, travel requirement, the Dice position id, postal code, the date the ad expires, and the recruiter card
("Contact the job poster": name, title, Dice profile link) when the page shows one. It is one extra request per job.
Single job URLs in Start URLs always come with details. E-mail addresses and apply links that Dice only reveals in
its apply flow are not collected.

### Does it work without login? Is a proxy needed?

It works without any login or cookies. It uses the same public JSON search API the Dice website calls, and the
public job pages. Apify's datacenter proxy (the default) works; no residential proxy is needed.

### Monitor changes on a schedule

Turn on **Only new or changed items** to watch a search: each run remembers what earlier runs returned and outputs
only jobs that are new or whose title or pay text changed. Unchanged jobs are dropped before any job page is opened,
so they are not charged. **Max jobs** then sets how many jobs are checked per run; sort by date so the newest jobs land
in that window. Save the input as a task and add a Schedule in Apify (for example daily); give each watch its own
**Monitoring key** if several schedules use the same search. Every output item has `changeType` (`new` or
`changed`), and changed jobs have `previousValues` with the old values, e.g. `{"salaryText": "$60 - $65"}`.

### Pricing

Pay per job: **$0.0006 per job** ($0.60 per 1,000). With **Include full job description** (or for a job URL) each
job adds a **$0.0002 detail** event, so $0.80 per 1,000 jobs with descriptions, skills and recruiters. No start fee
and no subscription.

### Proxy note and cost

The actor runs on Apify's datacenter proxy by default. A search request returns up to 100 jobs and is about 0.15 MB;
a job page is about 0.25 MB. Measured platform usage (compute, storage) on top of the per-job price: about
**$0.005 per 1,000 jobs** without details and about $0.02 per 1,000 with details. Speed on the datacenter proxy is
about 20 jobs per second from search pages and 1-2 job pages per second with details; Dice also answers requests
without a proxy, which is about 4 times faster for job pages (switch the proxy off if you want that). Requests that
fail or come back blocked are retried automatically on a new IP.

### Is it legal to scrape Dice?

The actor reads only public job ads that anyone can open on Dice without an account: what employers and agencies
publish, company names and pay information. It does not log in and does not collect job seekers' data. Job pages
sometimes show the recruiter who posted the job (name, title, Dice profile link); that is part of the public page.
Contact e-mails and apply links that Dice reveals only in its apply flow are not collected. You are responsible for
using the data in line with Dice's terms and the privacy laws that apply to you (for example CCPA or GDPR when you
process personal data from ads).

# Actor input Schema

## `keywords` (type: `array`):

One search per keyword, e.g. "python developer", "data engineer", "java". Leave empty to list every job matching the location and filters.

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

Where, as you would type it on Dice: a city ("Austin, TX"), a state ("California"), or a ZIP code ("10001"). Leave empty for the whole US. "Remote" = remote jobs only.

## `radius` (type: `integer`):

Distance around a city or ZIP code. Dice's default is 30 miles; the site offers 10, 30, 50 and 75. Ignored for states and without a location.

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

Only jobs posted (or refreshed) within this period.

## `employmentTypes` (type: `array`):

Only these employment types. Several = any of them.

## `workplaceTypes` (type: `array`):

Only remote, hybrid or on-site jobs. Several = any of them.

## `employerTypes` (type: `array`):

Direct employers, recruiting agencies or other. Several = any of them.

## `easyApplyOnly` (type: `boolean`):

Only jobs you can apply to on Dice with Easy Apply.

## `willingToSponsorOnly` (type: `boolean`):

Only jobs whose employer is willing to sponsor a work visa.

## `companyName` (type: `string`):

Only jobs from this company, exactly as Dice shows the name (e.g. "Amazon Web Services, Inc.").

## `includeRemote` (type: `boolean`):

Dice adds remote jobs from anywhere to a city or state search (as on the site). Turn off to get only jobs in or near the location.

## `sortBy` (type: `string`):

Relevance (Dice's default) or newest first.

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

Optional: Dice search URLs with any filters set on the site, e.g. https://www.dice.com/jobs?q=python\&location=Austin,%20TX\&filters.employmentType=CONTRACTS, or single job URLs (https://www.dice.com/job-detail/<id>), which are returned with full details.

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

Stop after this many jobs in total (you pay per job saved).

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

Optional cap for each keyword / start URL, so one search does not use the whole Max jobs budget.

## `splitLargeSearches` (type: `boolean`):

Dice shows at most 10,000 jobs for any search. With this on, a bigger search is split by employer type, Easy Apply, remote, employment type and US state (and read in both sort orders when a slice is still too big), so you get far more of its jobs. Each extra page is one small request.

## `includeDetails` (type: `boolean`):

Open each job page for the full description (text and HTML), skills, contract types (W2, C2C...) and term, travel, Dice position id, postal code, expiry date and the recruiter shown on the page. One extra request and one 'detail' event per job.

## `onlyNewOrChanged` (type: `boolean`):

Remember what earlier runs of this search returned and output only new jobs or jobs whose title or pay text changed. Use with a Schedule; unchanged jobs are not charged. With this on, Max jobs is the number of jobs checked per run; sort by date to watch the newest jobs.

## `monitoringKey` (type: `string`):

Name for this watch, so several schedules on the same search stay separate; defaults to a key derived from the search input

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

Apify datacenter proxy (the default) works: Dice's search API and job pages do not block it. A page of 100 jobs is about 0.15 MB; a job page about 0.25 MB.

## Actor input object example

```json
{
  "keywords": [
    "python developer"
  ],
  "location": "New York, NY",
  "postedDate": "",
  "easyApplyOnly": false,
  "willingToSponsorOnly": false,
  "includeRemote": true,
  "sortBy": "relevance",
  "maxItems": 100,
  "splitLargeSearches": true,
  "includeDetails": false,
  "onlyNewOrChanged": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "keywords": [
        "python developer"
    ],
    "location": "New York, NY",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tortuga/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 = {
    "keywords": ["python developer"],
    "location": "New York, NY",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("tortuga/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 '{
  "keywords": [
    "python developer"
  ],
  "location": "New York, NY",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call tortuga/dice-scraper --silent --output-dataset

```

## MCP server setup

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