# Multiple Job Board Scraper — Remote Job Search API (`khadinakbar/multiple-job-board-scraper`) Actor

Search public Remote OK, Remotive, and Arbeitnow listings in one normalized, AI-ready dataset for recruiting and job-market research.

- **URL**: https://apify.com/khadinakbar/multiple-job-board-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Jobs, MCP servers, AI
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 validated job saveds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## Multiple Job Board Scraper — Remote Job Search API

**Multiple Job Board Scraper** searches Remote OK, Remotive, and Arbeitnow with one query and returns a single normalized job dataset. Use it to source remote candidates, monitor hiring demand, research companies, compare job markets, or feed current public vacancies into recruiting and analytics workflows without maintaining three separate integrations.

Choose the job boards you want, enter a role or skill query, optionally require a location match, and cap the number of saved results. Every accepted record has the same field names regardless of its source, including the job title, company, location, description, tags, original listing URL, application URL, publication date, and source provenance.

The Actor uses public job-board endpoints and does not require login cookies or user-supplied proxies.

Pricing is $0.005 per validated job saved, plus a $0.001-per-GB start event and Apify platform usage. `maxResults` caps both the dataset size and per-job event charges.

### What job data can you extract?

| Field | Type | Description |
| --- | --- | --- |
| `jobId` | string | Stable, source-prefixed identifier used for within-run deduplication. |
| `title` | string | Job title published by the source board. |
| `companyName` | string or null | Hiring company when the board provides it. |
| `location` | string or null | Published location or remote-region requirement. |
| `description` | string or null | Cleaned job description, capped at 10,000 characters; null when disabled or unavailable. |
| `salaryText` | string or null | Salary or compensation text when published by the source. |
| `employmentType` | string or null | Employment type such as full-time or contract when available. |
| `workArrangement` | string or null | Normalized remote-work signal when the source exposes one. |
| `tags` | array of strings | Skills, categories, or source-supplied job tags. |
| `jobUrl` | URL | Canonical public job-listing URL. |
| `applyUrl` | URL or null | Public application URL when available. |
| `postedAt` | string or null | Source publication date or timestamp. |
| `source` | string | One of `remoteok`, `remotive`, or `arbeitnow`. |
| `sourceUrl` | URL | Public endpoint from which the record was obtained. |
| `scrapedAt` | ISO 8601 string | Time the Actor fetched and normalized the record. |

Optional values remain `null` instead of being guessed. The Actor never fabricates a salary, company, date, or application URL.

### When should you use Multiple Job Board Scraper?

- Build a normalized feed of remote and international vacancies.
- Find companies currently hiring for a role or skill set.
- Monitor job demand for technologies such as React, Python, or Kubernetes.
- Create recruiting shortlists and talent-market research datasets.
- Compare listings across Remote OK, Remotive, and Arbeitnow.
- Export public jobs to Google Sheets, a database, a CRM, or a data warehouse.
- Supply structured job records to an AI agent through the Apify API or MCP.

This Actor is not a replacement for a LinkedIn, Indeed, ZipRecruiter, or company ATS scraper. It searches only the three supported public boards. It also does not return applicant profiles, private candidate data, historical listings that are no longer exposed by a source, or guaranteed contact details.

### How to use the job board scraper

The quickest workflow is:

1. Enter a `searchQuery`, such as `react engineer`.
2. Set `location` to `Remote`, a location substring such as `Germany`, or `any` to disable location filtering.
3. Keep all three sources selected or choose only the boards you need.
4. Set `maxResults` between 1 and 500.
5. Run the Actor and open the default dataset.

The search uses all whitespace-separated query terms. For example, `react engineer` requires both `react` and `engineer` to appear across the job title, company, description, or tags. Location matching is a case-insensitive substring check against the published location and work-arrangement text.

#### Input parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `searchQuery` | string | `software engineer` | Required role or skill keywords. Maximum 160 characters. |
| `location` | string | `Remote` | Location text to require. Use `any` or an empty string to accept any location. |
| `sources` | string\[] | all three boards | Any combination of `remoteok`, `remotive`, and `arbeitnow`. At least one is required. |
| `maxResults` | integer | `50` | Global cap on validated, saved, and billable job records. Allowed range: 1–500. |
| `includeDescription` | boolean | `true` | Include the cleaned description. Set false for smaller dataset items. |

#### Example input

```json
{
  "searchQuery": "data engineer",
  "location": "Remote",
  "sources": [
    "remoteok",
    "remotive",
    "arbeitnow"
  ],
  "maxResults": 50,
  "includeDescription": true
}
```

