# Remote Jobs Scraper (Himalayas, Remote OK, We Work Remotely) (`juliob.rangel/remote-jobs-scraper-fast`) Actor

Search remote job boards by keyword and get one clean table of jobs: title, company, salary range, location limits, seniority, tags, posted date, link and full description. Sources: Himalayas, Remote OK and We Work Remotely.

- **URL**: https://apify.com/juliob.rangel/remote-jobs-scraper-fast.md
- **Developed by:** [Julio Barcellos Rangel](https://apify.com/juliob.rangel) (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 $0.70 / 1,000 job scrapeds

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 Scraper (Himalayas, Remote OK, We Work Remotely)

Remote Jobs Scraper searches three remote job boards at once (Himalayas, Remote OK and We Work Remotely) and returns one clean table of remote jobs: title, company, salary range, where you can work from, seniority, tags, posted date, link and the full description as plain text. It is built for job seekers, recruiters, job-alert newsletters and anyone who wants to export remote job listings to Excel, CSV or JSON without copying them by hand. No login and no API keys are needed.

### What does Remote Jobs Scraper do?

You give it one or more keywords (for example `python`, `product designer` or `customer support`) and pick the job boards. For each keyword and each board, the scraper collects the matching jobs and turns them into the same set of fields, so jobs from different boards sit side by side in one dataset.

How each board is searched:

- **Himalayas**: the scraper uses the Himalayas job search for your keyword and pages through the results until it reaches your limit. With no keyword, it pages through the newest Himalayas jobs.
- **Remote OK**: the scraper reads the Remote OK job feed and the feed for the tag that matches your keyword (for example `product designer` becomes the tag `product-designer`), then keeps the jobs whose title, company, tags or description contain the keyword.
- **We Work Remotely**: the scraper reads the We Work Remotely jobs feed and keeps the jobs whose title, company, tags or description contain the keyword.

Leave the keyword list empty to get the newest jobs from each board instead of a search. Every job links back to its page on the original board, and descriptions are converted from HTML to readable plain text (list items become lines that start with "- ").

### What data can you extract?

Each job is one row with these fields. Fields that a board does not provide are `null` (or an empty list).

| Field | What it means | Example |
|---|---|---|
| `keyword` | The keyword that found this job (`null` when you searched without keywords) | `python` |
| `source` | Job board the job comes from | `Remote OK` |
| `title` | Job title | `Senior React Full stack Developer` |
| `company` | Company name | `Lemon.io` |
| `companyLogo` | Company logo image URL, when the board gives one | `https://cdn-images.himalayas.app/7q73…` |
| `url` | Link to the job on the original board | `https://remoteOK.com/remote-jobs/remote-senior-react-full-stack-developer-lemon-io-1137475` |
| `applyUrl` | Application link (falls back to `url`) | `https://remoteOK.com/remote-jobs/…` |
| `locations` | Countries or regions you can work from, as listed by the board | `["United States"]`, `["USA Only"]` |
| `employmentType` | Type of contract (Himalayas and We Work Remotely) | `Full Time`, `Contractor`, `Full-Time` |
| `seniority` | Seniority levels (Himalayas only) | `["Senior"]` |
| `salaryMin` | Lower end of the salary range | `80000` |
| `salaryMax` | Upper end of the salary range | `200000` |
| `salaryCurrency` | Salary currency | `USD`, `EUR` |
| `salaryPeriod` | Salary period, filled only when a salary is given | `annual` |
| `tags` | Categories and skills listed for the job | `["python", "aws", "react"]` |
| `postedAt` | Date the job was posted (ISO 8601) | `2026-10-09T13:09:18.000Z` |
| `expiresAt` | Date the listing expires (Himalayas only) | `2026-10-22T11:19:53.000Z` |
| `summary` | Short excerpt of the job (Himalayas only) | `Are you a talented Senior Developer looking for a remote job…` |
| `description` | Full job description as plain text (only when **Include full description** is on) | `Are you a talented Senior Developer…` |
| `scrapedAt` | When the scraper collected the job (ISO 8601) | `2026-10-12T20:29:50.169Z` |
| `error` | Only on error rows: why a board could not be loaded | `Could not load remoteok.com` |

What each board fills in:

| Board | Salary | Seniority | Employment type | Summary and expiry |
|---|---|---|---|---|
| Himalayas | When the company publishes it, in the posted currency | Yes | Yes | Yes |
| Remote OK | When the job has one; always read as USD per year | No | No | No |
| We Work Remotely | No | No | Yes | No |

### How to use Remote Jobs Scraper

1. Open Remote Jobs Scraper in Apify Console.
2. Type your keywords in **Keywords**, one per line (for example `python`, `data engineer`, `customer support`). Clear the list if you want the newest jobs with no search.
3. In **Job boards**, keep all three boards or pick only the ones you want.
4. Set **Max jobs per board and keyword** (default 50).
5. Turn **Include full description** off if you only need the table fields and want smaller rows.
6. Click **Start** and wait for the run to finish.
7. Open the **Output** tab and export the jobs as JSON, CSV, Excel or HTML, or connect the dataset to another tool.

To get new jobs every day, save the input as a task and add a schedule to it in Apify Console.

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `keywords` | list of text | `["python"]` | Job keywords. Each keyword is searched on every selected board. Leave the list empty (`[]`) to get the newest jobs instead. |
| `sources` | list | `["himalayas", "remoteok", "weworkremotely"]` | Which boards to search. Allowed values: `himalayas`, `remoteok`, `weworkremotely`. Empty means all three. |
| `maxJobsPerSource` | integer | `50` | Maximum jobs for each board and keyword, from 1 to 5,000. Remote OK and We Work Remotely only list their latest jobs (around 100), so they usually return fewer. |
| `includeDescription` | true/false | `true` | Adds the full job description as plain text in `description`. |
| `proxy` | object | `{ "useApifyProxy": true }` | Apify Proxy settings. The default works for most runs. |

The limit applies to each board and keyword separately. Three keywords on three boards with `maxJobsPerSource: 50` can return up to 450 jobs.

Example input:

```json
{
  "keywords": ["python", "product designer"],
  "sources": ["himalayas", "remoteok", "weworkremotely"],
  "maxJobsPerSource": 100,
  "includeDescription": true,
  "proxy": { "useApifyProxy": true }
}
```

Note for API users: if you leave `keywords` out of the input, the default `["python"]` is used. Send `"keywords": []` to get the newest jobs without a keyword.

### Output example

One real job from a recent run (the description is trimmed):

```json
{
  "keyword": "python",
  "source": "Remote OK",
  "title": "Senior React Full stack Developer",
  "company": "Lemon.io",
  "companyLogo": null,
  "url": "https://remoteOK.com/remote-jobs/remote-senior-react-full-stack-developer-lemon-io-1137475",
  "applyUrl": "https://remoteOK.com/remote-jobs/remote-senior-react-full-stack-developer-lemon-io-1137475",
  "locations": [],
  "employmentType": null,
  "seniority": [],
  "salaryMin": 80000,
  "salaryMax": 200000,
  "salaryCurrency": "USD",
  "salaryPeriod": "annual",
  "tags": ["dev", "engineer", "remote", "python", "aws", "gcp", "javascript", "react", "node", "ruby", "typescript", "full time", "full stack"],
  "postedAt": "2026-10-09T13:09:18.000Z",
  "expiresAt": null,
  "summary": null,
  "description": "Are you a talented Senior Developer looking for a remote job that lets you show your skills and get decent compensation? Look no further than Lemon.io…",
  "scrapedAt": "2026-10-12T20:29:50.169Z"
}
```

### How much does it cost?

Remote Jobs Scraper uses pay-per-event pricing. You pay **$1.00 per 1,000 jobs** ($0.001 per job) on the Free plan. Apify platform usage is included in the price, so the job count is the only thing that sets the cost.

| Plan | Price per 1,000 jobs |
|---|---|
| Free | $1.00 |
| Bronze (-10%) | $0.90 |
| Silver (-20%) | $0.80 |
| Gold and higher (-30%) | $0.70 |

Worked examples on the Free plan:

- 1 keyword, 3 boards, 50 jobs each: up to 150 jobs = **$0.15**
- 10 keywords, 3 boards, 100 jobs each: up to 3,000 jobs = **$3.00**
- 5 keywords on Himalayas only, 2,000 jobs each: up to 10,000 jobs = **$10.00**

What you are not charged for:

- Error rows, for example when a board could not be loaded after several tries.
- Jobs skipped as duplicates: the same job URL found twice for the same keyword is returned only once.
- Boards that return no matching jobs.

### Use cases

- **Job alerts and newsletters**: collect new Python, design, support or marketing jobs every day and send them to your readers.
- **Job search**: pull every remote job for your skills from three boards into one spreadsheet, then filter by salary, seniority or country.
- **Salary research**: compare published salary ranges by skill, seniority and currency.
- **Hiring-market research**: count how many companies are hiring remotely for a skill and how that changes over time.
- **Lead generation**: build a list of companies that are hiring remote staff right now.
- **Recruiting**: watch which companies post roles similar to the ones you fill.
- **Job board aggregation**: feed a niche remote job board or a Slack or Discord channel. Please credit the original board when you publish jobs.

### Tips and limits

- **Remote OK and We Work Remotely return fewer jobs.** Their feeds only contain the latest jobs (around 100), so a high limit mostly affects Himalayas. Himalayas search pages through up to 250 result pages.
- **Keyword matching** on Remote OK and We Work Remotely is a simple text match: the keyword must appear in the title, company, tags or description. A short keyword like `go` can match many unrelated jobs, so prefer specific phrases such as `golang`.
- **Salary is only there when the board publishes it.** We Work Remotely jobs never have salary fields. Remote OK salaries are read as USD per year. On Himalayas, `salaryCurrency` can be filled even when `salaryMin` and `salaryMax` are empty.
- **Locations are free text from each board.** Himalayas lists countries, Remote OK gives one location string, and We Work Remotely gives region, country and state values such as `USA Only`. An empty list means the board gave no location limit.
- **The same job can appear on more than one board.** In the run used for the example above, the Lemon.io job came back from both Himalayas and Remote OK. Each board's row is kept, with its own `url`.
- **The same job can appear once per keyword.** Duplicates are removed per keyword, so if two of your keywords match the same job, you get it twice with a different `keyword` value.
- **Error rows**: if a board does not answer after five tries, the run continues with the other boards and adds a row with `keyword`, `source` and `error` (for example `Could not load remoteok.com`). Error rows are free.
- **Smaller rows**: switch off `includeDescription` to drop the long `description` text. Keyword matching still uses the description.

### Use it from the API, Python or JavaScript

You can start the scraper and read the jobs with the official Apify clients. Replace `YOUR_TOKEN` with your Apify API token.

JavaScript (Node.js):

```javascript
const { ApifyClient } = require('apify-client');

const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const input = { keywords: ['python'], maxJobsPerSource: 100 };

const run = await client.actor('juliob.rangel/remote-jobs-scraper-fast').call(input);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

Python:

```python
from apify_client import ApifyClient

client = ApifyClient('YOUR_TOKEN')
input = {'keywords': ['python'], 'maxJobsPerSource': 100}

run = client.actor('juliob.rangel/remote-jobs-scraper-fast').call(run_input=input)
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

The scraper also works with Make, Zapier and n8n, can export results to Google Sheets, can call your webhook when a run finishes, and can be used by AI agents through the Apify MCP server.

### FAQ

**Do I need a login, cookies or API keys for the job boards?**
No. The scraper reads public job listings from Himalayas, Remote OK and We Work Remotely. You only need an Apify account.

**Can I export the jobs to Excel or CSV?**
Yes. After the run, open the Output tab and download the dataset as Excel, CSV, JSON or HTML. You can also send it to Google Sheets.

**How many jobs can I get?**
Up to 5,000 per board and keyword. In practice Remote OK and We Work Remotely return at most their latest jobs (around 100), while Himalayas can return thousands for broad keywords.

**Can I get only jobs with a salary?**
The scraper returns all matching jobs. Filter the `salaryMin` or `salaryMax` columns in your spreadsheet, or in your code, to keep only jobs with a published salary.

**How do I get only new jobs every day?**
Schedule the scraper daily and compare `url` with what you already have, or filter on `postedAt`.

**Is it legal to scrape remote job boards?**
The scraper only collects publicly available job listings. You are responsible for complying with each site's terms and with privacy laws such as GDPR and LGPD. Job posts can contain personal data such as recruiter names or emails; you need a legitimate reason to store or use it. Please credit the source board when you republish jobs.

**Why did I get a row with an `error` field?**
One job board could not be loaded after five tries, usually a temporary problem on the board's side. The other boards still run. Error rows are not charged; run the scraper again later for that board.

### Related scrapers

- [Career Site Jobs: Greenhouse, Lever, Ashby, Workable](https://apify.com/juliob.rangel/career-site-jobs)
- [LinkedIn Jobs Scraper (No Login, Fast)](https://apify.com/juliob.rangel/linkedin-jobs-fast)
- [LinkedIn Company Scraper (No Login, Fast)](https://apify.com/juliob.rangel/linkedin-company-fast)
- [Website Contact Details Scraper (Emails, Phones, Socials)](https://apify.com/juliob.rangel/website-contact-details-scraper)

***

## Vagas Remotas (PT-BR)

Pesquise vagas remotas em Himalayas, Remote OK e We Work Remotely de uma vez e receba título, empresa, salário, países aceitos, senioridade, tags, data, link e descrição. Exporte para Excel, CSV ou JSON. Você paga só por vaga retornada.

# Actor input Schema

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

Job keywords, e.g. python, product designer, customer support. Leave empty to get the newest jobs.

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

Which boards to search. Leave empty for all.

## `maxJobsPerSource` (type: `integer`):

Remote OK and We Work Remotely only list their latest ~100 jobs, so they return fewer.

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

Add the full job description as plain text.

## `proxy` (type: `object`):

Apify Proxy settings.

## Actor input object example

```json
{
  "keywords": [
    "python"
  ],
  "sources": [
    "himalayas",
    "remoteok",
    "weworkremotely"
  ],
  "maxJobsPerSource": 50,
  "includeDescription": true,
  "proxy": {
    "useApifyProxy": true
  }
}
```

# 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"
    ],
    "maxJobsPerSource": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("juliob.rangel/remote-jobs-scraper-fast").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"],
    "maxJobsPerSource": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("juliob.rangel/remote-jobs-scraper-fast").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"
  ],
  "maxJobsPerSource": 50
}' |
apify call juliob.rangel/remote-jobs-scraper-fast --silent --output-dataset

```

## MCP server setup

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

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/mUpnSeWFGz2WN44VY/builds/S5hckDMmLB8lzFRFB/openapi.json
