# Remote Jobs Scraper & Aggregator – 6 Boards, Job Alerts (`gazidev/remote-jobs-aggregator`) Actor

All remote jobs in one clean, deduplicated JSON feed from official APIs & RSS: Himalayas, Remote OK, Jobicy, Arbeitnow, plus opt-in Remotive and We Work Remotely. Filter by keyword, category, region, salary (annual USD) and date. Only-new mode for daily job alerts.

- **URL**: https://apify.com/gazidev/remote-jobs-aggregator.md
- **Developed by:** [Cemal Atakli](https://apify.com/gazidev) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 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 Scraper & Aggregator – 6 Boards, Job Alerts

Get **remote jobs from up to 6 job boards in one clean, deduplicated JSON feed**. The Actor reads each board's official public API or RSS feed: **Himalayas, Remote OK, Jobicy and Arbeitnow** by default, with **Remotive and We Work Remotely** as opt-in sources. It does not scrape HTML, run a browser or use proxies.

- **6 boards, one schema, no duplicates.** When the same opening appears on several boards, you get one record, and the other boards are listed in `also_listed_on`.
- **Filters that work across boards.** Filter by keyword, category, region (for example, `Europe` also matches Germany), minimum salary normalized to annual USD, employment type and posting date.
- **Job alerts for $1.50 per 1,000 jobs.** Only-new mode charges only for jobs you haven't received yet, plus $0.005 per run.

### Quick start

This is the prefilled input. It returns 3 of this week's Python or React remote jobs in seconds, for less than $0.01. Raise `maxItems` for real use.

```json
{ "keywords": ["python", "react"], "postedWithinDays": 7, "maxItems": 3, "maxJobsPerSource": 40 }
```

#### Sample output

| title | company | source\_name | salary (USD/year) | category | also\_listed\_on |
|---|---|---|---|---|---|
| Video Data Annotator | iMerit Technology | Remote OK | 70,000–80,000 | Data & AI | weworkremotely |
| Associate Project Manager | Fortive | Himalayas | 70,600–117,900 | Project & Operations | – |
| Account Executive Mid-Market - Italy | Alma | Jobicy | 77,541–98,066 | Sales & Business Development | – |

#### Price comparison (Apify Store, September 2026)

| Actor | Price per 1,000 jobs | Monthly users |
|---|---|---|
| **Remote Jobs Scraper & Aggregator (this Actor)** | **$1.50** (+ $0.005 per run) | new |
| memo23/remote-jobs-aggregator | $1.99 | 117 |
| benthepythondev remote jobs aggregator | $15 | 80 |

**Related Actors:** [Greenhouse, Lever, Ashby & Workday Jobs API](https://apify.com/gazidev/ats-jobs-api) returns jobs straight from company career pages, and [Wappalyzer Alternative – Bulk Tech Stack Detector](https://apify.com/gazidev/tech-stack-detector) profiles the websites of hiring companies.

### What it does

- **6 official sources (4 on by default), one schema.** Every job comes with the same fields, whichever board it came from: title, company, logo, allowed locations, timezone restrictions, salary, employment type, seniority, tags, category, posted date, apply URL, source URL.
- **Cross-source deduplication.** The same opening posted on several boards is matched by normalized company name plus a fuzzy title match. It comes back as one record, and the other boards are listed in `also_listed_on`. Region variants such as "Engineer - UK" and "Engineer - Americas" are kept as separate jobs.
- **Salary normalization.** Hourly, monthly and other periods are converted to annual (hourly × 2080, monthly × 12…), then to USD using live ECB exchange rates. You can filter by `minSalaryUsd` across every board and currency. The original amount, currency and period are kept too.
- **Normalized categories.** 17 categories that are the same across boards (Software Development, Data & AI, DevOps, Design, Marketing, Sales, Customer Support…). The board's own category is also kept.
- **Region filter that understands geography.** `Europe` also matches Germany, Poland and other European countries. `USA` also matches "Northern America" and "US timezones". Worldwide jobs are included unless you turn that off.
- **Only new since last run.** Each saved search remembers which jobs it already delivered, in a named key-value store. A scheduled run returns and charges only jobs you haven't seen, including jobs you saw earlier on a different board.
- **Attribution kept.** Every record has `source_url` (the listing on the original board), `source_name` and an `attribution` line, as the boards' API terms require.

### Use cases

- Daily remote job alerts to Slack, email or Google Sheets (schedule + only-new mode + an Apify integration)
- Filling a niche remote job board or newsletter, with links back to the source boards
- Remote salary benchmarks by category, seniority and region
- Labour-market research: which companies hire remotely, and where
- Giving an AI job-search agent a fresh, structured remote job feed

### Input example

```json
{
  "keywords": ["python", "react"],
  "excludeKeywords": ["intern"],
  "categories": ["Software Development", "Data & AI"],
  "regions": ["Europe"],
  "includeWorldwide": true,
  "minSalaryUsd": 60000,
  "includeJobsWithoutSalary": true,
  "employmentTypes": ["full_time", "contract"],
  "postedWithinDays": 7,
  "sources": ["himalayas", "remoteok", "jobicy", "arbeitnow"],
  "onlyNewSinceLastRun": true,
  "stateKey": "python-europe-alert",
  "descriptionMode": "snippet",
  "maxItems": 200
}
```

Every field is optional. Clicking **Start** with the prefilled input returns 3 of this week's Python and React remote jobs (a quick, low-cost test run).

| Field | What it does |
|---|---|
| `keywords` / `excludeKeywords` | Whole-word, case- and accent-insensitive match. `develop*` matches as a prefix. Keywords are matched against the title, company, tags and full description. Exclude keywords are checked against the title and company. |
| `categories` | Normalized category, or the board's own category or tags (partial match). |
| `regions` | Where you can work from: country or region names. |
| `minSalaryUsd` | Top of the salary range, converted to annual USD. |
| `postedWithinDays` | 0 means any age. |
| `onlyNewSinceLastRun` + `stateKey` | Alert mode. The memory is kept for 60 days. |
| `descriptionMode` | `none`, `snippet` (500 characters) or `full` plain text. |
| `sources` | Boards to query. Default: `himalayas`, `remoteok`, `jobicy`, `arbeitnow`. Add `remotive` or `weworkremotely` to opt in. |
| `maxJobsPerSource` | How far back to page on Himalayas and Arbeitnow. |

### Output example

```json
{
  "id": "jobicy:151870",
  "title": "Account Executive Mid-Market - Italy",
  "company": "Alma",
  "company_logo": "https://jobicy.com/data/server-nyc0409/galaxy/mercury/2025/06/bcae38e1-221.jpeg",
  "locations": [
    "Italy"
  ],
  "is_worldwide": false,
  "timezone_restrictions": null,
  "salary_min": 68000.0,
  "salary_max": 86000.0,
  "salary_currency": "EUR",
  "salary_period": "year",
  "salary_min_annual": 68000.0,
  "salary_max_annual": 86000.0,
  "salary_min_usd_annual": 77541,
  "salary_max_usd_annual": 98066,
  "employment_type": [
    "full_time"
  ],
  "seniority": "Director",
  "tags": [
    "Sales"
  ],
  "category": "Sales & Business Development",
  "source_category": "Sales",
  "posted_at": "2026-09-26T11:30:15Z",
  "expires_at": null,
  "apply_url": "https://jobicy.com/jobs/151870-account-executive-mid-market-italy",
  "source": "jobicy",
  "source_name": "Jobicy",
  "source_url": "https://jobicy.com/jobs/151870-account-executive-mid-market-italy",
  "attribution": "Job via Jobicy (https://jobicy.com). Credit Jobicy and send applicants to source_url.",
  "description": "About Alma\nAt Alma, we believe sustainable commerce depends on fair, well‑balanced trade. …",
  "matched_keywords": null,
  "also_listed_on": null,
  "first_seen_at": "2026-09-26T22:31:55.692999Z"
}
```

When the same job is on several boards, `also_listed_on` lists the other boards. For example, *Video Data Annotator* at iMerit Technology was found on Remote OK and on We Work Remotely (with `weworkremotely` enabled).

A run summary is saved to the default key-value store as `OUTPUT`: jobs fetched per source, counts after filtering and dedupe, how many were skipped as already seen, and any per-source errors. If one board fails, the run continues with the others.

### Pricing

| | This Actor | Typical aggregator on the Store |
|---|---|---|
| Price per job | **$0.0015** | $0.00199 (memo23/remote-jobs-aggregator) to $0.015 (benthepythondev), Store prices 2026-09 |
| Start fee | $0.005 per run | varies |
| 1,000 jobs | **≈ $1.50** | ≈ $1.99 to $15 |
| Sources | 6 official APIs/RSS (4 default, Remotive + WWR opt-in) | varies |
| Cross-source dedupe, annual-USD salary, only-new alerts | Yes | varies |

With only-new mode you pay only for jobs you haven't seen. If you set a maximum cost per run, the Actor stops cleanly at that limit. Jobs it didn't deliver are not marked as seen, so they arrive in the next run.

### Sources and terms

| Source | Endpoint | Terms we follow |
|---|---|---|
| Himalayas | `himalayas.app/jobs/api` (+ `/search`) | Link back to the Himalayas URL and name Himalayas. Maximum 20 jobs per request, fetched with cursor paging. |
| Remote OK | `remoteok.com/api` | Link back to the Remote OK URL (followed link, no `nofollow`) and name Remote OK. The Remote OK logo is not used. |
| Jobicy | `jobicy.com/api/v2/remote-jobs` | Credit Jobicy and send applicants to the Jobicy URL. The Actor checks at most once per hour (responses are cached for 1 h). |
| Remotive | `remotive.com/api/remote-jobs` | Link back to the Remotive URL and name Remotive. At most about 4 requests per day (cached for 6 h). Remotive itself delays its jobs by 24 h. |
| We Work Remotely | `weworkremotely.com/remote-jobs.rss` | The public RSS feed, with links attributed back to WWR. Applications go through the WWR listing. |
| Arbeitnow | `arbeitnow.com/api/job-board-api` | Free public API, used lightly, with links back. Only jobs flagged `remote` are kept. |

**Your obligations when republishing:** show `source_name` and a followed link to `source_url` for every job. Remotive and Himalayas also ask that their jobs **not be submitted to third-party job sites** such as Jooble, Neuvoo, Google Jobs or LinkedIn Jobs. Remotive does not allow its jobs to be shown behind a sign-up or email wall. We Work Remotely's terms forbid building a service that competes with or replaces WWR. Remotive and We Work Remotely are off by default; if your use case conflicts with their terms, leave them off.

### FAQ

**How fresh is the data?** Every run reads the live feeds. The exceptions are Remotive, if enabled (cached up to 6 h, and delayed 24 h by Remotive itself) and Jobicy (cached up to 1 h), because those boards ask for infrequent polling.

**How many jobs per run?** Usually 500–800 unique remote jobs posted in the last week across the default boards. Keyword searches also query the Himalayas search endpoint, which reaches further back.

**Why doesn't every job have a salary?** Many postings don't publish one. Structured salaries come from Himalayas, Jobicy, Remote OK and (if enabled) Remotive, where Remotive's free-text salary is parsed. With `minSalaryUsd`, turn on `includeJobsWithoutSalary` if you still want jobs with no published salary.

**How does deduplication work?** Company names are normalized (Inc, GmbH, Ltd… removed). Titles are normalized: gender tags such as (m/w/d), "Remote", "100%", and Sr/Jr are handled. Two postings with the same company and a title similarity of 0.88 or more are merged. The record with the most detail is kept (salary, logo, locations), and missing fields are filled in from the duplicates.

**Can I run several alerts?** Yes. Give each saved task its own `stateKey`.

**Why only remote jobs from Arbeitnow?** Arbeitnow is mostly an on-site board for Europe. This Actor keeps only the postings Arbeitnow flags as remote.

### Use with AI agents / Apify MCP

The Actor works as a tool for Claude, ChatGPT, Cursor and other MCP clients through the **Apify MCP server** (`https://mcp.apify.com`). Add the Actor as a tool and the agent can call it with structured input, for example:

> "Find remote senior Python jobs open to Europe paying at least $90k, posted this week."

The agent fills in `keywords`, `regions`, `minSalaryUsd` and `postedWithinDays`, and gets back small JSON records. Use `descriptionMode: "none"` or `"snippet"` to keep context small. `source_url` gives the agent a link it can cite. You can also call the Actor from the Apify API, the Python or JS client, Make, Zapier or n8n.

# Actor input Schema

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

Job must match at least one keyword (title, company, tags, category or description). Case- and accent-insensitive whole words; add \* for prefix match (e.g. `develop*`). Leave empty for all jobs.

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

Drop jobs whose title or company contains any of these words (e.g. `senior`, `sales`).

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

Keep jobs in any of these categories. Matches the normalized category (Software Development, Data & AI, DevOps & Infrastructure, Security, QA & Testing, Design, Product, Project & Operations, Marketing, Sales & Business Development, Customer Support, Writing & Content, Finance & Legal, HR & Recruiting, Healthcare, Education, Other) and the source's own category/tags. Partial, case-insensitive.

## `regions` (type: `array`):

Keep jobs open to candidates in any of these places, e.g. `Europe`, `USA`, `UK`, `Canada`, `LATAM`, `APAC`, `Germany`. Region names also match their countries (Europe → Germany, Poland…).

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

When a region filter is set, also keep jobs open worldwide or with no location restriction.

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

Keep jobs whose top of range, normalized to annual USD (hourly×2080, monthly×12; live ECB FX rates), is at least this. Jobs without a published salary are dropped unless the option below is on.

## `includeJobsWithoutSalary` (type: `boolean`):

Only relevant when a minimum salary is set.

## `employmentTypes` (type: `array`):

Keep only these types. Leave empty for all.

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

Only jobs published in the last N days. 0 = any age.

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

Job boards to include. Remotive and We Work Remotely are opt-in: check their terms before enabling.

## `onlyNewSinceLastRun` (type: `boolean`):

Remember delivered jobs (per search, in a named key-value store) and output + charge only jobs not delivered before — including the same job re-posted on another board. Ideal with a daily/hourly schedule.

## `stateKey` (type: `string`):

Name for the only-new memory. By default it is derived from your filters, so changing filters starts a fresh alert. Set it to keep one memory across filter tweaks, or to run several independent alerts.

## `deduplicate` (type: `boolean`):

Same company + near-identical title on several boards → one record, other boards listed in `also_listed_on`.

## `descriptionMode` (type: `string`):

Include a plain-text description: none, a 500-character snippet, or the full text.

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

Upper limit of jobs output (and charged) per run, newest first.

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

Fetch depth for paginated sources (Himalayas, Arbeitnow). Higher = more history, slower run.

## Actor input object example

```json
{
  "keywords": [
    "python",
    "react"
  ],
  "excludeKeywords": [],
  "categories": [],
  "regions": [],
  "includeWorldwide": true,
  "includeJobsWithoutSalary": false,
  "employmentTypes": [],
  "postedWithinDays": 7,
  "sources": [
    "himalayas",
    "remoteok",
    "jobicy",
    "arbeitnow"
  ],
  "onlyNewSinceLastRun": false,
  "deduplicate": true,
  "descriptionMode": "snippet",
  "maxItems": 3,
  "maxJobsPerSource": 40
}
```

# Actor output Schema

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

No description

## `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",
        "react"
    ],
    "postedWithinDays": 7,
    "maxItems": 3,
    "maxJobsPerSource": 40
};

// Run the Actor and wait for it to finish
const run = await client.actor("gazidev/remote-jobs-aggregator").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",
        "react",
    ],
    "postedWithinDays": 7,
    "maxItems": 3,
    "maxJobsPerSource": 40,
}

# Run the Actor and wait for it to finish
run = client.actor("gazidev/remote-jobs-aggregator").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",
    "react"
  ],
  "postedWithinDays": 7,
  "maxItems": 3,
  "maxJobsPerSource": 40
}' |
apify call gazidev/remote-jobs-aggregator --silent --output-dataset

```

## MCP server setup

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

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/HopkSEjb1FdzKkTRC/builds/JyodpO62J1LjggjUN/openapi.json
