# Remote Jobs API: Himalayas, Jobicy, RemoteOK & Arbeitnow (`tinlark/remote-jobs-feed`) Actor

One feed of remote jobs from Himalayas, Jobicy, RemoteOK and Arbeitnow: filters, merged duplicates, a source link and attribution line on every row, and a new-only mode for schedules. No login, no proxy. Free during launch; from 1 November 2026: $1.50 per 1,000 jobs.

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

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## 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: Himalayas, Jobicy, RemoteOK and Arbeitnow in one feed

Get remote job listings from **Himalayas**, **Jobicy**, **RemoteOK** and **Arbeitnow** as one uniform record per job. Filter by keyword, category, country, time zone, job type, salary and age. The same job listed on several boards is merged into one row. Every row carries the board's own listing URL and a ready-made attribution line, which the boards ask any re-publisher to show. Turn on **new-only** mode and a daily schedule returns only listings you have not received before.

The Actor uses the boards' public JSON APIs. It needs no login, no browser and no proxy.

### Use cases

- **A remote job board or newsletter.** Fill it with listings that carry the source link and attribution each board requires.
- **Job alerts.** Schedule a run with `newOnly` and a State name, and send yourself or your users the listings that appeared since the last run.
- **Market data.** Count remote roles by category, country, seniority or published salary range.
- **AI agents and automations.** The input and output schemas are defined, so an agent can call the Actor and read the fields without guessing.
- **Candidate search.** Keywords plus time zone, country and minimum salary narrow over 100,000 listings to the few that fit.

### What you get

One row per job, the same fields for every board: title, company, categories (a common list) and the board's own tags, job type, where candidates must be (countries or regions and UTC offsets), salary (min, max, currency, period, only where the board publishes it), seniority (only where the board states it), posted and expiry date, description as plain text or HTML, `listingUrl`, `applyUrl` and `attribution`.

### Input

Everything is optional. With an empty input you get the 100 newest listings across the four boards.

| Field | What it does |
|---|---|
| `sources` | `himalayas`, `jobicy`, `remoteok`, `arbeitnow`. Default: all four. |
| `keywords`, `excludeKeywords` | Matched, not case sensitive, against title, company, categories, tags and description. Up to 20 each. |
| `categories` | Common categories: `software-engineering`, `devops-infrastructure`, `data-ai`, `design`, `product`, `marketing`, `sales`, `customer-support`, `finance`, `hr-recruiting`, `legal`, `operations-admin`, `writing-content`, `security`, `education`, `healthcare`, `other`. |
| `countries` | Two-letter ISO codes (`US`, `DE`, `GB`). Matches the country, or a region that contains it (EMEA, Europe, LATAM), in the board's own location text. |
| `includeWorldwide` | With a country filter, also keep listings open to candidates anywhere. Default on. |
| `jobTypes` | `full-time`, `part-time`, `contract`, `internship`. |
| `timezones` | UTC offsets such as `-5`, `UTC+1`, `UTC+05:30`. |
| `minSalaryUsd` | Yearly USD. Hourly, daily, weekly and monthly pay is converted to a year. |
| `postedWithinDays` | Keep listings published in the last N days. |
| `includeDescription` | `text` (default), `html` or `none`. |
| `dedupe` | Merge the same company and title across boards (default on). |
| `newOnly`, `stateName` | Return only listings not delivered before in runs with the same State name. |
| `maxItems` | Default 100, at most 10,000. |

#### Example: the prefilled run

```json
{
  "sources": ["himalayas", "jobicy", "remoteok", "arbeitnow"],
  "keywords": ["python"],
  "maxItems": 50
}
```

#### Example: a daily feed of new senior engineering jobs in Europe

```json
{
  "keywords": ["senior", "lead"],
  "categories": ["software-engineering"],
  "countries": ["DE", "NL", "GB"],
  "postedWithinDays": 7,
  "newOnly": true,
  "stateName": "eu-senior-eng",
  "maxItems": 500
}
```

The first run returns everything that matches. Every later run with the same State name returns only listings that were not delivered before. Use a different State name for each watch list.

If `maxItems` cuts the list, the boards take turns (newest first within each board), so one busy board does not crowd out the others.

### Output

Results go to the default dataset: download them as JSON, CSV, Excel or XML, or read them through the API. The *Jobs*, *With salary* and *Problems* views show the main fields. A run summary (rows per board, requests, errors, duration) is stored under the `SUMMARY` key.

#### Job row (real output, description shortened)

