# Dice Jobs Scraper | $1.99 / 1k | (`glasswing/dice-jobs-scraper`) Actor

Scrape US tech jobs from Dice by keyword, location, remote flag or date. Title, company, city, salary parsed to min and max, employment type, skills, sponsorship flag and apply link. Export to CSV, JSON or Excel.

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

## Pricing

from $1.99 / 1,000 job postings

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

### What does Dice Jobs Scraper do?

Get US tech job postings as clean, analysis-ready rows: title, company, city and state, remote flag, the pay range parsed into `salaryMin` and `salaryMax`, employment type, posted date and a direct apply link. It is built for recruiters, job boards and compensation analysts who need Dice.com listings in bulk instead of one browser tab at a time.

Give it a Dice search URL - or just a keyword and a location - and **scrape Dice jobs** into JSON, CSV or Excel, or read them straight from the Apify API. It works as a practical **Dice.com API alternative** and a **US tech job listings API** when you have no documented feed to build on: no headless browser, no residential proxies, no scraper to maintain. The default 20-job run finished in **2.8 seconds** on the Apify platform.

It reads only pages and endpoints that Dice.com serves publicly to any visitor. It does **not** log in, does not solve challenges and does not touch candidate profiles or resumes. There are no recruiter, email or phone-number columns, and if an employer pasted an email address or a phone number into the posting text, it is replaced with `[email removed]` / `[phone removed]` before the row is saved.

### Use cases for this Dice scraper

- **Recruiting or staffing agency building a client pipeline.** Track every new Python, DevOps or Salesforce opening in a metro area, sort by `postedDate`, and reach the hiring company in the first 48 hours - `employerType` tells you whether you are looking at a direct hire or another agency's listing.
- **Compensation analyst tracking salary trends.** `salaryMin`, `salaryMax`, `salaryCurrency` and `salaryPeriod` are parsed out of Dice's free-text pay label, so you can build hourly-rate and annual-band datasets split by `city`, `isRemote` and contract versus full-time.
- **Job board or aggregator seeding listings.** Keep a US tech feed fresh with title, company, location, salary range, employment type and a direct `jobUrl`, plus `summary` on every row and the full `description` when you crawl job pages.
- **Sales team finding companies that are hiring.** A company posting for Snowflake or Kubernetes engineers is buying that stack. Filter by `skills` and `company`, then push the accounts into your CRM as fresh hiring-intent signals.
- **Talent sourcing and market research.** Measure demand for a skill over time, or compare remote versus on-site posting volumes by state using `workplaceTypes` and `state`.
- **Immigration and relocation services.** `willingToSponsor` flags the employers that state they sponsor visas, which is a hard filter you cannot get from a generic aggregator export.

### What data you get from every Dice job posting

One row per job posting. Every column below exists in the dataset schema; the **Overview** table view shows `title`, `company`, `location`, `isRemote`, `employmentType`, `salary`, `postedDate`, `jobUrl`, `status`, `error` and `scrapedAt`.

**Row status and provenance**

