# Remote Jobs API: Remote OK and Jobicy in one feed (`itayozer9/remote-jobs-api`) Actor

Remote jobs from Remote OK and Jobicy in one clean schema: salary in USD per year, worldwide or region filter, seniority, tags, apply link, duplicates merged, only-new mode. Contact details removed.

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

## Pricing

from $1.00 / 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.

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: Remote OK and Jobicy in one feed

Get fresh remote jobs from **Remote OK** and **Jobicy** as one clean JSON feed. Every job comes in the same shape: title, company, salary converted to **USD per year**, where you can work from, seniority, tags, the apply link and the board it came from. Filter by keywords, region, seniority, minimum salary and age, merge duplicates across boards, and run it on a schedule with **only-new mode** so each run returns just the jobs you have not seen.

Built for job boards, newsletters, Slack or Discord alerts, career tools and AI agents that need remote job data without writing two integrations.

The data comes from the official public JSON APIs of Remote OK and Jobicy, so there are no blocked pages, no captchas and no proxy costs. Runs are quick: about 3 to 20 seconds for a search that returns up to a few hundred jobs.

### What you get

For every job:

- **Title, company and board** (`source`: Remote OK or Jobicy)
- **Job link** on the board (`url`) and **apply link** (`applyUrl`)
- **Posted date** (ISO 8601, UTC)
- **Salary in USD per year** (`salaryMinUsd`, `salaryMaxUsd`), converted from the posted currency and period (hourly, monthly, yearly) with the latest European Central Bank rates, plus the salary exactly as posted (`salary`)
- **Where you can work from**: `locations` as the board lists them and `worldwide` (true, false, or null when the board does not say)
- **Seniority**: intern, junior, mid, senior, lead, director or executive, read from the title first and then from the board's own level
- **Employment type**: full-time, part-time, contract, internship
- **Tags** or categories from the board
- **Description** as plain text, cut to the length you choose, with **email addresses and phone numbers removed**
- **alsoOn**: when the same job (same company and title) is on both boards, you get it once, with the other board's link here

### Input

| Field | Required | Example | Notes |
|---|---|---|---|
| `keywords` | no | `python, golang` | All words of a phrase must be in the title, company or tags. Commas separate alternatives |
| `sources` | no | `["remoteok", "jobicy"]` | Which boards to read. Default: both |
| `region` | no | `usa` | `any`, `worldwide`, `usa`, `canada`, `uk`, `europe`, `latam`, `apac`. Keeps jobs open worldwide plus jobs whose location names the region or a country in it |
| `seniority` | no | `["senior", "lead"]` | Levels to keep. Empty keeps all |
| `minSalaryUsd` | no | `100000` | Top of the range in USD per year must reach this. Drops jobs without a salary |
| `maxAgeDays` | no | `3` | Only jobs posted in the last N days |
| `onlyNew` | no | `true` | Skip jobs an earlier run with the same filters returned |
| `descriptionMaxChars` | no | `1000` | 0 leaves descriptions out. Default 1000 |
| `strictSources` | no | `false` | Fail the run if a board is down, instead of continuing with the other |
| `maxItems` | no | `100` | 1 to 2000, newest first. You pay only for jobs returned |

```json
{
    "keywords": "engineer, developer",
    "region": "usa",
    "minSalaryUsd": 100000,
    "maxItems": 200
}
```

### Output example

One dataset item per job, newest first:

```json
{
    "id": "jobicy:158175",
    "source": "Jobicy",
    "title": "Staff Software Engineer, Frontend",
    "company": "hims & hers",
    "url": "https://jobicy.com/jobs/158175-staff-software-engineer-frontend",
    "applyUrl": "https://jobicy.com/jobs/158175-staff-software-engineer-frontend",
    "postedAt": "2026-10-31T10:09:18.000Z",
    "employmentType": "full-time",
    "seniority": "lead",
    "tags": ["software engineering"],
    "locations": ["USA"],
    "worldwide": false,
    "salaryMinUsd": 190000,
    "salaryMaxUsd": 230000,
    "salary": { "min": 190000, "max": 230000, "currency": "USD", "period": "yearly" },
    "description": "Hims & Hers is the leading health and wellness platform, on a mission to help the world feel great through the power of better health. We are redefining...",
    "alsoOn": [],
    "scrapedAt": "2026-10-31T15:58:18.747Z"
}
```

Fields a board does not have are `null`, never guessed. A salary in an unknown currency keeps its posted values in `salary` and leaves the USD fields `null`.

### Pricing

You pay per job returned, nothing per run beyond Apify's standard start fee:

| Event | Price | When |
|---|---|---|
| Job returned | $0.001 | Every job in your dataset |

Example: 1,000 jobs cost $1.00. A daily only-new run that finds 40 new jobs costs about $0.04.

The actor reads your run's maximum charge before it fetches anything and returns only as many jobs as that covers, so a run never goes over the limit you set.

### Use the data fairly

