# Remote Jobs Search: RemoteOK, WWR, Himalayas and More Boards (`accountable_eel/remote-jobs-unified-search`) Actor

Search six remote job boards in one run: Remote OK, We Work Remotely, Himalayas, Working Nomads, Jobgether and Y Combinator. One deduplicated row per job with salary, tags and link, plus a new-jobs-only monitoring mode.

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

## Pricing

from $1.50 / 1,000 job returneds

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?

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 Search: RemoteOK, WWR, Himalayas and More Boards

**Search six remote job boards in one run and get one clean, deduplicated list of jobs.**
Remote OK, We Work Remotely, Himalayas, Working Nomads, Jobgether and Y Combinator's Work at a Startup are searched together for your keywords. A job posted on several boards comes back once, with the other boards named. Each row has the title, company, location, salary when stated, skill tags, posting date and the link to the job page.

**Who uses it.** Job-board and newsletter builders who need a daily feed of new remote jobs, recruiters and agencies tracking who is hiring remotely for a skill, and job seekers or AI agents that want one search instead of six. Turn on monitoring and schedule it to get only the jobs that are new since your last run.

**No login, no API key, no proxy.** Every source is a public feed or a documented public API.

### How to use

1. **In the Apify Console.** Open the actor page and click **Start** — the `keywords` field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
2. **Via the API.** Call it directly with a POST request — no Console needed once you have an API token:
   ```bash
   curl "https://api.apify.com/v2/acts/accountable_eel~remote-jobs-unified-search/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"keywords":["python"]}'
   ```
3. **On a schedule.** Save this actor as an Apify **Task** with the input you want, then add a **Schedule** (hourly, daily, weekly) so it runs on its own — no server of your own required.

### Input

```json
{
  "keywords": [
    "python"
  ]
}
```

One keyword or phrase per line, for example python, product designer or customer support. A job matching any one of them is returned. Leave empty to get the newest remote jobs from every board. Accepted formats: python, product designer, customer support.

One combined search runs per call, whatever the number of keywords. A job is returned when any one keyword matches.

| Field | What it does |
| --- | --- |
| `keywords` | Job titles, skills or company names. Empty = the newest remote jobs from every board. Up to 10. |
| `maxItems` | Most jobs to return (and pay for). Default 100, up to 1,000. The newest are kept. |
| `boards` | Optional. Narrow the search to some boards, by name. Empty = all six. |
| `postedWithinDays` | Optional. Only jobs posted in the last N days. |
| `titleMatchOnly` | On = the keyword must be in the job title itself. |
| `onlyNewSinceLastRun` | Monitoring: only return and bill jobs not seen on your earlier runs. |
| `deltaName` | Optional name for a monitoring watchlist. |

**How matching works.** On Working Nomads, We Work Remotely, Remote OK and Y Combinator the keyword is matched against the title, company, category and skill tags. Short keywords match whole words only, so `java` does not return JavaScript jobs. Himalayas and Jobgether run your keyword through their own search, which also reads the job description, and their newest matches are returned. Turn on `titleMatchOnly` when you want only jobs with the keyword in the title, on every board.

**How much each board holds.** The boards publish their current listings, not an archive: about 100 jobs on Remote OK, 90 on We Work Remotely, 50 on Working Nomads, the 30 newest engineering jobs (remote ones only) on Y Combinator, and the top 20 (Himalayas) and newest 25 (Jobgether) matches per keyword. A narrow keyword returns tens of jobs per run, not thousands. Schedule the actor to build up a history.

### Output

One row per job. The headline fields of three rows from a real `python` search:

| source | alsoListedOn | title | company | location | salaryText | postedAt | url |
| --- | --- | --- | --- | --- | --- | --- | --- |
| Remote OK | Working Nomads, We Work Remotely, Himalayas | Senior React Full stack Developer | Lemon.io | Anywhere in the World | USD 80,000-200,000 | 2026-10-09 | https://remoteok.com/remote-jobs/... |
| Jobgether | | Software Development Engineer in Test II (Python) | Akamai Technologies | North America, Canada | CAD 82,100-147,900/year | 2026-10-10 | https://jobgether.com/offer/... |
| Himalayas | | Python Developer | AssetIntel | United States | | 2026-08-22 | https://himalayas.app/companies/... |

