# Global Jobs Scraper — LinkedIn, Indeed & More (`datavoyantlab/multi-source-jobs-api`) Actor

Search worldwide job listings from LinkedIn, Indeed, Bing, and Xing in one run. Export deduplicated JSON, CSV, or Excel with titles, companies, locations, salaries, descriptions, and application URLs. Includes remote filters, enriched results, and salary reports—no login or external API key.

- **URL**: https://apify.com/datavoyantlab/multi-source-jobs-api.md
- **Developed by:** [DataVoyantLab](https://apify.com/datavoyantlab) (community)
- **Categories:** Jobs, Automation, Lead generation
- **Stats:** 2 total users, 2 monthly users, 100.0% runs succeeded, 3 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $4.00 / 1,000 standard job 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

**Global Jobs Scraper** is a multi-source jobs API for searching public listings from
[LinkedIn](https://www.linkedin.com/jobs/), [Indeed](https://www.indeed.com/),
[Bing Jobs](https://www.bing.com/), and [Xing](https://www.xing.com/jobs) in one run.
Search worldwide by job title, skill, location, recency, employment type, or remote
preference, then export deduplicated job data as JSON, CSV, Excel, XML, or through the
Apify API. You can also create structured salary reports by role and country.

No LinkedIn or Indeed account, cookies, proxy configuration, or external API key is
required. Enter your search, select the job platforms, and click **Start**.

### Why use this global jobs scraper?

- **Search four major job sources together.** Replace separate LinkedIn Jobs, Indeed,
  Bing Jobs, and Xing extraction workflows with one Actor.
- **Get one consistent schema.** Titles, companies, locations, salaries, posting dates,
  descriptions, and application URLs use the same field names across sources.
- **Collect worldwide job data.** Run a location-free worldwide LinkedIn search or
  target countries, cities, and regions supported by the selected source.
- **Choose cost or completeness.** Use economical standard results for discovery, or
  enriched results when every saved job must include a description and application URL.
- **Remove duplicate listings automatically.** Cross-posted jobs are merged before they
  reach the dataset and before result billing.
- **Pay only for usable data events.** Invalid records, incomplete enrichments,
  unavailable salary reports, and duplicate jobs do not trigger a result event.
- **Automate without maintaining a scraper.** Run from the Apify Console, API, Python,
  JavaScript, schedules, webhooks, Make, Zapier, n8n, or your existing data pipeline.

### What job data can you extract?

Every job record can contain the following fields when the publisher makes them
available:

| Data group | Fields |
|---|---|
| Job | `jobId`, `title`, `employmentType`, `description`, `detailLevel` |
| Company | `companyName` |
| Location | `location`, `remote` |
| Application | `jobUrl` |
| Dates | `postedAt`, `scrapedAt` |
| Compensation | `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod` |
| Provenance | `source`, `resultType` |

Use the resulting job dataset for:

- recruiting and candidate sourcing workflows;
- job-board aggregation and job alert products;
- remote-job monitoring;
- labor-market and skills-demand research;
- company hiring and competitor intelligence;
- salary benchmarking by title and country;
- AI, search, analytics, ATS, CRM, and data-warehouse pipelines.

### Standard jobs vs. enriched job details

Choose the result level that matches your workflow and budget.

| | Standard | Enriched |
|---|---|---|
| Best for | Discovery, monitoring, large datasets | Job pages, ATS records, AI analysis |
| Maximum saved jobs | 500 per run | 50 per run |
| Description | Included when available | Required for every saved job |
| Application URL | Included when available | Required for every saved job |
| Billing event | `job-result` | `job-detail` |
| Sources | LinkedIn, Indeed, Bing, Xing | LinkedIn, Indeed, Bing, Xing |

Salary information attached to a job stays part of that job. It does not create a
separate salary-report charge.

### Worldwide job search coverage

The Actor is built for global job discovery, but each public job platform supports a
different search vocabulary. Unsupported filters are never silently converted into a
different filter; they are applied only to compatible sources and the run reports the
limitation.

| Source | Coverage and filter behavior |
|---|---|
| LinkedIn | Supports worldwide searches when `locations` is empty, plus remote, date-posted, and employment-type filters. |
| Indeed | Uses `countryCode` to select the job market. Shared remote, date, and employment-type filters are not applied to Indeed. |
| Bing | Requires a location. Supports remote and past-day/past-week filters; internship is not supported. |
| Xing | Best coverage is in German-speaking job markets. Supports remote and past-day/past-week/past-month filters. |

For the broadest multi-platform coverage, provide both a two-letter `countryCode` and a
city, region, or country in `locations`. For a worldwide LinkedIn search, select only
LinkedIn and leave `locations` empty.

### How to scrape jobs in less than a minute

1. Open the **Input** tab.
2. Enter up to five job titles, skills, company names, or keyword searches.
3. Choose up to five locations and any combination of LinkedIn, Indeed, Bing, and Xing.
4. Select **Standard** for economical discovery or **Enriched** for complete descriptions
   and application URLs.
5. Set `maxJobs`, click **Start**, and preview the normalized results in the **Output**
   tab.
6. Download the dataset or connect it to your application through the Apify API.

#### Multi-platform job search example

This search combines four sources and deduplicates their results:

```json
{
  "mode": "jobs",
  "queries": ["Software engineer", "Data engineer"],
  "countryCode": "DE",
  "locations": ["Berlin"],
  "sources": ["linkedin", "indeed", "bing", "xing"],
  "resultMode": "standard",
  "datePosted": "week",
  "employmentTypes": ["full_time"],
  "maxJobs": 100,
  "maxPagesPerSearch": 2
}
```

Some shared filters in a mixed search apply only to compatible sources. For example,
Indeed results are still included in the example above, but the shared date and
employment-type filters are not sent to Indeed.

#### Worldwide LinkedIn jobs example

Leave `locations` empty to search LinkedIn worldwide:

```json
{
  "mode": "jobs",
  "queries": ["Machine learning engineer"],
  "locations": [],
  "sources": ["linkedin"],
  "resultMode": "standard",
  "maxJobs": 100,
  "maxPagesPerSearch": 2
}
```

#### Remote jobs scraper example

```json
{
  "mode": "jobs",
  "queries": ["Python developer"],
  "countryCode": "US",
  "locations": ["United States"],
  "sources": ["linkedin", "bing"],
  "resultMode": "enriched",
  "remoteOnly": true,
  "datePosted": "week",
  "employmentTypes": ["full_time", "contract"],
  "maxJobs": 25
}
```

### Salary data API

Salary mode creates one structured compensation report per requested job title for a
two-letter country code. A complete report includes a currency and at least one numeric
salary range. Hourly, daily, weekly, monthly, and yearly minimum, maximum, mean, and
median values are returned where available.

```json
{
  "mode": "salary",
  "queries": ["Software engineer", "Data engineer", "Product manager"],
  "countryCode": "US"
}
```

An unavailable or incomplete salary report is omitted and does not trigger a
`salary-report` event. Salary coverage varies by role and country, so start with a small
test for your target market.

### Job scraper output example

The default dataset contains flat, analysis-ready records. Optional fields are omitted
when the original listing does not provide them; the Actor does not invent missing
values.

```json
{
  "resultType": "job",
  "detailLevel": "enriched",
  "jobId": "example-job-id",
  "source": "LinkedIn",
  "title": "Senior Data Engineer",
  "companyName": "Example Labs",
  "location": "New York, NY",
  "remote": true,
  "employmentType": "full_time",
  "description": "Build reliable data products and pipelines...",
  "jobUrl": "https://www.linkedin.com/jobs/view/example-job-id",
  "postedAt": "2026-08-09T14:30:00Z",
  "salaryMin": 135000,
  "salaryMax": 175000,
  "salaryCurrency": "USD",
  "salaryPeriod": "year",
  "scrapedAt": "2026-08-10T09:15:00Z"
}
```

Salary reports use `resultType: "salaryReport"` and include `jobTitle`, `country`,
`countryCode`, `currency`, `lastUpdatedAt`, `reportId`, `scrapedAt`, and the available
salary statistics such as `hourlyMedian`, `monthlyMean`, or `yearlyMax`.

Results can be downloaded from Apify as **JSON, JSONL, CSV, Excel, XML, RSS, or HTML**.

### Use the jobs scraper as an API

#### Python

```python
import os

from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_API_TOKEN"])

run = client.actor("datavoyantlab/multi-source-jobs-api").call(
    run_input={
        "mode": "jobs",
        "queries": ["Data engineer"],
        "countryCode": "GB",
        "locations": ["London"],
        "sources": ["linkedin", "indeed", "bing"],
        "resultMode": "standard",
        "maxJobs": 50,
    }
)

for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], job.get("companyName"), job.get("jobUrl"))
```

#### HTTP

Run the Actor synchronously and receive dataset items in the response:

```bash
curl --request POST \
  "https://api.apify.com/v2/acts/datavoyantlab~multi-source-jobs-api/run-sync-get-dataset-items" \
  --header "Authorization: Bearer $APIFY_API_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "mode": "jobs",
    "queries": ["Data engineer"],
    "countryCode": "CA",
    "locations": ["Toronto"],
    "sources": ["linkedin", "indeed", "bing"],
    "resultMode": "standard",
    "maxJobs": 25
  }'
```

The Actor's **API** tab also generates ready-to-use examples for Python, JavaScript,
HTTP, OpenAPI, and MCP.

### Automate job monitoring and recruiting workflows

- Use **Apify Schedules** to collect new jobs every day or week.
- Send completed datasets to a webhook, database, ATS, CRM, Google Sheets, or a data
  warehouse.
- Connect the Actor to **Make, Zapier, n8n, Slack, or Airbyte** through Apify
  integrations.
- Store `jobId` in your application to compare recurring runs and detect newly published
  jobs.
- Use standard mode for frequent monitoring, then run a smaller enriched search when
  full descriptions are required.

### Pay-per-event pricing

The Actor uses transparent pay-per-event billing:

| Event | When it is charged |
|---|---|
| `apify-actor-start` | Automatically when a run starts; the live price is shown in the Pricing tab. |
| `job-result` | Once for each valid standard job saved to the default dataset. |
| `job-detail` | Once for each valid enriched job saved with a description and application URL. |
| `salary-report` | Once for each complete salary report saved to the default dataset. |

Each saved item triggers exactly one data event, in addition to the small Actor-start
event. Duplicate jobs, invalid records, incomplete enrichments, and unavailable salary
reports are not saved and do not trigger a data event. A run with no matching results can
still incur the Actor-start charge.

Use Apify's **maximum charge per run** setting to enforce a hard budget. Before the
search starts, the Actor reduces the requested result count when the remaining charge
limit is smaller than `maxJobs`. The live **Pricing** tab is always the source of truth
for event prices and platform-usage charges.

#### Free-account safeguards

Users without a paid Apify plan can evaluate every output mode under a deliberately
small allowance. Job searches are limited to one query, one location, two platforms,
one page, and either 25 standard results or 5 enriched results. Salary mode accepts one
query per run. The allowance includes up to 3 runs and 10 uncached data requests per day,
with a maximum of 30 uncached data requests per month. Repeated cached searches do not
consume the data-request allowance.

When the free allowance is exhausted, the Actor stops without saving or charging a data
event; the small Actor-start event can still apply. Paid Apify users retain the full
input limits documented above.

### Tips for better job search results

- Start with one precise title and one location, then expand the query after checking
  relevance.
- Use `maxPagesPerSearch: 1` for quick tests and increase it only when you need deeper
  coverage.
- Select standard mode for broad or recurring searches. Enriched mode performs more work
  per result and is intended for smaller, detail-heavy datasets.
- Search synonyms separately, such as `software engineer`, `backend developer`, and
  `platform engineer`, because job publishers use different titles.
- For global research, split large searches by country or region. This makes scheduled
  runs easier to compare and diagnose.
- Treat `maxJobs` as an upper limit, not a guaranteed count. Available public listings,
  selected filters, source availability, and deduplication determine the final total.

### Frequently asked questions

#### Is this a LinkedIn Jobs scraper and an Indeed Jobs scraper?

Yes. It searches public LinkedIn and Indeed job listings and can combine them with Bing
and Xing results in the same normalized dataset. You can select one source or any
combination of the four.

#### Do I need a LinkedIn account, Indeed account, cookies, or an API key?

No. Users provide only an Apify API token when calling the Actor programmatically. No
account, session cookie, proxy setup, or external data-provider key is required in the
Actor input.

#### Can this Actor search jobs worldwide?

Yes, with source-specific coverage. LinkedIn supports a worldwide search when no
location is supplied. Indeed selects markets with `countryCode`, Bing uses free-form
locations, and Xing is strongest in German-speaking markets. No single platform is
guaranteed to have listings for every role and location.

#### Are full job descriptions and application URLs guaranteed?

Use enriched mode when both are required. Standard mode may omit either field when it is
not present in the discovery result. In enriched mode, incomplete records are discarded
instead of being billed as job details.

#### Why did the Actor return fewer jobs than `maxJobs`?

`maxJobs` is a ceiling. A narrow query may have fewer public listings, multiple sources
may return the same job, filters may reduce the result set, or one selected source may be
temporarily unavailable. The Actor removes duplicates rather than charging for repeated
records.

#### Can I schedule the Actor for daily job alerts?

Yes. Create an Apify Schedule and connect the finished run to a webhook or integration.
For change detection, retain `jobId` from earlier runs and compare it with the latest
dataset.

#### Is job and salary data always complete?

No. Public listings often omit salary, employment type, posting date, or remote status.
Optional job fields are returned only when available. Standalone salary reports are
saved only when they contain a currency and at least one numeric salary range.

### Troubleshooting

- **Invalid input with Indeed selected:** add a two-letter `countryCode`, such as `US`,
  `GB`, `FR`, `DE`, `IN`, `BR`, or `AU`.
- **Invalid input with Bing selected:** add at least one value to `locations`.
- **Invalid enriched search:** set `maxJobs` to 50 or less.
- **Too many job queries:** jobs mode accepts up to five queries per run; salary mode
  accepts up to twenty.
- **No matching results:** broaden the title or location, remove optional filters, or try
  another source. No result event is charged when nothing is saved.
- **Some filters were partially applied:** one selected source does not support that
  filter. Check the worldwide coverage table above.

### Responsible use and support

This Actor collects public job-listing and aggregate salary information. Listings can be
changed or removed after collection, and output accuracy depends on the original
publisher. Follow applicable laws, data-protection requirements, and the terms of the
websites whose public data you use. Do not use job data for unlawful discrimination,
spam, or decisions that require verified information without independent review.

If a run behaves unexpectedly, open the Actor's **Issues** tab and include the run ID,
selected sources, and a sanitized input example. Never post your Apify API token or
other credentials in an issue.

# Actor input Schema

## `mode` (type: `string`):

Choose job listings or standalone salary reports.

## `queries` (type: `array`):

Job titles, skills, or keywords. Jobs mode accepts up to 5; salary mode accepts up to 20.

## `countryCode` (type: `string`):

Two-letter country code, such as US, GB, FR, DE, IN, BR, or AU. Required for Indeed and salary reports.

## `locations` (type: `array`):

Up to 5 cities, regions, or countries. Leave empty for a worldwide LinkedIn search; Bing requires a location.

## `sources` (type: `array`):

All platforms support standard discovery. Enriched mode adds descriptions and application URLs where available.

## `resultMode` (type: `string`):

Standard is economical and may omit descriptions or application URLs. Enriched requires both fields and is capped at 50 results.

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

Supported by LinkedIn, Bing, and Xing. In mixed searches it is ignored only for platforms that do not offer this filter.

## `datePosted` (type: `string`):

Bing supports day and week; LinkedIn and Xing also support month. In mixed searches it is ignored only for platforms that do not offer the selected value.

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

Indeed does not offer this filter, and Bing does not offer internship. In mixed searches unsupported values are ignored only for those platforms.

## `maxJobs` (type: `integer`):

Maximum deduplicated results. Enriched mode is limited to 50.

## `maxPagesPerSearch` (type: `integer`):

Pagination depth for each query, location, and platform combination.

## Actor input object example

```json
{
  "mode": "jobs",
  "queries": [
    "Python developer"
  ],
  "countryCode": "US",
  "locations": [
    "New York"
  ],
  "sources": [
    "linkedin"
  ],
  "resultMode": "standard",
  "remoteOnly": false,
  "datePosted": "any",
  "employmentTypes": [],
  "maxJobs": 1,
  "maxPagesPerSearch": 1
}
```

# Actor output Schema

## `results` (type: `string`):

Normalized job listings or salary reports, depending on the selected mode.

# 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 = {
    "queries": [
        "Python developer"
    ],
    "countryCode": "US",
    "locations": [
        "New York"
    ],
    "sources": [
        "linkedin"
    ],
    "maxJobs": 1,
    "maxPagesPerSearch": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("datavoyantlab/multi-source-jobs-api").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 = {
    "queries": ["Python developer"],
    "countryCode": "US",
    "locations": ["New York"],
    "sources": ["linkedin"],
    "maxJobs": 1,
    "maxPagesPerSearch": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("datavoyantlab/multi-source-jobs-api").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 '{
  "queries": [
    "Python developer"
  ],
  "countryCode": "US",
  "locations": [
    "New York"
  ],
  "sources": [
    "linkedin"
  ],
  "maxJobs": 1,
  "maxPagesPerSearch": 1
}' |
apify call datavoyantlab/multi-source-jobs-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datavoyantlab/multi-source-jobs-api"
        }
    }
}

```

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/vc9v6M7zWVV7g77Ba/builds/nIVZtXlLe477ro79O/openapi.json