```json
{
  "recordType": "job",
  "source": "himalayas",
  "sourceName": "Himalayas",
  "jobId": "https://himalayas.app/companies/instacart/jobs/software-engineer-ii-crm-seo",
  "title": "Software Engineer II, CRM & SEO",
  "company": "Instacart",
  "companyUrl": "https://himalayas.app/companies/instacart",
  "categories": ["software-engineering", "marketing"],
  "tags": ["Developer", "Software Engineer", "Full Stack Engineer", "CRM Engineer"],
  "jobType": "full-time",
  "locationRestriction": ["Canada"],
  "timezoneRestriction": ["UTC-8", "UTC-7", "UTC-6", "UTC-5", "UTC-4", "UTC-3:30"],
  "isWorldwide": false,
  "salaryMin": 145000,
  "salaryMax": 153000,
  "salaryCurrency": "CAD",
  "salaryPeriod": "annual",
  "seniority": "Mid-level",
  "postedAt": "2026-10-03T08:53:34Z",
  "expiresAt": "2026-12-02T08:53:33Z",
  "description": "We're transforming the grocery industry ...",
  "listingUrl": "https://himalayas.app/companies/instacart/jobs/software-engineer-ii-crm-seo",
  "applyUrl": "https://himalayas.app/companies/instacart/jobs/software-engineer-ii-crm-seo",
  "attribution": "Source: Himalayas (https://himalayas.app), https://himalayas.app/companies/instacart/jobs/software-engineer-ii-crm-seo",
  "status": null,
  "firstSeenAt": null
}
```

With a State name, `status` is `new` or `seen` and `firstSeenAt` is the first run that delivered the listing. Rows merged from other boards add `alsoListedOn`. If a board cannot be read, the dataset gets one row with `recordType: "error"`, the board and the reason, and the other boards still run. Error rows are free.

#### What each board gives

| Board | Listings you can reach | Notes |
|---|---|---|
| Himalayas | The whole feed (over 100,000 listings), newest first | The richest data: salary, countries, time zones, seniority, expiry date. With keywords or a country the board's search is used; the Actor reads up to 5,000 results per search (the number the board reports as its total). |
| Jobicy | The last 7 days, with a delay of 3 hours | The Actor reads the whole 7-day feed at most once an hour and keeps it as a snapshot in your account (see Limits). `applyUrl` is Jobicy's own listing page. |
| RemoteOK | About the latest 100 listings | That is what its public API returns. Many listings have no location (read as worldwide) and no job type. Salaries are yearly USD. |
| Arbeitnow | Listings flagged remote, from the first 5 pages | A German board; most of its listings are on-site and are skipped. Remote ones often name no country. |

#### Field notes

- `categories` maps each board's own labels (and the title when a board has none) to the common list, so a listing can have more than one. The original labels are in `tags`.
- `salaryMin` and `salaryMax` are filled only when the board publishes pay. Most listings have none. `minSalaryUsd` compares only salaries stated in USD.
- `locationRestriction` is the board's own text (countries, regions such as EMEA, or a city). `isWorldwide` is true when the board says anywhere or names no restriction.
- `timezoneRestriction` is filled only by Himalayas. A listing that lists every offset is read as having no restriction.
- Duplicates are matched on company and title (case, punctuation and "(m/f/d)" ignored) across boards only. Two listings of the same board are never merged. Matches are exact on company and title, so merges are rare: in a 1,500-row test on 3 October 2026 the boards shared 23 companies but no identical title.

### Attribution: what the boards ask of you

The Actor puts `listingUrl` and `attribution` on every row for this reason. If you publish or redistribute listings, these are the boards' own rules as read on 3 October 2026. Read the pages themselves, they can change.

| Board | What it asks | Where |
|---|---|---|
| Himalayas | Link back to the listing URL **and** mention Himalayas as the original source. Do not submit Himalayas jobs to third-party sites such as Jooble, Neuvoo, Google Jobs or LinkedIn Jobs. | himalayas.app/api |
| Jobicy | Keep Jobicy as the original source and keep the Jobicy listing URL. Do not present the listings as your own postings, and do not build spam networks or misleading job databases. Application buttons should lead to the URL in `applyUrl`. | jobicy.com/jobs-rss-feed, "Fair use" |
| RemoteOK | Link back with a followed link (no `nofollow`) to the listing and mention Remote OK as the source, or API access can be suspended. Do not use the Remote OK logo without written permission. The Actor never outputs it. | remoteok.com/api |
| Arbeitnow | Link back to Arbeitnow.com on your platform. Arbeitnow may revoke API permission at any time. | arbeitnow.com/terms, section 11 |

### Pricing

**Free during launch (until 31 October 2026).** You pay only Apify's own platform usage for your runs.

From 1 November 2026: pay per event, **$1.50 per 1,000 job rows** ($0.0015 each; $2.00 per 1,000 on the Apify free plan, lower on higher Apify plans; the Store page shows the price for your plan). Not charged: error rows, duplicates merged across boards, and listings that new-only mode skips because you already have them.