The first job was listed on four boards and is returned once; fields its Remote OK copy lacked (here the location) are filled from the other boards' copies.

Every column:

| query | found | status | searchSummary | jobCount | totalMatched | duplicatesMerged | truncated | boardsSearched | boardsFailed | monitorStatus | jobs | source | alsoListedOn | jobId | title | company | location | employmentType | seniority | salaryMin | salaryMax | salaryCurrency | salaryText | category | tags | postedAt | url | descriptionSnippet | matchedKeyword | isNew | firstSeenAt | scrapedAt |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| python | true | OK | <search run> | <jobs returned> | <jobs matched before the cap> | <duplicates merged> | <more jobs were available> | <boards searched> | <boards that did not answer> | <monitoring status> | \<all jobs (full list)> | <job board> | <also listed on> | <job id on the board> | <job title> | <company> | <location or region allowed> | <employment type> | <seniority> | <salary from> | <salary to> | <salary currency> | <salary as text> | <category> | <skills and tags> | <posted on> | <job page on the board> | \<description (first 300 characters)> | <keyword that matched> | \<is this job new?> | <first seen on a run> | 1970-01-01T00:00:00.000Z |

A search that matches nothing comes back as one row with `"found": false` and is never charged. Values a board does not publish are empty (`null`), never `0`: salary is stated on a minority of postings, and Y Combinator publishes no posting date. `boardsFailed` names any board that did not answer on a run; the other boards' jobs are still returned.

**Using Remote OK rows.** Remote OK asks anyone who republishes its listings to link back to the job's Remote OK URL (a normal followed link) and to name Remote OK as the source. Every row carries both (`url` and `source`), so keep them if you show these jobs on a site.

### Pricing

Pay-per-event. A flat per-run fee covers session/proxy warmup; you're billed
per item only when data is actually found and returned — see
`.actor/pay_per_event.json` for exact prices. A miss is never charged.

You pay per job returned. A search with no match, a monitoring run with nothing new, and the duplicate copies merged into one row cost nothing.

### Example runs

Paste any of these into the Input tab and press Start. All three return rows with no key, no token
and no account of your own beyond an Apify login.

**Python jobs across all six boards, newest 30.** The default shape.

```json
{
  "keywords": ["python"],
  "maxItems": 30
}
```

**Design jobs with the keyword in the title, posted in the last 14 days.**

```json
{
  "keywords": ["designer"],
  "titleMatchOnly": true,
  "postedWithinDays": 14,
  "maxItems": 50
}
```

**Daily alert for new customer support jobs.** Schedule it once a day: each run returns only jobs not seen before.

```json
{
  "keywords": ["customer support", "customer success"],
  "onlyNewSinceLastRun": true,
  "maxItems": 100
}
```

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

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

```bash
curl "https://api.apify.com/v2/acts/accountable_eel~remote-jobs-unified-search/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"keywords":["python"]}'
```

**n8n.** Add an HTTP Request node: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~remote-jobs-unified-search/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body Content Type `JSON`, JSON Body `{"keywords":["python"]}` (swap in an expression from an earlier node for a real value).

**Clay.** Add an "HTTP API" column: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~remote-jobs-unified-search/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body `{"keywords":["{{search}}"]}`, mapping the row's search into the `keywords` array.

**MCP.** In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "remote jobs scraper" — the agent will find and run this actor.

# Actor input Schema

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

One keyword or phrase per line, for example python, product designer or customer support. A job matching any one of them is returned. Leave empty to get the newest remote jobs from every board. Accepted formats: python, product designer, customer support. You're only charged for the ones we actually find — a miss costs nothing.

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

