# Dice Tech Jobs Scraper (`scrapyx/dice-jobs-scraper`) Actor

Scrapes tech job listings from Dice.com, one of the largest US tech-specific job boards. Search by keyword and optional location; returns salary, location, employment/workplace type and a description snippet from a single search call, with an optional full-description detail pass.

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

## Pricing

from $0.35 / 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.
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?

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 (USA)

Tech job listings from **[Dice.com](https://www.dice.com)**, one of the largest
US tech-specific job boards (part of DHI Group). Search by keyword and optional
location; every job comes back with title, company, location, salary,
employment and workplace type, posting date and a description snippet — from a
single search call, with an optional pass for the full job description.

No API key, no login, HTTP only.

### Example input

```json
{
  "keywords": ["Python Developer", "DevOps Engineer"],
  "location": "Austin, TX",
  "includeJobDetails": false,
  "maxItems": 100
}
```

### What you get

Records share one dataset, told apart by `recordType`:

- **`JOB`** — one per listing. Carries the envelope plus `jobId`, `jobUrl`,
  `keywordQueried`, `locationQueried`, `searchPage`/`searchRank`, and the raw
  search entry under **`listing`** — passed through verbatim, so upstream's own
  field names are preserved:

  | field | example |
  | --- | --- |
  | `title` | `Python Developer` |
  | `companyName` | `The Avian Consulting LLC` |
  | `jobLocation` | `{ "city": "Hartford", "state": "Connecticut", "country": "USA" }` |
  | `salary` | `$60 - $70` (as Dice prints it — hourly or annual, sometimes a range) |
  | `employmentType` | `Full-time` |
  | `workplaceTypes` | `["On-Site"]` · also `isRemote`, `workFromHomeAvailability` |
  | `postedDate` / `modifiedDate` | ISO 8601 UTC |
  | `summary` | a description snippet |
  | `detailsPageUrl` · `guid` | the job's own Dice URL and id |
  | `companyLogoUrl` · `easyApply` · `employerType` | |

  With **`includeJobDetails`** on, `jobDetail` is filled from the job page's
  `JobPosting` structured data, which carries the **full HTML-formatted
  description** (the search snippet is only a teaser).

- **`SEARCH_SUMMARY`** — one per keyword: `totalResults` reported by Dice,
  `returnedCount`, `pagesFetched`, and `locationApplied` (see the location note).

- **`ERROR`** — one per keyword that failed, so **every keyword maps to at least
  one row**.

Every row carries `_input`, `_source`, `_scrapedAt`, `recordType`.

### Input

| Field | Meaning |
|---|---|
| `keywords` | **Required.** One full-text search per entry (`Python Developer`, `DevOps Engineer`). |
| `location` | Optional, applies to every keyword. Format as Dice shows it: `Austin, TX`, `New York, NY`. |
| `includeJobDetails` | Fetch each job's page for the full description. Off by default — it is one extra request per job. |
| `maxItems` | Stop a search after this many jobs (default 100; `0` = unlimited, still bounded by `maxPages`). |
| `maxPages` | Pagination-depth cap (default 20; 20 jobs per page). |
| `maxConcurrency` | Requests in flight at once (default 5). |
| `minRequestInterval` | Seconds between request starts (default 1). Dice showed no rate sensitivity in recon; kept small as a courtesy. |
| `proxyConfiguration` | Apify US residential by default. |

### Known limits — worth reading

- **US-focused.** Dice is a US tech board; a non-US `location` mostly returns
  little or nothing. That is the source, not a bug.
- **An unrecognised location is silently ignored** by Dice — the search runs
  nationwide instead of erroring. `locationApplied` on the summary row tells you
  whether the location actually bound, so you can tell "nationwide" apart from
  "filtered".
- **The `summary` field is a snippet, not the full posting.** Turn on
  `includeJobDetails` for the complete description (`jobDetail`).
- **`salary` is exactly what Dice prints** — sometimes hourly, sometimes annual,
  sometimes a range or blank. It is passed through as text, not normalised.
- **Roughly 900+ results per broad keyword.** Results thin out past the first
  pages; the actor stops when a page stops adding new jobs rather than paying for
  Dice re-serving the last page (which it does instead of erroring at the end).

### Method

Dice's `robots.txt` disallows the query-string search form (`/jobs?q=…`) that
its own search box uses, but allows the **path-based** search form its sitemap
publishes for SEO (`/jobs/q-{keyword}-jobs`). This actor uses only the allowed
path form. Search results are read from the page's Next.js RSC stream; the full
description on the detail pass comes from the `JobPosting` JSON-LD block. No WAF
or bot-mitigation gate was seen in recon — six TLS profiles answered 200 cold.

# Actor input Schema

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

Free-text keyword search (e.g. 'Python Developer', 'DevOps Engineer') -- one search per entry, each with its own SEARCH\_SUMMARY row. This is a genuine full-text search: a keyword with no matches is reported honestly with zero rows, not silently substituted.

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

Optional. Format as it appears on Dice ('Austin, TX', 'New York, NY'). Applies to every keyword in this run. An unrecognised location is silently ignored by Dice rather than erroring -- this actor detects that by comparing against a keyword-only baseline and reports it as locationApplied=false on the SEARCH\_SUMMARY row, rather than pretending the filter worked.

## `includeJobDetails` (type: `boolean`):

Also fetch each job's detail page for the full HTML-formatted description. Search results already carry a description snippet, salary, location, employment type and workplace type. Off by default -- one extra request per job.

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

Stop paginating a search after this many jobs. Set to 0 for unlimited (still bounded by Max pages).

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

Hard cap on pagination depth, independent of maxItems (20 jobs/page). Dice re-serves the same page past a real ceiling rather than erroring -- this actor stops on its own once a page carries zero NEW job ids, so this is a cost guard for large searches, not the only stop condition.

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

Upper bound on requests in flight at once, across searches and detail fetches. No bot-mitigation gate was observed for this target in recon, so this can be raised more freely than most actors in this portfolio.

## `minRequestInterval` (type: `integer`):

Paces request starts (not held inside a concurrency slot) rather than raw concurrency. Kept small by default as a courtesy -- no request-velocity sensitivity was observed for this target.

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

No WAF or bot-mitigation gate was observed for Dice.com in recon. Residential proxy pinned to the US is still the default, as this portfolio's standard baseline for a single-country public site.

## Actor input object example

```json
{
  "keywords": [
    "Python Developer"
  ],
  "location": "",
  "includeJobDetails": false,
  "maxItems": 100,
  "maxPages": 20,
  "maxConcurrency": 5,
  "minRequestInterval": 1,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

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

One row per scraped record. See the dataset's default view for field definitions.

# 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"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/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 = { "keywords": ["Python Developer"] }

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/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 '{
  "keywords": [
    "Python Developer"
  ]
}' |
apify call scrapyx/dice-jobs-scraper --silent --output-dataset

```

## MCP server setup

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