Platform usage measured on 3 October 2026: a run with 1,000 job rows from Himalayas, RemoteOK and Arbeitnow (256 MB) took 57 seconds and cost $0.006 in Apify platform usage, almost all of it dataset writes. The prefilled run (50 rows from all four boards, 512 MB) took 15 seconds and cost $0.0009. On the Apify free plan that is covered by your monthly credit.

Cost examples at the planned price:

- 500 jobs for a one-off market snapshot: $0.75.
- A daily `newOnly` feed that finds 40 new matching jobs a day: $0.06 a day.
- 10,000 jobs from Himalayas for a data set: $15.

Set *Maximum cost per run* in the run options to cap spending once pricing is active; the Actor stops cleanly when the cap is reached.

### Limits and honest notes

- **Four boards.** Remotive and We Work Remotely are not included: Remotive's API allows 4 requests a day per user, which a shared cloud service cannot honour, and We Work Remotely's terms could not be read.
- **RemoteOK returns about 100 listings.** That is the size of its public API answer. Older listings are not reachable through it.
- **Jobicy is a 7-day window with a 3-hour delay,** and its terms allow one automated pass per hour. The first run in an hour reads the whole window and saves it as a snapshot in a named storage of your account (`remote-jobs-feed-cache`). Runs in the next 60 minutes reuse the snapshot, so Jobicy rows can be up to an hour old. If a pass fails, an older snapshot is used and the run summary says so.
- **Himalayas search is read up to 5,000 results** per keyword or country (the board reports 5,000 as the total of a search). Keywords and countries each start their own search (at most 20 values each). Search results on the board's side can shift between calls, so a listing missed by one run can show up in the next; with a State name it is delivered once.
- **Arbeitnow:** only listings the board flags as remote, from its first 5 pages, read at one request a second.
- **Salary filters need data.** Listings without a published salary, or with one in another currency, are dropped when you set `minSalaryUsd`. Listings from boards that do not state a job type are dropped when you pick a type. Only Himalayas publishes time zones, so a time zone filter drops the other boards.
- **Country matching is text matching** on the board's own location wording, with common country names and regions (EMEA, Europe, LATAM, APAC, North America). A listing that names only a city, or no country at all, does not match a country filter unless it is worldwide and `includeWorldwide` is on.
- **Pace.** Himalayas at no more than 2 requests a second with `Retry-After` honoured, RemoteOK, Jobicy and Arbeitnow at 1 a second. Failed requests (429, 5xx, network errors) are retried with backoff. The Actor reads each board's robots.txt and identifies itself as TinlarkBot with a contact address.
- **State for new-only** is kept per State name in a named storage `remote-jobs-state-<name>` of your account. Entries that were not seen for 90 days are dropped.
- Listings are the boards' content. The Actor does not log in, read private data, or collect personal data about candidates.

### Data source, terms and your responsibility

All data comes from the public APIs the boards publish for others to use, read on 3 October 2026:

- Himalayas: `himalayas.app/jobs/api` and `/jobs/api/search`, "free public JSON API, no authentication required".
- Jobicy: `jobicy.com/api/v2/remote-jobs`, the public endpoint without an API key. Its optional paid commercial key is not used.
- RemoteOK: `remoteok.com/api`. The first element of the answer is a legal notice, not a job; the Actor drops it and passes its requirements on in the table above.
- Arbeitnow: `arbeitnow.com/api/job-board-api`. Its terms bar commercial use of the website's own materials, so only the API is used.

Tinlark is not affiliated with Himalayas, Jobicy, RemoteOK or Arbeitnow, and those boards can change or withdraw API access at any time.

### Use it from code or an AI agent

Call the Actor through the Apify API or any Apify client library, or through Apify's MCP server, with the input above, and read the dataset items. Example with the Python client:

```python
from apify_client import ApifyClient

client = ApifyClient("<your Apify token>")
run = client.actor("tinlark/remote-jobs-feed").call(run_input={"keywords": ["python"], "countries": ["US"], "maxItems": 50})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], job["company"], job["listingUrl"])
```

### FAQ

**Does it need a proxy or a login?** No. The APIs are public and the Actor makes plain HTTP requests.

**How fresh is the data?** Himalayas, RemoteOK and Arbeitnow are read live on every run (Arbeitnow says it updates hourly). Jobicy is up to an hour old by design.

**How big can a run be?** Up to 10,000 jobs. A run of 1,000 jobs from three boards took 57 seconds at 256 MB and peaked at 185 MB; the default is 512 MB.

