# Remote Jobs Scraper: 4 Remote Job Boards in One Dataset (`datagleaner/remote-jobs-scraper`) Actor

Remote jobs scraper: one dataset from Remote OK, Jobicy, Arbeitnow and We Work Remotely. Filter by keyword, category, location and date; duplicates removed. Salary, tags, description, apply link. No login. $1 per 1,000 jobs.

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

## Pricing

$1.00 / 1,000 remote jobs

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

## Remote Jobs Scraper: four remote job boards in one dataset

**Read Remote OK, Jobicy, Arbeitnow and We Work Remotely in one run and get one de-duplicated dataset: title, company, location, category, tags, salary when the board shows it, posting date, full description and apply link.** Filter by keyword, category, candidate location and posting date. No login, no API key, no browser.

**Price: $1 per 1,000 jobs** ($0.001 per job), no start fee. 100 jobs cost 10 cents.

### Why use this one

- **One call instead of four integrations.** Every row has the same fields and a `source` field, so boards stay separable.
- **Duplicates across boards removed,** so a job posted twice is billed once.
- **Built for schedules and agents.** `postedWithinDays: 1` plus a keyword gives a daily feed; the same input works from n8n, Make, Zapier or an MCP agent.
- **Each row links to its original posting** (`url`, `applyUrl`) so you can credit the board.
- **Honest limits:** each board exposes a recent window, not its archive (Remote OK about 100 jobs, Jobicy the last 7 days, We Work Remotely about 400, Arbeitnow the latest ~1,000, remote ones kept). Salary appears only when the board shows it. Remotive and Himalayas are not included; their terms do not allow passing listings on.

### Minimal input

```json
{"keywords": ["python"], "postedWithinDays": 7, "maxJobs": 100}
```

### Sample output row (real platform run, long text shortened)

```json
{
  "jobId": "weworkremotely-quickmail-technical-customer-support",
  "source": "weworkremotely",
  "url": "https://weworkremotely.com/remote-jobs/quickmail-technical-customer-support",
  "title": "Technical Customer Support",
  "company": "QuickMail",
  "companyLogo": "https://wwr-pro.s3.amazonaws.com/logos/0064/3699/logo.gif",
  "location": "Zug, Anywhere in the World",
  "isRemote": true,
  "employmentType": "full_time",
  "category": "Customer Support",
  "tags": [
    "Technical Support",
    "Customer Support"
  ],
  "salaryMin": null,
  "salaryMax": null,
  "salaryCurrency": null,
  "salaryPeriod": null,
  "postedAt": "2026-10-10T21:21:48+00:00",
  "description": "Headquarters: Zurich, Switzerland\nURL: https://quickmail.com\nThe role\nWe are hiring a technical customer suppo...",
  "applyUrl": "https://weworkremotely.com/remote-jobs/quickmail-technical-customer-support",
  "scrapedAt": "2026-10-11T06:37:45+00:00",
  "input": {
    "categories": [
      "customer support"
    ],
    "maxJobs": 15
  }
}
```

### What you can do with it

- Feed a remote-job search to an AI agent or an automation (n8n, Make, Zapier) with one call instead of four integrations.
- Track hiring for a skill: run it daily with `keywords: ["rust"]` and `postedWithinDays: 1`.
- Build a newsletter, alert or internal dashboard of remote roles for your own audience.
- Study remote salary and demand trends across boards (the `source` field keeps the boards apart).
- Merge with the Data Gleaner `career-jobs` and `seek-jobs` Actors: all three use `jobId`, `title`, `postedAt`, `employmentType` and `applyUrl`.

### Sources

| `sources` value | Board | Notes |
|---|---|---|
| `remoteok` | Remote OK | Latest ~100 jobs, salary on many |
| `jobicy` | Jobicy | Last 7 days; keywords are searched server-side; salary on many |
| `arbeitnow` | Arbeitnow | Only jobs flagged remote; Europe-heavy |
| `weworkremotely` | We Work Remotely | Main feed plus the ten category feeds |

Not included: Remotive and Himalayas, whose terms do not allow passing their listings on to third parties.

