# Remote Jobs Scraper - RemoteOK, Himalayas & Arbeitnow API (`appdata-labs/remote-jobs`) Actor

Every open remote job from three public job boards in one table: RemoteOK, Himalayas and Arbeitnow. Published salary bands, tags, seniority, location restrictions and direct apply links, normalised into one schema with search, tag, salary and posting-date filters.

- **URL**: https://apify.com/appdata-labs/remote-jobs.md
- **Developed by:** [Kobkoon Janngam](https://apify.com/appdata-labs) (community)
- **Categories:** Agents, MCP servers, Jobs
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 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.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

## Remote Jobs Scraper — RemoteOK, Himalayas & Arbeitnow in one table

**Every open remote role from three public job boards, in one run.** RemoteOK, Himalayas and Arbeitnow each publish a keyless JSON API and each describes a job differently. This Actor reads all three and returns one identically shaped table.

**Quick start:** press **Start** with no configuration at all. It pulls from all three boards, keeps the remote roles, and returns a couple of hundred live listings immediately.

### Sample output

| source | title | company | location | employmentType | salaryMin | salaryMax | publishedAt |
|---|---|---|---|---|---|---|---|
| remoteok | Senior Python Engineer | Acme | Worldwide | | 120,000 | 160,000 | 2026-09-02 |
| himalayas | Senior Product Owner | NirYu | Mexico, Brazil | Contractor | 90,000 | 130,000 | 2026-09-03 |
| arbeitnow | Account Executive | Fiskaly | Berlin | full\_time | | | 2026-09-03 |

Every row also carries `jobId`, `url`, `applyUrl`, `companyLogo`, `locationRestrictions`, `isRemote`, `seniority`, `tags`, `salaryCurrency`, `salaryPeriod`, `descriptionPreview`, `descriptionTruncated` and `descriptionChars`.

### Why this one

**Three boards, one schema.** A job is called `position` on one board and `title` on the next. A date arrives as an ISO string here and epoch seconds there. Salary is two numbers with an implied currency on one, an explicit currency and period on another, and absent on the third. All of it is normalised, every field is always present, and `jobId` is a string everywhere so joins do not break.

**Salary you can actually filter on.** 54 of the first 180 listings published a band. `minSalary` uses it — and deliberately **keeps jobs that publish no salary at all**, because silence is not evidence of a low offer, and dropping them would quietly hide most of every board while looking like a working filter.

**Two details that break naive integrations.** RemoteOK's API returns its licence notice as the *first element of the jobs array* — treat it as a job and every result starts with a blank row. And it ships some fields already mis-encoded, so a Dubai listing arrives as `Ø¯Ø¨Ù`. Both are handled: the notice is skipped, and the text is repaired back to `دبي` when — and only when — the round trip is unambiguous.

**Honest coverage.** RemoteOK and Himalayas are remote-only boards, so `isRemote` is a fact there. Arbeitnow is a general board, so its own flag is used rather than assumed. `remoteOnly` is on by default and drops the on-site roles.

### What you can do with it

- **A daily remote-jobs feed.** Schedule it with `postedAfter` set to yesterday and you get only the new listings across all three boards.
- **Salary benchmarking.** Filter by `tag` and read the published bands — three boards give a wider sample than any one.
- **Watch an employer.** `companyContains` follows a company across every board at once.
- **Feed an AI agent.** Rows are under 2.6 KB, identically shaped, and every one carries a direct apply URL.

### Input

| Field | Default | Notes |
|---|---|---|
| `sources` | all three | `remoteok`, `himalayas`, `arbeitnow`. Narrow it when you only want one. |
| `searchQuery` | empty | Searches title, tags **and** description — on a remote board the useful signal is often a technology named in the body. |
| `tag` | empty | Boards tag by technology, function and seniority. |
| `companyContains` | empty | Case-insensitive partial match. |
| `remoteOnly` | `true` | Drops the on-site roles Arbeitnow carries. |
| `minSalary` | `0` | Jobs publishing no salary are kept. |
| `postedAfter` | empty | `YYYY-MM-DD`. The most useful filter for a scheduled run. |
| `includeFullDescription` | `false` | Full posting text instead of an 800-character preview. |
| `maxJobsPerSource` | `100` | Applied before filtering. Himalayas alone lists over 100,000 open roles. |

### Limits worth knowing before you buy

`maxJobsPerSource` is applied **before** the filters, so a narrow `searchQuery` over a small limit can return very little. Raise the limit when you filter hard.

If one board is down, the run continues with the others and names the one that failed in the log and in `SUMMARY`, rather than returning a quietly short result.

These boards each surface a slice of the market, not all of it. Two are remote-first; Arbeitnow is Europe-heavy. This is a broad daily feed, not an exhaustive index of every remote job on the internet.

### Pricing

Pay per job delivered, after filtering. A board with no matching jobs charges you nothing.

### Attribution and terms

**RemoteOK's API terms ask for a credit and a link back**, and this Actor is built to let you honour that: every row carries the original `url` on the source board, and `SUMMARY` records the home page of each board used. If you republish these listings, credit **[Remote OK](https://remoteok.com)**, **[Himalayas](https://himalayas.app)** and **[Arbeitnow](https://www.arbeitnow.com)** and link back to the job on the board it came from.

### Disclaimer

This is an **unofficial** tool. It is not affiliated with, authorised by, endorsed by, or in
any way officially connected to Remote OK, Himalayas, Arbeitnow, or any company whose job
listing it returns. Those names are trademarks of their respective owners.

It reads only each board's **public, unauthenticated** JSON API — the documented endpoint
each one publishes for this purpose. `robots.txt` on all three either answers `Allow: /` or
does not mention the path. It signs into nothing, stores no credentials, and returns nothing
behind a login or a paywall. No candidate or applicant data is accessed; job postings are,
by definition, published to be read.

Any board can change or withdraw its API at any time. When one cannot be read, this Actor
says which and why rather than handing you a short result that looks complete.

# Actor input Schema

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

Which boards to pull from. remoteok and himalayas are remote-only by nature; arbeitnow is a general board whose own remote flag is respected. Narrow this when you only care about one.

## `searchQuery` (type: `string`):

Keep only jobs matching this text, case-insensitive. Title, tags and the description are all searched, because on a remote board the useful signal is usually a technology named in the body rather than in the title.

## `tag` (type: `string`):

Keep only jobs carrying a matching tag, case-insensitive and partial. Boards tag by technology, function and seniority, so "senior", "python" and "design" all work.

## `companyContains` (type: `string`):

Keep only jobs whose company name contains this text, case-insensitive. Useful for watching a specific employer across all three boards at once.

## `remoteOnly` (type: `boolean`):

On by default. Two of the three boards are remote-only anyway; this drops the on-site roles Arbeitnow carries. Turn it off to include those.

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

Drop jobs whose published upper salary is below this. Jobs that publish no salary at all are kept, because silence is not evidence of a low offer — and most listings are silent.

## `postedAfter` (type: `string`):

Keep only jobs published on or after this date, as YYYY-MM-DD. The most useful filter for a scheduled run: set it to yesterday and you get just the new listings.

## `includeFullDescription` (type: `boolean`):

Off by default. Descriptions run to several thousand characters, which makes a row too big for an AI agent to read comfortably. Off, you get an 800-character preview plus the true length.

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

How many jobs to take from each board before filtering. Himalayas alone advertises over 100,000 open roles, so this is what keeps a default run fast and cheap.

## Actor input object example

```json
{
  "sources": [
    "remoteok",
    "himalayas"
  ],
  "searchQuery": "react",
  "tag": "python",
  "companyContains": "automattic",
  "remoteOnly": true,
  "minSalary": 100000,
  "postedAfter": "2026-08-01",
  "includeFullDescription": false,
  "maxJobsPerSource": 100
}
```

# Actor output Schema

## `rows` (type: `string`):

One row per open role: title, company, location, tags, salary band, posting date, a direct apply link and the board it came from.

## `summary` (type: `string`):

How many jobs each board returned, what the filters removed, and the attribution each board asks for.

# 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",
        "himalayas",
        "arbeitnow"
    ],
    "searchQuery": "",
    "tag": "",
    "companyContains": "",
    "remoteOnly": true,
    "minSalary": 0,
    "postedAfter": "",
    "includeFullDescription": false,
    "maxJobsPerSource": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("appdata-labs/remote-jobs").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",
        "himalayas",
        "arbeitnow",
    ],
    "searchQuery": "",
    "tag": "",
    "companyContains": "",
    "remoteOnly": True,
    "minSalary": 0,
    "postedAfter": "",
    "includeFullDescription": False,
    "maxJobsPerSource": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("appdata-labs/remote-jobs").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",
    "himalayas",
    "arbeitnow"
  ],
  "searchQuery": "",
  "tag": "",
  "companyContains": "",
  "remoteOnly": true,
  "minSalary": 0,
  "postedAfter": "",
  "includeFullDescription": false,
  "maxJobsPerSource": 100
}' |
apify call appdata-labs/remote-jobs --silent --output-dataset

```

## MCP server setup

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

```

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/GVQdcgyjBrRkJpsNR/builds/KODRRXgooVH31ugDo/openapi.json