For a broad international search, set `"location": "any"`. For a source-specific search, pass only that board, for example `"sources": ["remotive"]`.

### Output example

The default dataset contains job records only. Run diagnostics are stored separately in the `OUTPUT` and `RUN_SUMMARY` key-value-store records.

```json
{
  "jobId": "remoteok:1135025",
  "title": "Presentation Designer",
  "companyName": "INFUSE",
  "location": "Warszawa, Warszawa, Woj. Mazowieckie, Polska",
  "description": null,
  "salaryText": null,
  "employmentType": null,
  "workArrangement": "remote",
  "tags": [
    "design",
    "marketing",
    "photoshop"
  ],
  "jobUrl": "https://remoteok.com/remote-jobs/remote-presentation-designer-infuse-1135025",
  "applyUrl": "https://remoteok.com/remote-jobs/remote-presentation-designer-infuse-1135025",
  "postedAt": "2026-07-18T09:56:25+00:00",
  "source": "remoteok",
  "sourceUrl": "https://remoteok.com/api",
  "scrapedAt": "2026-07-19T16:14:43.766Z"
}
```

The exact fields available depend on what each source publishes. A missing salary or employment type is returned as `null`, not inferred from the description.

### Pricing

This Actor uses **Pay per event plus Apify platform usage**.

| Event | Price | When it is charged |
| --- | ---: | --- |
| Actor start | $0.001 per GB of Actor memory, minimum one event | When a run starts. The current 4 GB default results in four start events, or $0.004. |
| Validated job saved | $0.005 per job | Only after a normalized job record is validated and persisted to the dataset. |
| Platform usage | Variable | Apify compute, storage, data transfer, and other platform usage are billed separately. |

At the current 4 GB default, approximate event charges are:

- 1 saved job: **$0.009** plus platform usage.
- 50 saved jobs: **$0.254** plus platform usage.
- 100 saved jobs: **$0.504** plus platform usage.
- 500 saved jobs: **$2.504** plus platform usage.

`maxResults` is both an output cap and a job-event cost cap. You are not charged a `job-scraped` event for unmatched, invalid, duplicate, or unsaved records. Actual totals can be lower when fewer jobs match.

### Run with the Apify API

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({
  token: process.env.APIFY_TOKEN,
});

const run = await client.actor(
  'khadinakbar/multiple-job-board-scraper',
).call({
  searchQuery: 'data engineer',
  location: 'Remote',
  sources: ['remoteok', 'remotive', 'arbeitnow'],
  maxResults: 50,
  includeDescription: false,
});

const { items } = await client
  .dataset(run.defaultDatasetId)
  .listItems();

console.log(items);
```

#### Python

```python
import os
from apify_client import ApifyClient

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

run = client.actor(
    "khadinakbar/multiple-job-board-scraper"
).call(run_input={
    "searchQuery": "data engineer",
    "location": "Remote",
    "sources": ["remoteok", "remotive", "arbeitnow"],
    "maxResults": 50,
    "includeDescription": False,
})

items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

### Use with an MCP server or AI agent

Add this Actor to an Apify MCP connection:

```text
https://mcp.apify.com?tools=khadinakbar/multiple-job-board-scraper
```

An MCP-compatible agent can then run the Actor with the same structured input and retrieve its dataset. This is useful for requests such as:

> Find up to 25 remote React engineer jobs across Remote OK, Remotive, and Arbeitnow. Return company, location, tags, posting date, and application URL.

Use `includeDescription: false` when an agent needs compact records. Use `maxResults` to keep the response and event cost predictable.

### Reliability, partial results, and limits

Each selected board is fetched independently. If one source is temporarily unavailable but another produces validated jobs, the Actor keeps the useful records and reports a `PARTIAL` outcome instead of discarding the dataset.

Every run writes machine-readable diagnostics:

- `OUTPUT` contains the final outcome, message, saved-item count, successful sources, and failed sources.
- `RUN_SUMMARY` contains source-level received and matched counts, warnings, duplicate counts, invalid-record counts, and charged-event counts.

Possible outcomes are:

- `COMPLETE`: matching jobs were saved with no recoverable source failures.
- `PARTIAL`: useful jobs were saved, but a board or dataset write produced a recoverable warning.
- `VALID_EMPTY`: the selected boards responded successfully, but no jobs matched.
- `INVALID_INPUT`: the input failed validation and includes a corrective example.
- `UPSTREAM_FAILED`: every selected board failed before producing usable data.
- `CONFIG_ERROR`: required billing configuration was unavailable.