| Field | Type | Description |
|---|---|---|
| `url` | string | Source URL the row came from (the job's Dice page for `ok` rows). |
| `status` | string | `ok`, `not_found` or `error` (see the table below). |
| `error` | string | Reason when `status` is not `ok`. Absent on `ok` rows. |
| `scrapedAt` | string | ISO 8601 time of extraction. |

**Job identity and links**

| Field | Type | Description |
|---|---|---|
| `jobId` | string | Dice's internal job id, stable for the life of the posting. |
| `jobGuid` | string | Dice GUID, the last path segment of the job URL. |
| `title` | string | Job title as published by the employer. |
| `jobUrl` | string | Public Dice job page for the posting. |

**Company**

| Field | Type | Description |
|---|---|---|
| `company` | string | Hiring company or staffing agency name. |
| `companyUrl` | string | Dice company page of the hiring company. |
| `companyLogo` | string | Company logo image URL. |
| `employerType` | string | `Direct Hire`, `Recruiter` or `Other`. |

**Location and workplace**

| Field | Type | Description |
|---|---|---|
| `location` | string | Location as Dice displays it, e.g. `Jersey City, New Jersey, USA`. |
| `city` | string | City part of the location. |
| `state` | string | State part of the location. |
| `country` | string | Country part of the location (Dice is a US board). |
| `isRemote` | boolean | True when Dice flags the posting as remote. |
| `workplaceTypes` | array | Workplace types Dice lists, e.g. `["Remote"]`, `["On-Site", "Hybrid"]`. |

**Pay**

| Field | Type | Description |
|---|---|---|
| `salary` | string | Salary text exactly as Dice publishes it, e.g. `$160,000 - $190,000`. |
| `salaryMin` | number | Lower bound parsed out of `salary`. |
| `salaryMax` | number | Upper bound parsed out of `salary`. |
| `salaryCurrency` | string | ISO 4217 code parsed out of `salary`, e.g. `USD`. |
| `salaryPeriod` | string | Usually `hourly` or `yearly`; also `daily`, `weekly` or `monthly` when the label says so. |

**Role details**

| Field | Type | Description |
|---|---|---|
| `employmentType` | string | `Full-time`, `Part-time`, `Contract`, `Third Party` or a combination. |
| `skills` | array | Skill tags Dice lists on the job page (job detail URLs only). |
| `easyApply` | boolean | True when the posting supports Dice's one-click apply. |
| `willingToSponsor` | boolean | True when the employer states it is willing to sponsor a visa. |

**Dates**

| Field | Type | Description |
|---|---|---|
| `postedDate` | string | ISO 8601 date the job was first posted. |
| `modifiedDate` | string | ISO 8601 date the posting was last updated. |

**Posting text**

| Field | Type | Description |
|---|---|---|
| `summary` | string | Description excerpt returned with every search result (contact details redacted). |
| `description` | string | Full description as plain text (job detail URLs only, contact details redacted). |

A field is simply omitted when Dice does not publish it. That is honest, not a guess: Dice leaves `salary` off roughly one posting in five, and leaves the location off many remote postings (there `isRemote` and `workplaceTypes` carry the information).

#### Result status (tri-state output)

| `status` | Meaning | Billed? |
|---|---|---|
| `ok` | The job was found and extracted. | Yes |
| `not_found` | Dice answered, but the search has no matches or the job page no longer exists (Dice serves those with HTTP 200 and a "Job Not Found" page). | No |
| `error` | Dice could not be read after retries (network error, block, or a format change). `error` says why. | No |

### How to scrape Dice.com with this Actor

1. Open the Actor in Apify Console and click **Try for free**.
2. Run a search on dice.com, copy the URL from the address bar and paste it into **Dice search URLs** - or leave that empty and type a **Search keyword** plus a **Location**.
3. Optionally tick **Remote jobs only** or set **Posted within (days)**.
4. Set **Maximum results** (start with the default 20 to see the output).
5. Click **Start**. The default input takes about 3 seconds; 1,000 jobs take under a minute.
6. Open the **Output** tab or **Export** the dataset as JSON, CSV, Excel, XML or HTML.

To automate it, use the **API** tab (Node.js, Python, curl examples) or add a **Schedule**.

### Input

Every field is optional - the prefilled values already produce a complete run. See the **Input** tab for the full schema.

| Field | Type | Default | When to change it |
|---|---|---|---|
| `startUrls` | array of strings | `["https://www.dice.com/jobs?q=python%20developer&location=Remote"]` | Paste the exact searches you want, one per line: search pages (`https://www.dice.com/jobs?q=...`) or single job pages (`https://www.dice.com/job-detail/<guid>`). Job pages are the only way to get `description` and `skills`. |
| `query` | string | empty | Use it instead of `startUrls` to describe the search in plain words, e.g. `data engineer`. Ignored when `startUrls` is set. |
| `location` | string | empty | Add a place to narrow the search: `New York, NY, USA`, `Austin, TX, USA` or `Remote`. Dice searches within about 30 miles of it. Ignored when `startUrls` is set. |
| `remoteOnly` | boolean | `false` | Turn it on to keep only postings Dice flags as remote. |
| `postedWithinDays` | integer | empty (no date filter) | Set `1` on a daily schedule, or `7` for a weekly sweep, so you only pay for fresh postings. Dice offers 1, 3 and 7-day buckets. |
| `maxItems` | integer | `20` | Raise it for production pulls, lower it while testing. This is your main spending cap; the Actor asks Dice for exactly as many jobs per request as the run may still keep, up to 100. |
| `proxyConfiguration` | object | Apify Proxy off | Leave it off - the Actor is HTTP-only and works from datacenter IPs. Enable the Apify Proxy datacenter group only if you see `error` rows mentioning blocking. |

Example input (exactly the prefilled default):

```json
{
    "startUrls": ["https://www.dice.com/jobs?q=python%20developer&location=Remote"],
    "maxItems": 20
}
```

Or without a URL:

```json
{
    "query": "data engineer",
    "location": "New York, NY, USA",
    "remoteOnly": true,
    "postedWithinDays": 7,
    "maxItems": 100
}
```

### Output

You can download the dataset in various formats such as JSON, HTML, CSV or Excel. A real row from the default run (2026-09-08, `summary` shortened here):

```json
[
    {
        "url": "https://www.dice.com/job-detail/f17ebf2b-fce5-49fa-acff-6b484c956ca9",
        "status": "ok",
        "scrapedAt": "2026-09-08T11:49:05.166Z",
        "jobId": "9bb1bcab0b82178a714ea0d1bb3bc7b4",
        "jobGuid": "f17ebf2b-fce5-49fa-acff-6b484c956ca9",
        "title": "Python Developer",
        "company": "Apex Systems",
        "companyUrl": "https://www.dice.com/company/apexsan",
        "companyLogo": "https://d3qscgr6xsioh.cloudfront.net/KXuMec4DRi2CdkvuPN96_c1c030ea-0493-453b-bd59-1fbd16b6b3f0.png?format=webp",
        "location": "Jersey City, New Jersey, USA",
        "city": "Jersey City",
        "state": "New Jersey",
        "country": "USA",
        "isRemote": false,
        "workplaceTypes": ["On-Site"],
        "employmentType": "Full-time",
        "employerType": "Recruiter",
        "salary": "$72 - $73 per hour",
        "salaryMin": 72,
        "salaryMax": 73,
        "salaryCurrency": "USD",
        "salaryPeriod": "hourly",
        "postedDate": "2026-09-03T09:24:31.000Z",
        "modifiedDate": "2026-09-08T10:51:15.000Z",
        "jobUrl": "https://www.dice.com/job-detail/f17ebf2b-fce5-49fa-acff-6b484c956ca9",
        "summary": "Job#: 3049528 Job Description: Python Developer Location: Jersey City, New Jersey (Hybrid) Duration: 12 months Role Overview ...",
        "easyApply": true,
        "willingToSponsor": false
    },
    {
        "url": "https://www.dice.com/job-detail/00000000-0000-0000-0000-000000000000",
        "status": "not_found",
        "error": "No results on this page",
        "scrapedAt": "2026-09-08T11:49:06.002Z"
    }
]
```

Rows that come from a `https://www.dice.com/job-detail/<guid>` start URL additionally carry `skills` and the full `description`.

### How much does it cost to scrape Dice.com?

This Actor uses **pay-per-event** pricing:

| Event | Price | Charged when |
|---|---|---|
| Actor start | $0.005 per run | Once when the run starts. The platform charges one event per GB of memory and the Actor runs on 1 GB, so this is one event. |
| Job posting | $0.00199 per job | One job posting with `status: ok` was saved to the dataset. |

**1,000 job postings cost about $2.00** ($0.005 to start plus 1,000 x $0.00199). You are never charged for a row with `status` `not_found` or `error`, and never for a duplicate: a URL that appears twice in your input, or a next-page link the crawler has already followed, is fetched once per run. The free Apify plan's $5 of monthly credit covers about 2,500 jobs in a single run.

You can cap spending per run with **Maximum results** and with the run's **Max total charge** option; the Actor stops gracefully when either limit is reached and keeps everything it has already saved.

### How it compares

This Actor is deliberately narrow and fast. It reads the same public job-search endpoint that dice.com's own site calls, which is why one request returns up to 100 jobs, a run costs seconds rather than minutes, and no browser or proxy is needed. If you want deep US tech coverage with parsed salaries, skill tags, a sponsorship flag and a tri-state row you can trust inside an automated pipeline, this is a good fit.

It is not for you if you need non-US roles or non-tech roles; if you need candidate profiles, resumes or anything inside a Dice account; if you need a vendor-backed feed with a stability guarantee; or if you want one Actor that also covers other job boards. It reads a single public source, and reports honestly when that source changes.

### Integrations, exports and API access

Results export to **CSV, JSON, Excel**, XML and HTML from the **Output** tab or the dataset API. From there, Apify integrations and webhooks push the same rows into **Google Sheets, Airtable or a CRM**, plus Slack, Amazon S3 or your own endpoint - directly, or through Zapier, Make and n8n. Add a **Schedule** and today's new postings land in your sheet every morning.

The Actor can also be called from the **Apify API** (Node.js, Python and curl snippets are on the **API** tab), from the **Apify MCP server**, or by any AI agent that can call a tool: the inputs are plain strings and numbers, and every row carries `status` and `error`, so an agent can tell an empty search apart from a failure without parsing prose.

### Tips

- Keep `maxItems` small while testing, then raise it. The Actor asks Dice for exactly as many jobs per request as the run may keep, up to 100.
- Pass several `startUrls` in one run instead of many single-URL runs; you pay the start fee once.
- To cover a large market, split it into several narrower search URLs (per city, per keyword) rather than one very deep search.
- If you see `error` rows mentioning blocking, enable Apify Proxy (datacenter) in **Proxy configuration**.

### Limitations

- **Dice is a US tech job board.** Expect software, data, IT, security and engineering roles in the United States; there is no coverage of other countries or of non-tech roles.
- **Undocumented data source.** The Actor reads the same public job-search endpoint that dice.com's own website calls. Dice can change or retire that endpoint at any time; when that happens rows come back as `error` and the Actor is updated (report it in the **Issues** tab).
- **Date filter granularity.** Dice only offers "today", "last 3 days" and "last 7 days"; other values of `postedWithinDays` are rounded up to the next bucket, and anything above 7 means no date filter.
- **Full description and skills need a job URL.** Search results carry a `summary` excerpt only. Put `https://www.dice.com/job-detail/<guid>` URLs in **Dice search URLs** to get `description` and `skills`, at one HTTP request per job.
- **Depth per search URL.** One search URL is followed for at most 50 pages (up to 5,000 jobs). Use several narrower searches beyond that.
- **No login and no personal data.** Postings behind a Dice account, candidate profiles, resumes and recruiter contact details are out of scope by design.
- Results reflect what Dice published at the time of the run.

### FAQ

**Does this Actor need an API key or a Dice account?** No. You only need an Apify account. The Actor sends the same public front-end key that dice.com's website ships in its own JavaScript to every visitor, and refreshes it from those public files if Dice changes it. There is no login step.

**How do I get more results?** Raise `maxItems` first - it is the only limit that stops a run early. Past about 5,000 jobs per search URL, split the market into several narrower searches (per city, per keyword, per employment type) and pass them all as `startUrls` in the same run.

**How often does the data change?** Constantly. US tech postings are added, updated and closed through the day, and `modifiedDate` moves whenever an employer edits a listing. Schedule a daily run with `postedWithinDays: 1` if you want a clean "new today" feed.

**What happens if Dice changes its site?** Rows come back with `status: error` and a reason instead of silently wrong data, so your pipeline can alert on it. Report it in the **Issues** tab with the run ID; you are not billed for `error` rows in the meantime.

**Is it legal to scrape Dice.com?** Scraping publicly available data is generally legal, but you are responsible for how you use the output. Read the legal notice below and Dice's terms of service, and do not collect personal data without a legitimate reason.

**Why is `location` empty on some rows?** Dice frequently leaves the location off fully remote postings. Those rows still have `isRemote: true` and `workplaceTypes`.

**Why did I get fewer rows than `maxItems`?** The search had fewer matches, or the run hit your **Max total charge** limit. Check the run log for "Stopping gracefully".

**Can I use this Actor from an AI agent or MCP client?** Yes. Every row is self-describing (`status` plus `error`), inputs are plain strings, and results can be fetched via the dataset API or the Apify MCP server.

### Legal and data-protection notice

This Actor extracts only data that Dice.com publishes publicly; it does not extract private user data such as recruiter names, email addresses, phone numbers, gender or precise location (contact details found in free-text job descriptions are redacted before the row is saved), and it does not log in or work around access controls. However, your results could still contain personal data. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you are unsure whether your reason is legitimate, consult your lawyers. You are responsible for complying with Dice.com's terms of service and applicable law when using the extracted data.

This Actor is an independent tool and is not affiliated with, endorsed by or sponsored by Dice.com, DHI Group, Inc. or their owners. All trademarks belong to their respective owners.

# Actor input Schema

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

Dice.com URLs to scrape, one per line. Accepts search pages (https://www.dice.com/jobs?q=python+developer\&location=Remote) and single job pages (https://www.dice.com/job-detail/<guid>). Search URLs are answered from Dice's own job-search endpoint; job pages add the full description and skill tags. Leave empty to use the keyword fields instead.

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

Alternative to Start URLs: a Dice search term such as `python developer`, `data engineer` or `salesforce administrator`. Ignored when Start URLs are given.

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

City, state or `Remote`, exactly as you would type it into Dice's location box, e.g. `New York, NY, USA`, `Austin, TX, USA` or `Remote`. Dice searches within about 30 miles of the place. Ignored when Start URLs are given.

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

Keep only postings that Dice flags as remote.

## `postedWithinDays` (type: `integer`):

Only jobs posted in the last N days. Dice offers three buckets: 1 (today), 3 and 7 days; other values are rounded up to the next bucket. Leave empty for no date filter.

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

Stop after this many records have been saved to the dataset. Each saved record with status `ok` is one billable result. Keep it small for test runs.

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

Optional. The Actor is HTTP-only and works from datacenter IPs. Enable Apify Proxy (datacenter group is the default) only if Dice blocks direct requests; residential proxies are not needed and not recommended for this Actor.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.dice.com/jobs?q=python%20developer&location=Remote"
  ],
  "query": "python developer",
  "location": "Remote",
  "remoteOnly": false,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# 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 = {
    "startUrls": [
        "https://www.dice.com/jobs?q=python%20developer&location=Remote"
    ],
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("glasswing/dice-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 = {
    "startUrls": ["https://www.dice.com/jobs?q=python%20developer&location=Remote"],
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("glasswing/dice-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 '{
  "startUrls": [
    "https://www.dice.com/jobs?q=python%20developer&location=Remote"
  ],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call glasswing/dice-jobs-scraper --silent --output-dataset

```

## MCP server setup

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