Up to 1,000. Caps how many jobs you get (and pay for) in one run. The newest jobs are kept.

## `testRun` (type: `boolean`):

Turn this on to test your input on a small sample before running the full list. Turn it off to process everything.

## `onlyFound` (type: `boolean`):

Only keep rows where something was actually found. Misses are always free, whether or not you show them here.

## `includeKeywords` (type: `array`):

Optional. Only keep results that mention at least one of these words (e.g. a job title, a city, a product name). Leave empty to keep everything.

## `excludeKeywords` (type: `array`):

Optional. Drop any result that mentions one of these words. Leave empty to skip nothing.

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

Optional. Stop the run once this many results have been found — useful for a quick, cheap sample. Leave blank for no limit.

## `boards` (type: `array`):

Optional. Leave empty to search all six. To narrow, list any of: Remote OK, We Work Remotely, Himalayas, Working Nomads, Jobgether, Y Combinator.

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

Optional. Only keep jobs posted within this many days. Y Combinator jobs publish no date and are left out when this is set.

## `titleMatchOnly` (type: `boolean`):

Off: a keyword may match the title, company, category or skill tags, and Himalayas and Jobgether use their own search. On: only jobs with a keyword in the title itself are returned, on every board.

## `onlyNewSinceLastRun` (type: `boolean`):

On: only jobs not seen on your previous runs are returned and charged for. Run it on a schedule as a remote job alert. Off: every matching job is returned every time.

## `deltaName` (type: `string`):

Optional. Name this search's monitoring memory so you can tell two schedules of this actor apart, or keep one memory across an input change. Leave empty to auto-derive one from your keywords and filters.

## `columns` (type: `array`):

Choose which pieces of information to include in each result row. All are included by default.

## `expandRows` (type: `boolean`):

When on, each job found gets its own row instead of being grouped under its search. You're still only charged once per search, no matter how many rows it produces.

## `maxConcurrency` (type: `integer`):

Parallel requests. Keep conservative — this target has no browser fallback, so getting blocked costs more than slow-and-steady.

## Actor input object example

```json
{
  "keywords": [
    "python"
  ],
  "maxItems": 100,
  "testRun": false,
  "onlyFound": false,
  "includeKeywords": [],
  "excludeKeywords": [],
  "boards": [],
  "titleMatchOnly": false,
  "onlyNewSinceLastRun": false,
  "deltaName": "",
  "columns": [
    "searchSummary",
    "jobCount",
    "totalMatched",
    "duplicatesMerged",
    "truncated",
    "boardsSearched",
    "boardsFailed",
    "monitorStatus",
    "jobs",
    "source",
    "alsoListedOn",
    "jobId",
    "title",
    "company",
    "location",
    "employmentType",
    "seniority",
    "salaryMin",
    "salaryMax",
    "salaryCurrency",
    "salaryText",
    "category",
    "tags",
    "postedAt",
    "url",
    "descriptionSnippet",
    "matchedKeyword",
    "isNew",
    "firstSeenAt"
  ],
  "expandRows": true,
  "maxConcurrency": 1
}
```

# 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 = {
    "keywords": [
        "python"
    ],
    "includeKeywords": [],
    "excludeKeywords": [],
    "boards": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("accountable_eel/remote-jobs-unified-search").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 = {
    "keywords": ["python"],
    "includeKeywords": [],
    "excludeKeywords": [],
    "boards": [],
}

# Run the Actor and wait for it to finish
run = client.actor("accountable_eel/remote-jobs-unified-search").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 '{
  "keywords": [
    "python"
  ],
  "includeKeywords": [],
  "excludeKeywords": [],
  "boards": []
}' |
apify call accountable_eel/remote-jobs-unified-search --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,accountable_eel/remote-jobs-unified-search"
        }
    }
}
```

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/eMohSWGqFbxdHEX4h/builds/a9ld69xtdDwFUSrI0/openapi.json
