# Remote Jobs API: Remote OK, WWR & Himalayas (`norespi/remote-jobs-aggregator`) Actor

Scrapes remote jobs from Remote OK, We Work Remotely and Himalayas into one deduplicated dataset. Filter by keyword, country, timezone, salary and contract type. Public APIs only, no login. $1.50 per 1,000 jobs.

- **URL**: https://apify.com/norespi/remote-jobs-aggregator.md
- **Developed by:** [Gabriel Jossic](https://apify.com/norespi) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.50 / 1,000 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.

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 API** that pulls fresh remote job listings from **Remote OK**, **We Work Remotely** and **Himalayas** in one run and returns **one clean, deduplicated dataset**: same fields for every board, newest jobs first, the source credited on every row.

Filter by **keyword, category, country, timezone, minimum salary and contract type**. Export to **JSON, CSV, Excel or Google Sheets**, call it from the **Apify API**, schedule it daily, or let an **AI agent** use it through MCP.

No login, no API key, no browser. The Actor only reads the boards' official public APIs and RSS feed, so runs are fast and cheap: the prefilled input finishes in a few seconds.

### What data does the Remote Jobs API return?

| Field | Example |
|---|---|
| `title` | Back-end Developer – Python |
| `company`, `companyUrl`, `companyProfileUrl` | Company name and links |
| `locations`, `locationText`, `timezones` | Where the job is open (countries, regions, UTC offsets) |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod` | Parsed salary, when the board publishes it |
| `employmentType`, `seniority` | `full-time`, `contract`… / `Entry-level`, `Senior`… |
| `categories`, `tags` | Role category and skills |
| `postedAt` | ISO 8601 date |
| `url`, `applyUrl` | Original job page and apply link |
| `source`, `sourceName`, `attribution` | Which board it came from, and how to credit it |
| `alsoListedOn` | Other boards where the same job was found |
| `description` | Optional plain-text description |

Fields a board does not publish are `null` or `[]`. Nothing is guessed or invented.

### How to use the Remote Jobs API

1. Click **Try for free**.
2. Type a few **keywords** (e.g. `react`, `devops`, `product designer`), and optionally a **country**, **timezone** or **minimum salary**.
3. Click **Start**. Download the jobs from the **Output** tab as JSON, CSV or Excel, or fetch them through the API.

Input example:

```json
{
  "keywords": ["react", "typescript"],
  "countries": ["Canada"],
  "minSalary": 80000,
  "maxAgeDays": 7,
  "maxResults": 100
}
```

#### Input fields

| Field | Default | What it does |
|---|---|---|
| `keywords` | `["developer"]` | Keep a job if its title, company, category or tags contain one of these words (whole words, case-insensitive). Empty = all recent jobs. |
| `excludeKeywords` | none | Drop jobs whose title or company contains one of these words (e.g. `senior`, `intern`). |
| `categories` | none | Keep jobs whose category or tags match, e.g. `engineering`, `design`, `marketing`. |
| `countries` | none | Keep jobs open to these countries or regions (e.g. `Canada`, `Europe`). Worldwide jobs are always kept. |
| `timezones` | none | UTC offsets you can work in, e.g. `-5`, `UTC+1`, `+5:30`. |
| `includeUnspecifiedLocation` | `true` | With a country or timezone filter, also keep jobs whose board gives no location data. |
| `minSalary` | none | Keep only jobs with a published salary whose annual maximum is at least this amount. Currencies are not converted. |
| `employmentTypes` | none | e.g. `full-time`, `contract`, `part-time`. |
| `maxAgeDays` | none | Keep only jobs posted in the last N days. |
| `sources` | all 3 | `himalayas`, `remoteok`, `weworkremotely`. |
| `maxResults` | 5 (prefilled) | Maximum jobs saved, after deduplication, newest first. |
| `includeDescription` | `false` | Add the plain-text description. |
| `proxyConfiguration` | none | Optional Apify Proxy. Usually not needed. |

### Output example

```json
{
  "title": "Back-end Developer intern - Python",
  "company": "Workforce Development Solutions",
  "companySlug": "workforce-development-solutions",
  "companyProfileUrl": "https://himalayas.app/companies/workforce-development-solutions",
  "locations": ["United States"],
  "timezones": [-10, -9, -8, -7, -6, -5],
  "locationText": "United States",
  "salaryMin": null,
  "salaryMax": null,
  "salaryCurrency": null,
  "employmentType": "internship",
  "seniority": ["Entry-level"],
  "categories": ["developer"],
  "tags": ["backend engineer", "python developer"],
  "postedAt": "2026-10-12T04:34:27.000Z",
  "url": "https://himalayas.app/companies/workforce-development-solutions/jobs/back-end-developer-intern-python",
  "applyUrl": "https://himalayas.app/companies/workforce-development-solutions/jobs/back-end-developer-intern-python",
  "source": "himalayas",
  "sourceName": "Himalayas",
  "attribution": "Job listing from Himalayas (himalayas.app). Link back to the job URL when you display it.",
  "alsoListedOn": []
}
```

A real record from a run on 2026-10-12 (some fields shortened). A `RUN_SUMMARY` record in the key-value store gives the number of jobs saved, duplicates merged and any board that failed.

### How much does it cost to get remote jobs?

**$1.50 per 1,000 jobs.** You pay only for jobs saved to the dataset; compute is included.

| You get | You pay |
|---|---|
| 5 jobs (prefilled input) | $0.0075 |
| 100 jobs | $0.15 |
| 1,000 jobs | $1.50 |

Set `maxResults` to cap a run. Apify's free plan credit covers thousands of jobs a month.

### How to get only new remote jobs every day

Create a **schedule** in Apify (e.g. every morning) with `maxAgeDays: 1`. Each run returns only the last day's jobs. Send them to **Slack, Google Sheets, email, Zapier, Make, n8n** or a **webhook** with Apify integrations.

### Use the Remote Jobs API with AI agents (MCP)

Claude, Cursor and other MCP clients can call this Actor through the official Apify MCP server. Add `NORESPI/remote-jobs-aggregator` to your Apify MCP configuration, then ask things like "find remote Rust jobs open to Canada posted this week".

### Use cases

- **Job boards and newsletters**: a weekly "remote React / DevOps / design jobs" section from 3 boards without maintaining 3 scrapers.
- **Job alerts**: daily new jobs to Slack, Sheets or a webhook.
- **Market research**: which companies hire remotely, for which roles, at what salary, open to which countries and timezones.
- **Sales and recruiting research (company level)**: companies hiring for a given stack right now.
- **Job seekers**: one list of remote jobs you can actually take from your country and timezone, above your salary floor.

### Source attribution (required if you republish)

Each board allows reuse only with credit. Every row carries `sourceName`, `url` and `attribution`. If you display these jobs publicly:

- **Himalayas**: link to the job URL and name Himalayas as the source. Do not pass the data on to Jooble, Google Jobs or LinkedIn.
- **Remote OK**: mention "Remote OK" and link to the job with a normal (followed, not `nofollow`) link. Do not use the Remote OK logo.
- **We Work Remotely**: link to the job URL and name We Work Remotely.

### Limits (stated up front)

- **3 boards only.** Remotive is not included on purpose: its terms forbid redistributing its jobs. We only add boards whose terms allow reuse.
- Remote OK's API returns its ~100 latest jobs and We Work Remotely's feed ~90. Himalayas is paginated, so most results come from Himalayas.
- Salaries appear only when the board publishes them (rare on Remote OK). Currencies are not converted.
- Remote OK does not publish contract types, so its jobs are dropped when `employmentTypes` is set. Only Himalayas publishes timezones.
- Deduplication matches normalized company + title. The same job with a very different title on two boards stays as two rows.

### Privacy

Company-level job data only. The Actor never outputs recruiter names, email addresses, phone numbers or personal profile links (LinkedIn, X/Twitter, Calendly, Telegram, WhatsApp…): they are removed from descriptions and URL fields.

### FAQ

#### Do I need an account on these job boards?

No. Only their public APIs and feeds are used.

#### How fresh are the jobs?

Live at run time, sorted newest first.

#### Can I export remote jobs to CSV, Excel or Google Sheets?

Yes, from the Output tab, the API, or the Google Sheets integration.

#### Is there a free remote jobs API?

The boards' own feeds are free but each has its own format and limits. This Actor merges them into one schema for $1.50 per 1,000 jobs, and Apify's free plan credit covers small volumes.

#### Why not more boards?

We only add boards whose terms allow reuse. Tell us which board you need in the **Issues** tab.

#### Is this Actor affiliated with Remote OK, We Work Remotely or Himalayas?

No. It is an independent tool that reads their public feeds and credits them on every row.

### Other job data Actors by NORESPI

| Actor | What it does | Price |
|---|---|---|
| [Career Page Jobs API](https://apify.com/NORESPI/ats-jobs-by-company) | Every open job of a list of companies, from Greenhouse, Lever, Ashby, Workable and 4 more ATS, plus a free hiring signal per company | $1 / 1,000 jobs |
| [HN Who Is Hiring Jobs API](https://apify.com/NORESPI/hn-who-is-hiring) | The monthly Hacker News "Who is hiring?" thread as structured jobs: salary, remote, visa, stack | $2 / 1,000 jobs |

Questions, bugs or a board to add: open an issue in the **Issues** tab.

# Actor input Schema

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

A job is kept if its title, company, category or tags contain at least one of these words (case-insensitive, whole words). Leave empty to get all recent jobs.

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

Jobs whose title or company contains one of these words are dropped (e.g. senior, intern).

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

Keep only jobs whose category or tags contain one of these words, e.g. engineering, design, marketing, sales, customer support, devops.

## `countries` (type: `array`):

Keep jobs open to one of these countries or regions (e.g. Canada, United States, Europe). Jobs marked Worldwide/Anywhere are always kept.

## `timezones` (type: `array`):

UTC offsets you can work in, e.g. -5, UTC+1, +5:30. Only Himalayas publishes timezone restrictions; jobs without timezone data are kept unless 'Keep jobs with unspecified location' is off.

## `includeUnspecifiedLocation` (type: `boolean`):

When a country or timezone filter is set, keep jobs whose source gives no location or timezone information.

## `minSalary` (type: `integer`):

Keep only jobs with a published salary whose maximum (annualized: hourly ×2080, monthly ×12) is at least this amount. Currencies are not converted. Jobs without salary are excluded when this is set.

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

Keep only these contract types. Remote OK does not publish contract types, so its jobs are excluded when this filter is set.

## `maxAgeDays` (type: `integer`):

Keep only jobs posted within this many days.

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

Job boards to query. All by default.

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

Maximum number of jobs in the dataset (after deduplication, newest first).

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

Add the plain-text job description (e-mail addresses and personal profile links are removed).

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

Optional. The sources are public APIs/feeds, a proxy is usually not needed.

## Actor input object example

```json
{
  "keywords": [
    "developer"
  ],
  "includeUnspecifiedLocation": true,
  "sources": [
    "himalayas",
    "remoteok",
    "weworkremotely"
  ],
  "maxResults": 5,
  "includeDescription": false,
  "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 = {
    "keywords": [
        "developer"
    ],
    "maxResults": 5,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("norespi/remote-jobs-aggregator").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": ["developer"],
    "maxResults": 5,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("norespi/remote-jobs-aggregator").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": [
    "developer"
  ],
  "maxResults": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call norespi/remote-jobs-aggregator --silent --output-dataset

```

## MCP server setup

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

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/H5Pa9xR8UHApO5Aj5/builds/yflj1La4slJP3nLgW/openapi.json
