# 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
- **Features:** Limited permissions
- **Stats:** 3 total users, 2 monthly users, 100.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. 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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What is Multiple Job Board Scraper — Remote Job Search API?

Multiple Job Board Scraper searches the public Remote OK, Remotive and Arbeitnow boards with one query and returns a single normalized dataset of job rows. Every row has the same fields whatever its source: job title, company, location, cleaned description, skill tags, work arrangement, listing and apply URLs, publication date and source provenance. Recruiters, talent-market researchers, job-alert builders and AI agents use it to source remote roles and track hiring demand without maintaining three separate integrations.

### Why teams use this remote job search API

- **Three boards, one schema.** Results from `remoteok`, `remotive` and `arbeitnow` share the same field names, so they merge cleanly in one sheet or table.
- **All-terms keyword matching.** Every word in `searchQuery` must appear across the title, company, description or tags, which keeps results on topic.
- **Location filter that understands remote.** `location` accepts `Remote`, a place such as `Germany`, or `any` for every location.
- **Skills as tags.** `tags` carries the board's skill and category labels, ready for demand analysis by technology.
- **Compact mode for agents.** Set `includeDescription` to `false` for lean rows.
- **Honest optional fields.** `salaryText`, `employmentType` and similar fields stay `null` unless the board publishes them, so nothing is guessed.

### Best fit and related Actors

Best fit for remote and international tech roles posted on Remote OK, Remotive and Arbeitnow: building a remote-jobs feed, finding companies hiring for a skill, or giving an agent a quick current sample of open roles.

