# Jobs Scraper All-in-One — Listings, Salaries & Insights (`toolzerhub/jobs-scraper-all-in-one`) Actor

Search live job postings from Indeed, LinkedIn, Glassdoor and company career pages in one run. Each comes back with its pay range, employer, location, posting date and apply link. Add the going rate for roles that quote no pay, and what each posting asks of a candidate.

- **URL**: https://apify.com/toolzerhub/jobs-scraper-all-in-one.md
- **Developed by:** [ToolzerHub](https://apify.com/toolzerhub) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 191 total users, 4 monthly users, 98.4% runs succeeded, 5 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

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

## Jobs Scraper All-in-One

Search live job postings from Indeed, LinkedIn, Glassdoor, ZipRecruiter, and company career pages in a single run. Every posting comes back with its employer, location, posting date, and a direct apply link. Two optional add-ons fill in what postings usually leave out — what the role pays, and what it asks of a candidate.

```json
{
  "query": ["python developer in new york"],
  "maxItems": 30,
  "country": "us",
  "postedWithin": "week"
}
```

### Input

**`query`** takes a list — every term in it gets searched. A term is free text: a role, a role plus a place, or a company name. **`maxItems`** bounds the whole run and is shared across the terms; a term that runs dry early hands its share to the ones after it. Set it to `0` for no bound.

Every filter below is optional:

- **`country`** — two-letter code, `us` by default. `gb`, `de`, `ca`, `au`, `in`, and the rest all work — results come back from that market's own boards, in its currency.
- **`language`** — leave on Default to follow the country.
- **`postedWithin`** — `any`, `today`, `3_days`, `week`, `month`.
- **`remoteOnly`** — keep only postings you can work from home.
- **`employmentType`** — `full_time`, `part_time`, `contract`, `internship`.
- **`requirement`** — `no_experience`, `under_3_years`, `over_3_years`, `no_degree_required`.
- **`radiusKm`** — how far from the place named in your search term to look.
- **`excludeBoards`** — comma-separated board names to drop, such as `BeeBe,Dice`.

```json
{
  "query": ["data engineer", "analytics engineer"],
  "maxItems": 100,
  "country": "de",
  "remoteOnly": true,
  "employmentType": "full_time",
  "postedWithin": "3_days"
}
```

### Pay estimate

Roughly seven postings in ten quote no pay at all. Turn on **`includePayEstimate`** and every row gets **`pay_estimate`** — what that role goes for in that location, split into total, base, and everything on top (bonus, commission, equity), each as a min, max, and median, with the number of reported salaries behind it.

You're charged per estimate, not per posting. Postings that share a role and a location are looked up once and billed once, so a hundred "Python Developer" rows in New York cost one estimate, not a hundred.

### Job insights

Turn on **`includeJobInsights`** and each posting gets read in full, adding an **`insights`** object: the seniority it's pitched at, the years of experience it asks for, required and preferred technologies, methodologies, work arrangement, whether it sponsors a visa, its start date, and contract length. **`highlights`** and employer star ratings fill in at the same time.

You're charged per posting enriched, and only once a read actually turns up something — a posting with nothing extra behind it costs nothing.

```json
{
  "query": ["senior python engineer new york"],
  "maxItems": 50,
  "includeJobInsights": true,
  "includePayEstimate": true
}
```

### Output

A job row carries:

- **`id`** and **`short_id`** — two ids for the same posting; use **`short_id`** as the compact one to key your own storage on.
- **`title`**, **`description`**, **`employment_type`**, **`employment_types`**, **`is_remote`**.
- **`company`** — name, logo, website, and any published star ratings with their review counts.
- **`location`** — free text plus split city, state, country, latitude, and longitude.
- **`salary`** — **`min`**, **`max`**, **`period`**, and the board's own phrasing in **`text`**. `null` where the posting quotes no pay, which is most of them.
- **`posted`** — relative text, an ISO timestamp, and a Unix timestamp.
- **`apply`** — the primary link, whether it goes straight to the employer, and every board carrying the posting.
- **`source_board`** — which board the posting was read from.
- **`benefits`**, **`highlights`**, **`insights`**, and **`pay_estimate`** — the last two `null` unless you turned their add-on on.

```json
{
  "id": "OE5QRjlGUEU0TlRTT2E2OEFBQUFBQT09OkVzd0JDb3dCUVVwcFZEUjBTVWc1Wm1oMk9GZzJVM0pxTWpWcFVtNDBSM",
  "short_id": "8NPF9FPE4NTSOa68AAAAAA==",
  "title": "Senior Python Software Engineer (Trading)",
  "employment_type": "Full-time",
  "employment_types": ["FULLTIME"],
  "is_remote": false,
  "company": {
    "name": "Fintal Partners",
    "website": "https://www.fintalpartners.com",
    "reviews": []
  },
  "location": {
    "text": "New York, NY",
    "city": "New York",
    "state": "New York",
    "country": "US",
    "latitude": 40.7127753,
    "longitude": -74.0059728
  },
  "salary": { "text": "300K–1M a year", "min": 300000, "max": 1000000, "period": "YEAR" },
  "posted": { "text": "2 days ago", "at": "2026-08-13T00:00:00.000Z", "timestamp": 1786584000 },
  "apply": {
    "url": "https://www.linkedin.com/jobs/view/senior-python-software-engineer",
    "is_direct": false,
    "options": [{ "board": "LinkedIn", "url": "https://www.linkedin.com/jobs/view/senior-python-software-engineer", "is_direct": false }]
  },
  "source_board": "LinkedIn",
  "insights": null
}
```

```json
{
  "pay_estimate": {
    "job_title": "Nodejs Developer",
    "location": "New York, NY",
    "currency": "USD",
    "period": "YEAR",
    "total": { "min": 120421.81, "max": 199347.14, "median": 154167.01 },
    "base": { "min": 98988.75, "max": 159338.77, "median": 125589.6 },
    "additional": { "min": 21433.06, "max": 40008.37, "median": 28577.41 },
    "sample_size": 6,
    "updated_at": "2025-04-10T23:59:59.000Z",
    "source": { "board": "Glassdoor", "url": "https://www.glassdoor.com/Salaries/company-salaries.htm" }
  }
}
```

### Questions

**Why does `pay_estimate` show a modelled figure instead of what the posting says?**
Because pay is usually missing — only about three postings in ten quote a range. `salary` carries what the employer actually wrote; `pay_estimate` carries the market rate for that role and city, with the sample size behind it. Keeping them in separate fields means you can always tell a quoted figure from a modelled one, and filter on either.

**Why do lookups still work when job titles vary so much — "Senior Python Software Engineer (Trading)" versus "Python Developer — Build High-Quality, Maintainable Software"?**
Because titles get trimmed before lookup. Those two are the same role underneath, and titles are reduced to the role before the pay lookup runs — which took coverage on a live New York page from one row in eight to six.

**Will I get the same job twice if it's posted on several boards?**
No — rows are de-duplicated. Postings are collapsed by id across every search term in a run. Where two boards file the same job under different ids, both survive; pair them up yourself with `company.name` plus `title`.

**Should I run one broad search term or several precise ones?**
Several precise ones. Each term reaches roughly 500 postings, and precise terms return more, and more relevant, results than one broad term paged to the end. The run's `maxItems` budget is shared across every term, so a term that comes up short hands its share to the next one.

**Can I use `short_id` as a primary key in my own store?**
Yes. It's the same string for the same posting on every run.

### Related Actors

| Actor | Use when |
|---|---|
| [LinkedIn Jobs Scraper](https://apify.com/toolzerhub/linkedin-jobs-scraper) | You want LinkedIn job search with LinkedIn's own filters, not a combined multi-board run |
| [LinkedIn Job Details Scraper](https://apify.com/toolzerhub/linkedin-job-details-scraper) | You already have a LinkedIn job URL or ID and want its full posting detail |

### Support

Questions, bugs, or feature requests: **contact@toolzerhub.com**

Browse the rest: [apify.com/toolzerhub](https://apify.com/toolzerhub)

# Actor input Schema

## `query` (type: `array`):

What to look for — a role, a role and a place, or a company name. Add several and the run collects all of them.

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

How many postings to save across every search term. Set 0 for no limit.

## `country` (type: `string`):

Two-letter country code the search runs in — us, gb, de, ca, au, in. Leave empty for us.

## `language` (type: `string`):

Language for the postings. Leave on Default to follow the country.

## `postedWithin` (type: `string`):

Only keep postings first published inside this window.

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

Keep only postings that can be worked from home.

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

Keep only one kind of engagement.

## `requirement` (type: `string`):

Keep only postings asking this of a candidate.

## `radiusKm` (type: `integer`):

How far from the place named in the search term to look.

## `excludeBoards` (type: `string`):

Comma-separated board names to drop from the results, such as BeeBe,Dice.

## `includeJobInsights` (type: `boolean`):

Read each posting in full and attach what it asks for: seniority, years of experience, required and preferred technologies, work arrangement, visa sponsorship, start date and contract length. Billed per posting enriched.

## `includePayEstimate` (type: `boolean`):

Attach the going rate for each posting's role in its own location, split into base pay and everything on top. Most postings quote no pay at all, and this fills that gap. Billed per estimate, and postings sharing a role and location are estimated once.

## Actor input object example

```json
{
  "query": [
    "python developer in new york"
  ],
  "maxItems": 10,
  "language": "",
  "postedWithin": "",
  "remoteOnly": false,
  "employmentType": "",
  "requirement": "",
  "includeJobInsights": false,
  "includePayEstimate": false
}
```

# Actor output Schema

## `dataset` (type: `string`):

Every record collected during this run

# 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 = {
    "query": [
        "software engineer"
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("toolzerhub/jobs-scraper-all-in-one").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 = {
    "query": ["software engineer"],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("toolzerhub/jobs-scraper-all-in-one").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 '{
  "query": [
    "software engineer"
  ],
  "maxItems": 10
}' |
apify call toolzerhub/jobs-scraper-all-in-one --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,toolzerhub/jobs-scraper-all-in-one"
        }
    }
}

```

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/YB4OYSD5qcurnA33M/builds/hcvKJVamlAQzf1GJ3/openapi.json