Every item carries `source` and the original job `url` so the board can be credited and linked. **If you publish these jobs anywhere, name the board as the source and link to the `url`** (Remote OK, Jobicy, Arbeitnow and We Work Remotely ask for this). Do not use the Remote OK logo.

### Input

```json
{
  "sources": ["remoteok", "jobicy", "arbeitnow", "weworkremotely"],
  "keywords": ["python", "data engineer"],
  "categories": [],
  "locations": ["worldwide", "usa"],
  "postedWithinDays": 7,
  "maxJobs": 100
}
```

| Field | What it does |
|---|---|
| `sources` | Boards to read. Empty plus any keyword, category or location means all four. |
| `keywords` | Keep jobs whose title, tags, category or description contains any keyword. |
| `categories` | Keep jobs whose category or tags contain any of these words (design, sales, devops...). |
| `locations` | Keep jobs open to candidates in these places. `worldwide`, `usa` and `europe` also match common variants (anywhere, United States, EMEA, main European countries); any other text is matched against the job's location. A job with no stated location counts as worldwide. |
| `postedWithinDays` | Only jobs published in the last N days. |
| `maxJobs` | Total cap, newest first (default 100). This is also your cost cap. |
| `requestDelaySeconds` | Pause between requests to the same board (default 1). |
| `proxyConfiguration` | Optional, off by default. |

**An input with no `sources`, `keywords`, `categories` or `locations` runs a small built-in example: the 5 newest jobs across all four boards (5 x $0.001 = $0.005), and the status message says so.** Set at least one of those fields for a real run.

### Output

```json
{
  "jobId": "jobicy-152824",
  "source": "jobicy",
  "url": "https://jobicy.com/jobs/152824-senior-staff-machine-learning-data-scientist",
  "title": "Senior/Staff Machine Learning Data Scientist",
  "company": "Bayesian Health",
  "companyLogo": "https://jobicy.com/data/.../f74593d8-221.png",
  "location": "USA",
  "isRemote": true,
  "employmentType": "full_time",
  "category": "Data Science & Analytics",
  "tags": ["Data Science & Analytics"],
  "salaryMin": null,
  "salaryMax": null,
  "salaryCurrency": null,
  "salaryPeriod": null,
  "postedAt": "2026-10-09T02:55:12+00:00",
  "description": "Senior/Staff Machine Learning Data Scientist\nIn Brief\n- ...",
  "applyUrl": "https://jobicy.com/jobs/152824-senior-staff-machine-learning-data-scientist",
  "scrapedAt": "2026-10-09T10:14:04+00:00",
  "input": {"keywords": ["python"], "maxJobs": 20}
}
```

`employmentType` is one of `full_time`, `part_time`, `contract`, `internship`, `temporary`, `other` (or null). `salaryPeriod` is `year`, `month`, `week`, `day` or `hour`. Salary fields are null where the board shows none (Arbeitnow and We Work Remotely publish none). `postedAt` is UTC ISO 8601. `description` is plain text.

The same job posted on two boards (same company and title, ignoring case and punctuation) is returned once, the newest copy.

### Pricing

Pay per event: **$0.001 per job returned** (event `job`). Nothing for runs that return nothing. Prices are final.

Example: 2,000 jobs = 2,000 x $0.001 = **$2.00**. A daily run capped at `maxJobs: 200` costs at most $0.20 a day.

### Use it from n8n, Make, Zapier or an AI agent

Actor ID: `datagleaner/remote-jobs-scraper`

Minimal input:

```
{"sources": ["remoteok", "jobicy"], "keywords": ["python"], "maxJobs": 20}
```

Each tool below runs this Actor with your own Apify API token.