Both boards ask for credit. When you show these jobs to other people, show the board name (`source`), link each job to its `url` on the board with a normal link (no `rel="nofollow"`, Remote OK asks for this), and keep the apply button on `applyUrl`. Do not use the Remote OK logo, and do not use Remote OK data to train AI models (its robots.txt says `ai-train=no`). That is all they ask, and it keeps these free APIs open.

### Limits

- **Coverage**: Remote OK's API gives its latest 100 or so jobs; Jobicy's gives every job from the last 7 days (about 1,400 on 2026-10-31). Older jobs are not available. A full run returns about 1,500 jobs.
- **Freshness**: live at run time. Jobicy publishes new jobs with a delay of about 3 hours.
- **Region filter** works on the location text the boards give. City names (for example Boston or Berlin) are not mapped to a country, and jobs with no location are kept only with region `any`.
- **Seniority** comes from words in the title (senior, lead, director, VP...) and Jobicy's level. Titles without such words have `null`.
- **Speed**: about 10 to 20 seconds for a few hundred jobs, about 3 minutes for 1,000.
- No timezone filter: neither board publishes timezone limits.

### FAQ

**Where does the data come from?**
The public JSON APIs of Remote OK (remoteok.com/api) and Jobicy (jobicy.com/api/jobs). No login, no API key, no scraping of web pages.

**Why only these two boards?**
These are the boards whose API terms allow passing their jobs on with credit. Some other well-known boards forbid it in their terms, so they are not included.

**How does only-new mode work?**
With `onlyNew` on, the actor remembers which jobs it returned for that exact set of filters, in a storage named `remote-jobs-api-seen` in your own Apify account. The next run with the same filters skips them. Different searches keep separate memories, and jobs are forgotten after 120 days.

**How is the salary converted?**
Hourly x 2080, daily x 260, weekly x 52, monthly x 12, then into USD with the latest European Central Bank reference rates (via frankfurter.dev). If the rate service is down, rates from 2026-10-30 are used. Values that come out under $1,000 a year are treated as a typo at the board and left `null` in the USD fields.

**Why did I get fewer jobs than `maxItems`?**
Your filters matched fewer jobs, only-new mode skipped jobs you already have, or your run's maximum charge covered fewer jobs.

**Can I schedule it or call it from an AI agent?**
Yes. It runs with limited permissions, so it needs no access to your other Apify data, and it works from schedules, the API and MCP clients. Schedule it hourly or less often: Jobicy asks for at most one pass an hour and publishes new jobs about 3 hours late anyway. Set `descriptionMaxChars` to 0 or 300 for small, cheap responses.

**Is there personal data in the results?**
No personal data is collected. The records are job ads from companies. Email addresses and phone numbers inside descriptions are removed before they reach your dataset.

**Something broke or a field is missing. What do I do?**
Open an issue on the Issues tab with your run link. Issues are answered within a few days.

# Actor input Schema

## `keywords` (type: `string`):

Words that must all appear in the job title, company or tags. Separate alternatives with commas: "python, golang" finds Python jobs or Go jobs. Leave empty for every job.

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

Which boards to read. Default: all.

## `region` (type: `string`):

Keep jobs open to people in this region: jobs open worldwide plus jobs whose location names the region or a country in it. "Worldwide only" keeps just the jobs open everywhere. Jobs with no location listed are kept only with "Any".

## `seniority` (type: `array`):

Keep only these levels (read from the job title, then the board's own level). Empty keeps all, including jobs with no level.

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

Keep jobs whose top of range, converted to USD per year, is at least this. Jobs without a salary are dropped when this is set.

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

Keep jobs posted in the last N days.

## `onlyNew` (type: `boolean`):

Skip jobs that an earlier run with the same filters already returned. Made for schedules: each run gives only what is new. The memory lives in a storage in your own account.

## `descriptionMaxChars` (type: `integer`):

Characters of plain-text description per job. 0 leaves the description out (smallest output).

## `strictSources` (type: `boolean`):

By default, if one board cannot be read the run continues with the others and logs a warning. Turn this on to fail the run instead.

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

Most jobs to return (1 to 2000), newest first. You pay only for jobs returned.

## Actor input object example

```json
{
  "sources": [
    "remoteok",
    "jobicy"
  ],
  "region": "any",
  "onlyNew": false,
  "descriptionMaxChars": 1000,
  "strictSources": false,
  "maxItems": 20
}
```

# Actor output Schema

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

One item per job, newest first.

# 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 = {
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("itayozer9/remote-jobs-api").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 = { "maxItems": 20 }

# Run the Actor and wait for it to finish
run = client.actor("itayozer9/remote-jobs-api").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 '{
  "maxItems": 20
}' |
apify call itayozer9/remote-jobs-api --silent --output-dataset

```

## MCP server setup

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

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/iOsQQQT4x3FePcDiy/builds/WG6SNK3NmX2h8PKNR/openapi.json
