# RemoteOK Jobs Scraper · Remote Roles, Salaries & Tags (`reapx/remoteok-jobs-scraper`) Actor

RemoteOK Jobs Scraper to scrape remote job listings from RemoteOK (remoteok.com). Extract remote jobs, tech positions, developer roles, salaries, hiring companies, tags, and apply links. Filter by skill tags, keywords, company name, location, and minimum salary.

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

## Pricing

from $1.10 / 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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

![reapX — public sources in, addressable records out](https://reapx.dev/reapx.gif)

## RemoteOK Jobs Scraper · Remote Roles, Salaries & Tags

RemoteOK Jobs Scraper to scrape remote job listings, tech positions, developer roles, salaries, hiring companies, and tags from RemoteOK (remoteok.com). Extract real-time remote job data and filter by skill tags, keywords, company name, location policy, and minimum salary range using the RemoteOK API. Export clean structured job data in JSON, CSV, or Excel.

> Maintained by **reapX**. Every row cites the Apify run that produced it — nothing is
> inferred, modelled or filled in, and a field absent from the source is absent from the row.
> The extracted archive for this source is browsable at
> [reapx.dev/data/remoteok-jobs-scraper/](https://reapx.dev/data/remoteok-jobs-scraper/) and mirrored as an open dataset on
> [Hugging Face](https://huggingface.co/datasets/reapxdev/remoteok-jobs-scraper) and
> [Kaggle](https://www.kaggle.com/datasets/reapxdev/remoteok-jobs-scraper). Questions: reapxdev@proton.me

### Scrape RemoteOK job listings by tag

**Tags** is the breadth control. Give it `python`, `golang`, `design`, `marketing`, `senior`, or any other RemoteOK tag, one per line. Each tag is fetched separately and the results are merged and deduplicated on job ID, so overlapping tags never produce duplicate rows.

Leave Tags empty and you get the whole current board.

### Filter RemoteOK jobs by salary

RemoteOK publishes a salary range on a minority of postings - on a 478-row sample taken while building this Actor, under 2% carried one. That is the board's reality, not a gap in the scraper, so every row carries a `hasSalary` flag and the Salaries view is built around it. **Segment on `hasSalary` before you average anything**, or your figures describe the small subset that discloses.

**Only jobs with a published salary** and **Minimum salary in USD** narrow to the disclosing subset directly.

### Filter RemoteOK jobs by keyword, company or verification

**Keyword filter** matches across title, company, tags and description. **Company filter** narrows to one employer. **Only verified employers** keeps postings RemoteOK has marked verified.

### Monitor new RemoteOK jobs

Schedule the Actor and deduplicate on `jobId`, which is permanent per posting. `postedEpoch` is a Unix timestamp, so windowing to "since my last run" is a single comparison.

### What RemoteOK job data you get

Job ID, slug, position, company, location, tags, primary tag, salary minimum and maximum in USD, a has-salary flag, verified-employer flag, posted timestamp and epoch, description as plain text at whatever length you ask for, apply URL and canonical posting URL.

Three views: Jobs, Salaries and Companies. Export as JSON, CSV, Excel or XML.

### Input configuration

Every field is optional. The prefilled values below are what runs if you press Start without changing anything.

#### What to pull

Tags decide breadth. Everything below narrows what comes back.

| Field | Type | Accepts | What it does |
| --- | --- | --- | --- |
| `tags` | list | one value per line | RemoteOK tags to pull, one per line, for example python, golang, design, marketing, senior. Each tag is fetched separately and the results are merged and deduplicated. Leave empty to take the whole board. Prefilled with `["python"]`. |
| `search` | string | free text | Keep only jobs whose title, company, tags or description contain this text. Matching is case-insensitive. |
| `company` | string | free text | Keep only jobs from companies whose name contains this text. |

#### Filters

All optional.

| Field | Type | Accepts | What it does |
| --- | --- | --- | --- |
| `onlyWithSalary` | true/false | checkbox | RemoteOK publishes a salary range on a minority of postings. Turn this on to keep only those. |
| `minSalaryUsd` | integer | 0 to 1000000 | Keep only jobs whose published range reaches at least this figure. Jobs without a published salary are dropped. |
| `onlyVerified` | true/false | checkbox | Keep only postings RemoteOK has marked as from a verified employer. |

#### Output

Row size and volume.

| Field | Type | Accepts | What it does |
| --- | --- | --- | --- |
| `descriptionCharacters` | integer | 0 to 20000 | How much of the job description to keep, in characters. Set 0 to omit descriptions entirely and keep rows small. Prefilled with `1000`. |
| `maxJobs` | integer | 1 to 5000 | Hard ceiling on the rows this run produces, and therefore on what it costs. You are charged per job returned. Prefilled with `100`. |

### Pricing

Pay per event. The primary event is **Job returned** (`job-returned`), charged at **$0.002 per event** on the free plan, falling to $0.001 on the highest tier.

One remote job posting delivered as a complete row. Blocked sources and empty result sets are never charged.

Minimum charge cap per run: $0.02.

Tiered discounts apply automatically on every paid Apify plan. Platform usage is absorbed by the Actor, so the per-event price is the whole price.

### Usage examples

#### The prefilled run, which is what Start does with nothing changed

```json
{
  "tags": [
    "python"
  ],
  "descriptionCharacters": 1000,
  "maxJobs": 100
}
```

#### Filter by tags

```json
{
  "tags": [
    "python",
    "golang"
  ],
  "descriptionCharacters": 1000,
  "maxJobs": 100
}
```

#### Filter by keyword

```json
{
  "tags": [
    "python"
  ],
  "descriptionCharacters": 1000,
  "maxJobs": 100,
  "search": "senior"
}
```

#### Filter by company

```json
{
  "tags": [
    "python"
  ],
  "descriptionCharacters": 1000,
  "maxJobs": 100,
  "company": "Automattic"
}
```

#### Only jobs with a published salary

```json
{
  "tags": [
    "python"
  ],
  "descriptionCharacters": 1000,
  "maxJobs": 100,
  "onlyWithSalary": true
}
```

### Output example

One row, exactly as the actor wrote it to the dataset:

```json
{
  "jobId": "1135789",
  "slug": "remote-patient-outreach-specialist-grapefruit-health-1135789",
  "position": "Patient Outreach Specialist",
  "company": "Grapefruit Health",
  "location": null,
  "tags": [
    "hr",
    "teaching",
    "education",
    "recruiter",
    "supervisor",
    "customer support",
    "dev",
    "virtual assistant",
    "video",
    "medical",
    "part time",
    "non tech",
    "digital nomad"
  ],
  "primaryTag": "hr",
  "salaryMinUsd": null,
  "salaryMaxUsd": null,
  "hasSalary": false,
  "isVerified": true,
  "postedAt": "2026-08-01T16:00:13+00:00",
  "postedEpoch": 1785600013,
  "description": "<p><span><strong id=\"docs-internal-guid-d2f9f2ed-7fff-9271-9657-97ab474bb4a0\">Patient Outreach Specialist: Remote Healthcare Position</strong></span></p><p><span><strong id=\"docs-internal-guid-d2f9f2ed-7fff-9271-9657-...",
  "applyUrl": "https://remoteOK.com/remote-jobs/remote-patient-outreach-specialist-grapefruit-health-1135789",
  "jobUrl": "https://remoteOK.com/remote-jobs/remote-patient-outreach-specialist-grapefruit-health-1135789",
  "retrievedAt": "2026-08-03T00:36:57Z"
}
```

#### Fields on every row

| Field | Type | What it is |
| --- | --- | --- |
| `jobId` | string | RemoteOK's permanent identifier for this posting. Deduplicate on this across runs. |
| `slug` | string | URL slug of the posting. |
| `position` | string | Job title as the employer wrote it. |
| `company` | string | Hiring company. |
| `location` | string | Where the role may be worked from. Often a region or 'Worldwide' rather than a city. |
| `tags` | list | RemoteOK's tags for the role, covering stack, seniority and function. |
| `primaryTag` | string | First tag on the posting, usually the main technology or function. |
| `salaryMinUsd` | number | Bottom of the published annual range. Null on the majority of postings, which publish no salary. |
| `salaryMaxUsd` | number | Top of the published annual range. Null where no salary is published. |
| `hasSalary` | true/false | Whether this posting publishes a salary range at all. Use it to segment before averaging. |
| `isVerified` | true/false | Whether RemoteOK has marked the employer as verified. |
| `postedAt` | string | ISO timestamp the job was posted. |
| `postedEpoch` | integer | Posting time as a Unix timestamp, for sorting and windowing. |
| `description` | string | Job description as plain text, truncated to the requested length. Null when descriptions are switched off. |
| `applyUrl` | string | Where to apply for the role. |
| `jobUrl` | string | Canonical RemoteOK posting URL. RemoteOK's API terms ask that this link is credited wherever the data is shown. |
| `retrievedAt` | string | UTC timestamp this row was collected. |

3 named dataset views ship with it: **Jobs**, **Salaries**, **Companies**. They drive the Output tab in Console and the Output block on the Actor's `.md` page.

### FAQ

#### Do I need an API key?

No. RemoteOK publishes the board as JSON without any credential.

#### How many jobs does one tag return?

The feed returns up to 100 postings per tag. Pull several tags to go wider - five tags returned 273 distinct jobs in testing, because tags overlap and duplicates are removed.

#### Why do some descriptions contain other languages?

Because the board is international. RemoteOK's feed serves those descriptions double-encoded, which renders them as mojibake in most clients; this Actor detects and repairs that, so non-Latin text comes back readable.

#### Why is there no company logo field?

Because the feed's `company_logo` and `logo` fields are empty on every record of both the whole-board and per-tag feeds. Rather than ship a column that is always null, it is omitted.

#### How do I use this data on my own site?

RemoteOK's API terms ask that you credit RemoteOK and link back to the posting. Every row carries `jobUrl` for exactly that purpose.

***

Unofficial - not affiliated with RemoteOK. Collects public data only. reapx.
Contact reapxdev@proton.me.

### The full published archive

- **[remoteok jobs scraper archive](https://reapx.dev/data/remoteok-jobs-scraper/)** — every entity this Actor has observed
- **[All reapx datasets](https://reapx.dev/data/)** — 20 sources, tens of thousands of pages
- **[llms.txt](https://reapx.dev/llms.txt)** · **[feed.json](https://reapx.dev/feed.json)** ·
  **[feed.xml](https://reapx.dev/feed.xml)** — the machine-readable index, for agents

Each archive page carries Dataset JSON-LD, a canonical URL and the identifiers used, so an agent
can resolve an entity without running anything. Nothing on those pages is estimated or modelled.

### 🧪 Example input

A real, runnable configuration — this is an actual input this Actor has run with.

```json
{
  "descriptionCharacters": 1200,
  "maxJobs": 2000
}
```

### 📄 Sample output

One real row from a real run of this Actor, unedited.

```json
{
  "jobId": "1135789",
  "slug": "remote-patient-outreach-specialist-grapefruit-health-1135789",
  "position": "Patient Outreach Specialist",
  "company": "Grapefruit Health",
  "location": null,
  "tags": [
    "hr",
    "teaching",
    "education",
    "recruiter",
    "supervisor",
    "customer support",
    "dev",
    "virtual assistant",
    "video",
    "medical",
    "part time",
    "non tech",
    "digital nomad"
  ],
  "primaryTag": "hr",
  "salaryMinUsd": null,
  "salaryMaxUsd": null,
  "hasSalary": false,
  "isVerified": true,
  "postedAt": "2026-08-01T16:00:13+00:00",
  "postedEpoch": 1785600013,
  "description": "<p><span><strong id=\"docs-internal-guid-d2f9f2ed-7fff-9271-9657-97ab474bb4a0\">Patient Outreach Specialist: Remote Healthcare Position</strong></span></p><p><span><strong id=\"docs-internal-guid-d2f9f2ed-7fff-9271-9657-97ab474bb4a0\">Grapefruit Health · Remote, U.S. · Part-time, Flexible · Graduates Only</strong></span></p><p></p><h5><span><strong id=\"docs-internal-guid-9ce6a45c-7fff-b3a4-432d-8169b305997a\">ABOUT GRAPEFRUIT HEALTH</strong></span></h5><p><span>Grapefruit Health is a healthcare services company on a mission to solve the growing staffing shortage in healthcare by putting tomorrow's clinicians to work today. We train and manage healthcare graduates to conduct remote, telephonic patient interactions using our purpose-built software. The result: patients receive timely support, healthcare organizations extend their capacity, and you gain real clinical experience.</span></p><h5><span><strong id=\"docs-internal-guid-9ce6a45c-7fff-b3a4-432d-8169b305997a\">THE ROLE</strong></span></h5><p><span>As a GFH Patient Outreach Specialist, you'll conduct structured phone-based interactions with patients on behalf of our partner healthcare organizations. Using our software, you'll follow e",
  "applyUrl": "https://remoteOK.com/remote-jobs/remote-patient-outreach-specialist-grapefruit-health-1135789",
  "jobUrl": "https://remoteOK.com/remote-jobs/remote-patient-outreach-specialist-grapefruit-health-1135789",
  "retrievedAt": "2026-08-03T00:36:57Z"
}
```

### How it works

1. You set the filters below, or none at all - every field is optional.
2. The Actor calls the public **remoteok.com** API directly over HTTP. There is no key to obtain, no login and no headless browser, so a run is fast and cannot break on a UI change.
3. It pages through the results until your maximum is reached or the source runs out of matches.
4. Every row is pushed to the dataset **as it is built** - never buffered to the end. A run that hits its time limit still returns everything it collected.
5. You are charged `job-returned` at **$0.002 per row**, and nothing for Apify platform usage. The maximum-results field is therefore your cost cap, and Apify Store discounts apply on top.

### 💬 Your feedback

Found a bug, or need a field this does not return yet? Open an issue on the Actor's **Issues**
tab, or write to **reapxdev@proton.me**. Bugs get fixed and reasonable field requests get
added.

### ⚠️ Run outcomes and error handling

This Actor reports what happened in the run's **status message**, and it always keeps whatever it collected. These are the outcomes you can get and what each one means.

| Outcome | What it means |
|---|---|
| **Success** | Rows were returned and you were charged `job-returned` at $0.002 per row. |
| **No matches** | The source returned nothing for your filters. **Nothing is charged.** Widen the date window or drop a filter. |
| **Partial - source refused** | The source rate-limited or refused some requests. The affected items are skipped and named in the log, and **everything already collected is still pushed**. A block never discards a run's work. |

#### What is guaranteed either way

- **Every row is pushed as it is built**, not buffered to the end of the run. Anything that buffers output loses everything to a timeout, a block or a migration; this does not.
- **A field absent from the source is absent from the row.** Nothing is inferred, modelled or filled in to make a row look complete.

### 🧭 Ready-made configurations

These are saved, published configurations of this exact Actor. Open one and run it as it is, or copy its input as a starting point - each link is a live page with the full input and its output schema.

| Configuration | Input |
|---|---|
| [Python Remote Jobs on RemoteOK](https://apify.com/reapx/remoteok-jobs-scraper/examples/remoteok-python-jobs) | `tags`: python; `descriptionCharacters`: 1200; `maxJobs`: 500 |
| [JavaScript Remote Jobs on RemoteOK](https://apify.com/reapx/remoteok-jobs-scraper/examples/remoteok-javascript-jobs) | `tags`: javascript; `descriptionCharacters`: 1200; `maxJobs`: 500 |
| [React Remote Jobs on RemoteOK](https://apify.com/reapx/remoteok-jobs-scraper/examples/remoteok-react-jobs) | `tags`: react; `descriptionCharacters`: 1200; `maxJobs`: 500 |
| [Go Remote Jobs on RemoteOK](https://apify.com/reapx/remoteok-jobs-scraper/examples/remoteok-golang-jobs) | `tags`: golang; `descriptionCharacters`: 1200; `maxJobs`: 500 |
| [Java Remote Jobs on RemoteOK](https://apify.com/reapx/remoteok-jobs-scraper/examples/remoteok-java-jobs) | `tags`: java; `descriptionCharacters`: 1200; `maxJobs`: 500 |
| [PHP Remote Jobs on RemoteOK](https://apify.com/reapx/remoteok-jobs-scraper/examples/remoteok-php-jobs) | `tags`: php; `descriptionCharacters`: 1200; `maxJobs`: 500 |
| [Ruby Remote Jobs on RemoteOK](https://apify.com/reapx/remoteok-jobs-scraper/examples/remoteok-ruby-jobs) | `tags`: ruby; `descriptionCharacters`: 1200; `maxJobs`: 500 |
| [Node.js Remote Jobs on RemoteOK](https://apify.com/reapx/remoteok-jobs-scraper/examples/remoteok-node-jobs) | `tags`: node; `descriptionCharacters`: 1200; `maxJobs`: 500 |
| [TypeScript Remote Jobs on RemoteOK](https://apify.com/reapx/remoteok-jobs-scraper/examples/remoteok-typescript-jobs) | `tags`: typescript; `descriptionCharacters`: 1200; `maxJobs`: 500 |
| [AWS Remote Jobs on RemoteOK](https://apify.com/reapx/remoteok-jobs-scraper/examples/remoteok-aws-jobs) | `tags`: aws; `descriptionCharacters`: 1200; `maxJobs`: 500 |
| [DevOps Remote Jobs on RemoteOK](https://apify.com/reapx/remoteok-jobs-scraper/examples/remoteok-devops-jobs) | - |
| [Kubernetes Remote Jobs on RemoteOK](https://apify.com/reapx/remoteok-jobs-scraper/examples/remoteok-kubernetes-jobs) | - |
| [Data Remote Jobs on RemoteOK](https://apify.com/reapx/remoteok-jobs-scraper/examples/remoteok-data-jobs) | - |
| [Machine Learning Remote Jobs on RemoteOK](https://apify.com/reapx/remoteok-jobs-scraper/examples/remoteok-machine-learning-jobs) | - |

There are **50** of these in total, all listed on the Actor's [**Examples** tab](https://apify.com/reapx/remoteok-jobs-scraper).

# Actor input Schema

## `tags` (type: `array`):

RemoteOK tags to pull, one per line, for example python, golang, design, marketing, senior. Each tag is fetched separately and the results are merged and deduplicated. Leave empty to take the whole board.

## `search` (type: `string`):

Keep only jobs whose title, company, tags or description contain this text. Matching is case-insensitive.<br><br>Leave this field empty to skip this filter.

## `company` (type: `string`):

Keep only jobs from companies whose name contains this text.<br><br>Leave this field empty to skip this filter.

## `onlyWithSalary` (type: `boolean`):

RemoteOK publishes a salary range on a minority of postings. Turn this on to keep only those.

## `minSalaryUsd` (type: `integer`):

Keep only jobs whose published range reaches at least this figure. Jobs without a published salary are dropped.

## `onlyVerified` (type: `boolean`):

Keep only postings RemoteOK has marked as from a verified employer.

## `descriptionCharacters` (type: `integer`):

How much of the job description to keep, in characters. Set 0 to omit descriptions entirely and keep rows small.

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

Hard ceiling on the rows this run produces, and therefore on what it costs. You are charged per job returned.<br><br>The higher the number, the longer the run takes and the more you are charged, because you pay per row returned.

## Actor input object example

```json
{
  "tags": [
    "python",
    "golang"
  ],
  "search": "senior",
  "company": "Automattic",
  "onlyWithSalary": true,
  "minSalaryUsd": 100000,
  "onlyVerified": true,
  "descriptionCharacters": 1000,
  "maxJobs": 100
}
```

# Actor output Schema

## `overview` (type: `string`):

One row per remote job, with company, tags and a link.

## `salaries` (type: `string`):

Postings that publish a pay range. Filter on Has salary before averaging.

## `companies` (type: `string`):

Hiring volume and verification status per company.

## `results` (type: `string`):

Every record this run produced, with all fields and no view applied. Field-level titles, types, descriptions and examples are declared in the dataset schema.

# 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 = {
    "tags": [
        "python"
    ],
    "descriptionCharacters": 1000,
    "maxJobs": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("reapx/remoteok-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 = {
    "tags": ["python"],
    "descriptionCharacters": 1000,
    "maxJobs": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("reapx/remoteok-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "tags": [
    "python"
  ],
  "descriptionCharacters": 1000,
  "maxJobs": 100
}' |
apify call reapx/remoteok-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=reapx/remoteok-jobs-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/8XwyM3V3Ase7IqnPH/builds/XfRKoyZvODAOVim69/openapi.json