- **n8n:** add the **Apify** node (`@apify/n8n-nodes-apify`). On n8n Cloud you install it from the community node registry. Choose **Run an Actor and get dataset**, set Actor to `datagleaner/remote-jobs-scraper` and paste the input above.
- **Make:** use the Apify app's **Run an Actor** module, then **Get Dataset Items** to read the results. **Watch Actor Runs** can trigger a scenario when a run finishes.
- **Zapier:** use the Apify action **Run Actor**, then the search **Fetch dataset items**. The trigger **Finished Actor run** starts a Zap when a run ends.
- **AI agents (MCP):** connect to `https://mcp.apify.com/?tools=datagleaner/remote-jobs-scraper`. Without a token, an agent can still find Actors with the `search-actors` tool, but running this one needs your Apify account. In Claude Code:

  ```
    claude mcp add --transport http apify "https://mcp.apify.com/?tools=datagleaner/remote-jobs-scraper"
  ```

  Then run `/mcp` to sign in to Apify in your browser. Then ask in plain language, for example: "Use the Remote Jobs scraper to find 30 remote Python jobs posted this week, and list the ones that show a salary."
- **LangChain (Python):**

```python
## pip install langchain-apify, then set APIFY_TOKEN in your environment
import json
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("datagleaner/remote-jobs-scraper")
result = tool.invoke({"run_input": json.loads('{"sources": ["remoteok", "jobicy"], "keywords": ["python"], "maxJobs": 20}')})
```

### Limits

- Each board's feed is a recent window, not its full archive: Remote OK about 100 jobs, Jobicy the last 7 days, Arbeitnow the latest ~1,000 listings (remote ones kept), We Work Remotely about 400 across its feeds. For a keyword, you get the matches inside those windows.
- Each feed is fetched once per run. Do not schedule runs more often than hourly; the boards ask for low-frequency use.
- Descriptions are the board's text; some contain the original language of the posting.

### FAQ

**Does it need a login or API key?** No. It reads public feeds.

**Why did a source return nothing?** The summary in the run's `SUMMARY` record lists each source with its status. A board can be down or rate-limiting; the other boards still return results.

**How do I get only worldwide jobs?** `"locations": ["worldwide"]`.

**Can I get salary for every job?** Only where the board publishes it (Remote OK and Jobicy).

### Responsible use

Only public job-board data is collected. Job listings name companies, not applicants, but if you combine the output with personal data you are responsible for complying with the laws that apply to you. Credit the original board and link to the job when you display listings, and do not submit these listings to other job aggregators against the boards' terms.

# Actor input Schema

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

Boards to read. If you leave this empty but set keywords, categories or locations, all four boards are read.

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

Return jobs whose title, tags, category or description contains any of these words (case-insensitive), for example python or product manager. Leave empty for all jobs.

## `categories` (type: `array`):

Optional. Keep jobs whose category or tags contain any of these words, for example design, sales, devops, customer support. Category names differ per board, so a word match is used.

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

Optional. Keep jobs open to candidates in these places. Text is matched against the job's location. The words worldwide, usa and europe also match common variants (anywhere, United States, EMEA, the main European countries). Jobs with no stated location count as worldwide.

## `postedWithinDays` (type: `integer`):

Optional. Only jobs published in the last N days. 0 or empty means no date limit. Some boards only expose their latest 7 days or so.

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

Upper bound on jobs returned in total, newest first. Each returned job is billed, so this is also your cost cap.

## `requestDelaySeconds` (type: `number`):

Base pause between requests to the same board; the actual pause is randomised up to 1.4x. Raise it if a board answers with rate limits (HTTP 429).

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

Optional. The default is no proxy, which works from Apify's servers.

## Actor input object example

```json
{
  "sources": [
    "remoteok",
    "jobicy",
    "arbeitnow",
    "weworkremotely"
  ],
  "keywords": [
    "python"
  ],
  "maxJobs": 100,
  "requestDelaySeconds": 1,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (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 = {
    "sources": [
        "remoteok",
        "jobicy",
        "arbeitnow",
        "weworkremotely"
    ],
    "keywords": [
        "python"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("datagleaner/remote-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 = {
    "sources": [
        "remoteok",
        "jobicy",
        "arbeitnow",
        "weworkremotely",
    ],
    "keywords": ["python"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("datagleaner/remote-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 '{
  "sources": [
    "remoteok",
    "jobicy",
    "arbeitnow",
    "weworkremotely"
  ],
  "keywords": [
    "python"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call datagleaner/remote-jobs-scraper --silent --output-dataset

```

## MCP server setup

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