The Actor deduplicates jobs within each run by source ID and job URL. Results reflect what the public source endpoints expose at run time; boards can change fields, remove listings, rate-limit requests, or return incomplete optional data. The Actor does not crawl application forms or verify that a vacancy remains open after the source response is received.

### Other dedicated job scrapers

Use a dedicated Actor when you need a platform or employer-specific search:

- [LinkedIn Jobs Scraper](https://apify.com/khadinakbar/linkedin-jobs-scraper) — keyword and location search across public LinkedIn job listings.
- [ZipRecruiter Jobs Scraper](https://apify.com/khadinakbar/ziprecruiter-jobs-scraper) — public US ZipRecruiter search results.
- [Workday Jobs Scraper](https://apify.com/khadinakbar/workday-jobs-scraper) — jobs from a specific company's public Workday career board.
- [Ashby Jobs Scraper](https://apify.com/khadinakbar/ashby-jobs-scraper) — public Ashby job boards and published compensation.
- [Workable Jobs Scraper](https://apify.com/khadinakbar/workable-jobs-scraper) — current jobs from public Workable career pages.
- [HiringCafe Jobs Scraper](https://apify.com/khadinakbar/hiringcafe-jobs-scraper) — normalized HiringCafe jobs, compensation, skills, and company fields.
- [JobsDB Jobs Scraper](https://apify.com/khadinakbar/jobsdb-jobs-scraper) — public jobs in Hong Kong and Thailand.
- [Bundesagentur Job Scraper](https://apify.com/khadinakbar/bundesagentur-job-scraper) — vacancies from Germany's public Bundesagentur für Arbeit feed.

### FAQ

#### How many results can I scrape with Multiple Job Board Scraper?

You can save between 1 and 500 jobs per run. Set `maxResults` to the maximum you need. The actual count depends on current source inventory and how many listings match every search and location term.

#### Can I integrate Multiple Job Board Scraper with other apps?

Yes. Use Apify integrations, webhooks, dataset exports, Make, Zapier, Google Sheets, or the API to move results into another system. Each run produces a normalized default dataset that can be exported as JSON, CSV, Excel, XML, or RSS through Apify.

#### Can I use Multiple Job Board Scraper with the Apify API?

Yes. Call `khadinakbar/multiple-job-board-scraper` with the JavaScript client, Python client, or REST API, then read the run's default dataset. The examples above show JavaScript and Python.

#### Can I use Multiple Job Board Scraper through an MCP Server?

Yes. Add the Actor to an Apify MCP connection and let an MCP-compatible AI agent submit the same input schema. Keep `maxResults` small and disable descriptions when you want a compact response.

#### Do I need proxies to scrape these job boards?

No user-supplied proxy is required. The Actor reads public job-board endpoints directly. Upstream boards can still rate-limit or change their public interfaces; those failures are reported in `OUTPUT` and `RUN_SUMMARY`.

#### Why did my run return no jobs?

The search requires every whitespace-separated query term to match the title, company, description, or tags, and the location must also match unless it is `any`. Try a shorter role query, set `location` to `any`, select more sources, or inspect `RUN_SUMMARY` to distinguish a valid empty result from a source failure.

#### Is it legal to scrape job board data?

This Actor extracts public job-listing data, but whether and how you may use it depends on the source terms, applicable laws, and your purpose. Do not use the output for unlawful discrimination, spam, privacy violations, or redistribution that infringes third-party rights. You are responsible for reviewing the relevant requirements and handling personal data appropriately.

### Your feedback

Found a missing field, unexpected source response, or workflow this README does not cover? Open an issue on the Actor page with a reproducible input and, when possible, the run ID. Do not include API tokens, private candidate data, or other secrets.

# Actor input Schema

## `searchQuery` (type: `string`):

Use this when you want matching role or skill keywords.

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

Use this to prefer jobs whose location text matches; Remote is accepted.

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

Use this to choose public job boards. Unavailable boards return a partial result without discarding other data.

## `maxResults` (type: `integer`):

Use this to cap saved results and billable job events.

## `includeDescription` (type: `boolean`):

Use this to include a cleaned, capped job description.

## Actor input object example

```json
{
  "searchQuery": "software engineer",
  "location": "Remote",
  "sources": [
    "remoteok",
    "remotive",
    "arbeitnow"
  ],
  "maxResults": 50,
  "includeDescription": true
}
```

# Actor output Schema

## `jobs` (type: `string`):

No description

## `output` (type: `string`):

No description

## `summary` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/multiple-job-board-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/multiple-job-board-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call khadinakbar/multiple-job-board-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=khadinakbar/multiple-job-board-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/bSGPfloZAg10KGSna/builds/9Kof99VYPgy6ZkiPh/openapi.json