- For keyword and location search on LinkedIn job listings, use [LinkedIn Jobs Scraper](https://apify.com/khadinakbar/linkedin-jobs-scraper) alongside this Actor.
- When a company from your results runs its own Workday career site, continue with [Workday Jobs Scraper](https://apify.com/khadinakbar/workday-jobs-scraper) to pull its full openings list.

### Example workflow: from a skill to a weekly remote-jobs digest

A newsletter editor starts with `searchQuery` set to `react engineer`, `location` set to `Remote` and `maxResults` set to 100. The dataset returns each job's `title`, `companyName`, `tags`, `postedAt` and `applyUrl` from all three boards. They sort by `postedAt`, keep the newest roles, and export them into the weekly newsletter. A weekly schedule with the same input refreshes the list, and they compare `jobId` values against last week's issue to highlight only new openings.

### How to search multiple job boards

1. Enter a **Search query**, for example `data engineer`.
2. Set **Location** to `Remote`, a place such as `Germany`, or `any`.
3. Keep all three **Job boards** selected or choose the ones you need, then set **Maximum jobs**.
4. Click **Start**, then export the dataset as JSON, CSV or Excel, or read it through the API.

### Input

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

| Field | Type | What it controls |
|---|---|---|
| `searchQuery` | string | Required role or skill keywords. Every word must match. Default `software engineer`. |
| `location` | string | Location text to match, `Remote`, or `any`. Default `Remote`. |
| `sources` | array | Any of `remoteok`, `remotive` and `arbeitnow`. Default all three. |
| `maxResults` | integer | Saved and billed job cap, from 1 to 500. Default 50. |
| `includeDescription` | boolean | Include the cleaned description. Default `true`. |

### Output

One dataset row per job. Diagnostics for each run go to the `OUTPUT` and `RUN_SUMMARY` key-value-store records.

| Field | What it contains |
|---|---|
| `jobId` | Source-prefixed ID, for example `remoteok:1137427` |
| `title` | Job title |
| `companyName` | Hiring company |
| `location` | Published location or remote region |
| `description` | Cleaned description, when `includeDescription` is on |
| `salaryText` | Compensation text when the board publishes it |
| `employmentType` | Full-time, contract and similar, when the board publishes it |
| `workArrangement` | Normalized remote signal such as `remote` |
| `tags` | Skill and category tags |
| `jobUrl`, `applyUrl` | Listing URL and application URL |
| `postedAt` | Publication date |
| `source`, `sourceUrl`, `scrapedAt` | Board name, source endpoint and collection time |

```json
{
  "jobId": "remoteok:1137427",
  "title": "Software Engineer",
  "companyName": "Prenosis",
  "location": "Remote",
  "description": "Remote - Prenosis Inc. is an artificial intelligence company pioneering precision medicine in acute care...",
  "salaryText": null,
  "employmentType": null,
  "workArrangement": "remote",
  "tags": ["golang", "dev", "engineer", "digital nomad"],
  "jobUrl": "https://remoteok.com/remote-jobs/remote-software-engineer-prenosis-1137427",
  "applyUrl": "https://remoteok.com/remote-jobs/remote-software-engineer-prenosis-1137427",
  "postedAt": "2026-09-23T14:00:02+00:00",
  "source": "remoteok",
  "sourceUrl": "https://remoteok.com/api",
  "scrapedAt": "2026-10-01T01:47:11.433Z"
}
```

`OUTPUT.outcome` is one of `COMPLETE`, `PARTIAL`, `VALID_EMPTY`, `INVALID_INPUT`, `UPSTREAM_FAILED` or `CONFIG_ERROR`, so code and agents can branch on the result. `PARTIAL` means useful jobs were saved while one selected board was unavailable.

### Pricing

This Actor uses Pay per event with Apify platform usage included in the event price. You pay one **Validated job saved** event for each job that is validated and written to the dataset, and **Actor Start** events when the run starts, counted per GB of memory. Unmatched, duplicate and invalid records are never charged, and `maxResults` caps the job events.

Worked example in words: a run that saves fifty matching jobs costs fifty Validated job saved events plus the start events for the run's memory. Check the live Pricing tab on this page for current event prices, and lower the run memory to reduce start events.

### API example

```bash
curl -X POST "https://api.apify.com/v2/acts/khadinakbar~multiple-job-board-scraper/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"searchQuery": "python developer", "location": "any", "maxResults": 25, "includeDescription": false}'
```

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_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,
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["source"], job["title"], job["companyName"], job["applyUrl"])
```

### Use with AI agents (MCP)

Connect the Actor to Claude, ChatGPT, Cursor or any MCP client through [Apify MCP](https://mcp.apify.com) and ask:

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

The agent sets `searchQuery`, `location` and `maxResults`, reads rows back from the dataset, and checks `OUTPUT.outcome` to tell an empty match from a partial run. Each row keeps `jobUrl`, `source` and `scrapedAt` for citation, and `maxResults` fixes the cost scope before the run starts.

### Best results

| Starting situation | Helpful action | Expected outcome |
|---|---|---|
| A long, specific query | Shorten to two or three core words, such as `react engineer` | More matches, still on topic |
| Global roles | Set `location` to `any` | Every location the boards publish |
| European roles | Set `location` to a country such as `Germany` | Rows whose location text matches |
| One preferred board | Pass only that board in `sources` | A single-source dataset |
| Agent or LLM context | Set `includeDescription` to `false` | Compact rows |
| Skill demand tracking | Count `tags` across a scheduled dataset | A trend of technologies in demand |

### Builder's note

I built this Actor because remote-job research usually means stitching together several boards with different field names. I designed one schema for all three, kept optional fields `null` instead of inferring them from text, and made `maxResults` the cap on both output and job charges. I found that requiring every query word to match keeps small searches focused without extra filters.

### FAQ

#### How many jobs can one run return?

Up to 500, set by `maxResults`. The actual count depends on what the boards list and how many match every term.

#### Do I need proxies or accounts?

No. The Actor reads the boards' public listings directly.

#### Why is salary empty on some rows?

`salaryText` is filled only when the board publishes compensation. Many remote listings omit it.

#### Can I run it on a schedule?

Yes. Attach an Apify schedule and compare `jobId` values between runs to find new postings.

### Responsible use

This Actor collects public job-listing data. Use it in line with each board's terms and applicable laws, use the output for lawful recruiting and research, and handle any personal data in line with privacy laws such as the GDPR. Remote OK, Remotive and Arbeitnow are trademarks of their owners; this independent Actor is not affiliated with or endorsed by them.

# 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(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 '{}' |
apify call khadinakbar/multiple-job-board-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,khadinakbar/multiple-job-board-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/bSGPfloZAg10KGSna/builds/Oudt2OFXkTlqvhfrp/openapi.json