**Why did I get fewer rows than `maxItems`?** Usually the filters leave fewer listings than that on the boards, or one board returned an error row. The summary under `SUMMARY` shows how many listings each board returned and how many matched.

**Can I get the job descriptions?** Yes, as plain text by default or as the board's HTML with `includeDescription: "html"`. Set it to `none` for smaller output.

**Can I schedule it?** Yes. Use an Apify Schedule with `newOnly` and a fixed State name.

**Disclaimers and legality: is it legal to use this data?** The Actor reads only the public APIs that the boards publish for reuse, within their stated rate limits, and it keeps each board's source link on every row. Each board attaches conditions, mainly attribution; they are listed above and you are responsible for meeting them when you republish. Listings and company names belong to the employers and the boards. You are also responsible for the laws that apply to you, for example on unsolicited contact. This is not legal advice.

### Related Tinlark Actors

- [ATS Jobs Scraper](https://apify.com/tinlark/ats-jobs-hiring-signals): reads open jobs straight from company career pages, for employers that do not post on these boards.
- [Greenhouse Jobs Scraper](https://apify.com/tinlark/greenhouse-jobs-scraper): open jobs from the Greenhouse boards of companies you pick, with pay ranges where published.
- [Workday Jobs Scraper](https://apify.com/tinlark/workday-jobs-scraper): open jobs from the Workday career sites of large employers you pick.

### Support

Something wrong or missing? Open an issue on this Actor's Issues tab with your input (the boards and filters) and what you expected.

# Actor input Schema

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

Which boards to read. Default: all four. Remotive and We Work Remotely are not offered.

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

Keep listings whose title, company, categories, tags or description contain any of these words (not case sensitive). Empty keeps everything.

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

Drop listings that contain any of these words.

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

Keep listings in these categories. Each board's own labels are mapped to this common list; the original labels stay in `tags`.

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

Two-letter codes such as US, DE or GB. Keeps listings that name the country, or a region that contains it (EMEA, Europe, LATAM). Matching is on the board's own location text. Worldwide listings are kept unless you turn off the next option.

## `includeWorldwide` (type: `boolean`):

With a country filter: also return listings open to candidates anywhere.

## `jobTypes` (type: `array`):

Keep these types. Listings whose board does not state a type are dropped when you pick one (RemoteOK rarely states it).

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

Stop after this many job rows. Each job row is the billable event once pricing is active.

## `newOnly` (type: `boolean`):

Return only listings you have not received before in runs that use the same State name, so a daily schedule stays cheap. The first run returns everything that matches.

## `stateName` (type: `string`):

The name under which the Actor remembers which listings it has already delivered, kept in a named storage of your account. Letters, digits and hyphens, up to 40 characters. Use the same name on every scheduled run and a different name per watch list. Defaults to 'default' when New listings only is on.

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

Keeps listings whose published salary reaches this yearly amount. Hourly, weekly and monthly pay is converted to a year. Only salaries stated in USD are compared; listings with no salary or another currency are dropped.

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

Offsets such as -5, UTC+1 or UTC+05:30. Keeps listings open to candidates in any of them. Only Himalayas publishes time zones; listings from the other boards are dropped when you use this.

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

Keep listings published in the last N days.

## `includeDescription` (type: `string`):

none: no description. text: plain text (default). html: the board's HTML.

## `dedupe` (type: `boolean`):

The same company and title on several boards becomes one row; the other boards are named in `alsoListedOn`. Duplicates are not charged.

## Actor input object example

```json
{
  "sources": [
    "himalayas",
    "jobicy",
    "remoteok",
    "arbeitnow"
  ],
  "keywords": [
    "python"
  ],
  "includeWorldwide": true,
  "maxItems": 50,
  "newOnly": false,
  "includeDescription": "text",
  "dedupe": true
}
```

# Actor output Schema

## `jobs` (type: `string`):

Job rows, newest first.

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

The same rows with salary columns first.

## `errors` (type: `string`):

Boards that could not be read.

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

Counts per board, errors, requests, duration.

# 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": [
        "himalayas",
        "jobicy",
        "remoteok",
        "arbeitnow"
    ],
    "keywords": [
        "python"
    ],
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("tinlark/remote-jobs-feed").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": [
        "himalayas",
        "jobicy",
        "remoteok",
        "arbeitnow",
    ],
    "keywords": ["python"],
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("tinlark/remote-jobs-feed").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": [
    "himalayas",
    "jobicy",
    "remoteok",
    "arbeitnow"
  ],
  "keywords": [
    "python"
  ],
  "maxItems": 50
}' |
apify call tinlark/remote-jobs-feed --silent --output-dataset

```

## MCP server setup

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

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/rXVvgj3AlCKlFl7Cd/builds/5fM4nIaUmEH6J0tqD/openapi.json
