# Remote Jobs Scraper · 6 Boards, One Schema, Only New (`agentsgearbox/remote-jobs-scraper`) Actor

Remote jobs from Himalayas, Jobicy, Remote OK, We Work Remotely, Working Nomads and the Hacker News hiring thread in one schema: regions, type, level, category, annualized salary, links. Deduplicated, filtered before charging, only-new alerts. $0.60 per 1,000 jobs; first 50 a month free.

- **URL**: https://apify.com/agentsgearbox/remote-jobs-scraper.md
- **Developed by:** [AgentsGearbox](https://apify.com/agentsgearbox) (community)
- **Categories:** Jobs, AI, Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 75.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.36 / 1,000 jobs

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/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

Remote job listings from **six boards in one run, one schema, no duplicates**: Himalayas, Jobicy, Remote OK, We Work Remotely,
Working Nomads and the monthly Hacker News "Who is hiring?" thread (Remotive as an opt-in seventh). Each listing comes back as the
same row: title, company, the regions the job is open to, employment type, seniority, a normalized category, salary where the posting
states one (annualized for filtering), the description, dates and the link back to the board. Filter by keyword, category, region,
type, level, salary floor and posting date before anything is charged; the same job on several boards is delivered once with the
other listings recorded next to it; the since-last-run checkpoint turns a daily schedule into a job alert. **$0.60 per 1,000 jobs.**
A free `board` record per board reports how many listings it had and what they were, and the first 50 jobs each month are free for every account.

### Why this one

| | This actor |
|---|---|
| Six sources, one schema | Himalayas, Jobicy, Remote OK, We Work Remotely, Working Nomads and Hacker News "Who is hiring?", each read through the feed or API the board publishes for developers, normalized to the same fields. Remotive is available as an opt-in board (it delays listings by 24 hours and asks for a few requests a day). |
| Regions you can filter on | Every board words locations differently ("Anywhere in the World", "US only", "EMEA", "REMOTE (US/EU timezones)"); the actor turns them into `regions` such as `Worldwide`, `USA`, `Europe`, `UK`, `LATAM`, `APAC` and country names, plus a `worldwide` flag. |
| Salary you can compare | Structured salary from Himalayas, Jobicy and Remote OK; parsed from titles and descriptions elsewhere (`$120k–$150k`, `€60k-80k`, `$20/hr`); annualized into `salaryAnnualMin` and `salaryAnnualMax` so a salary floor works across periods. |
| No duplicates | The same company and title on several boards is delivered once; the other listings sit in `alsoOn` with their URLs, so you can still credit every board. |
| Filters at the source | Keywords, excluded keywords, categories, regions, worldwide only, employment type, seniority, minimum salary, stated salary only and `postedAfter` are applied before anything is charged. |
| Alerts | `onlyNewSinceLastRun` remembers the job IDs delivered and returns only new listings next time. |
| Price | $0.0006 per job, Apify's default $0.00005 start fee. No platform usage charged on top; `board` and `error` records are free. |

### What people use it for

- **Job alerts**: your keywords, regions, level and salary floor, once a day, into Slack, Telegram or e-mail through an Apify integration, with nothing repeated.
- **Job boards and newsletters**: a deduplicated feed of remote listings across six sources, with apply links, categories and salaries, ready to publish with the attribution each board asks for.
- **Recruiting and sourcing**: which companies are hiring remotely for a skill this week, and what the postings that state a salary pay.
- **Market research**: roles, levels, regions and stated pay across the remote market, snapshot by snapshot.
- **AI agents**: "find remote senior Python jobs open to Europe that pay at least 100k" as one tool call through the Apify MCP server.

### Example tasks

Ready-made configurations you can open, copy and run as they are:

- [Daily remote job alert: new jobs for your profile, six boards](https://apify.com/agentsgearbox/remote-jobs-scraper/examples/daily-remote-job-alert-for-your-profile): one profile (keywords, categories, regions) watched daily across six boards with the checkpoint on.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `boards` | array | the six | Any of `himalayas`, `jobicy`, `remoteok`, `weworkremotely`, `workingnomads`, `hackernews`, `remotive` (opt-in). |
| `keywords` | array | `[]` | Keep jobs whose title or tags contain any of these (`python`, `product manager`). |
| `excludeKeywords` | array | `[]` | Drop jobs whose title contains any of these. |
| `categories` | array | `[]` | `engineering`, `devops`, `data`, `security`, `design`, `product`, `customer-support`, `marketing`, `sales`, `finance`, `hr`, `legal`, `writing`, `education`, `healthcare`, `operations`, `management`, `other`. |
| `locations` | array | `[]` | Keep jobs whose location or regions contain any of these (`Worldwide`, `USA`, `Europe`, `UK`, `Germany`, `LATAM`, `APAC`). |
| `worldwideOnly` | boolean | false | Only jobs open to candidates anywhere. |
| `employmentTypes` | array | `[]` | `full-time`, `part-time`, `contract`, `freelance`, `internship`. |
| `seniority` | array | `[]` | `entry`, `mid`, `senior`, `lead`, `executive`. |
| `minSalary` | integer | – | Drop jobs whose annualized stated salary is below this (posting's currency; jobs without a salary pass). |
| `requireSalary` | boolean | false | Only jobs that state a salary. |
| `postedAfter` | string | – | `2026-10-01`, `24h`, `7d`, `30d`, `12w`. |
| `maxJobs` | integer | 300 | Newest first across all boards, after filters and deduplication. |
| `maxJobsPerBoard` | integer | 200 | How far back each board is read; at least 1,000 when filters or the checkpoint are on. |
| `includeDescription` | boolean | true | Description as text and HTML. |
| `dedupeAcrossBoards` | boolean | true | Same company and title on several boards → one row with `alsoOn`. |
| `hackerNewsThreads` | integer | 1 | How many monthly threads to read, newest first. |
| `onlyNewSinceLastRun` | boolean | false | Alert mode: only listings not delivered in earlier runs. |
| `checkpointStoreName` | string | `remote-jobs-state` | Key-value store for the alert state. |

```json
{
    "keywords": ["python", "typescript", "backend"],
    "categories": ["engineering", "devops", "data"],
    "locations": ["Worldwide", "Europe"],
    "seniority": ["mid", "senior", "lead"],
    "minSalary": 60000,
    "postedAfter": "7d",
    "maxJobs": 200,
    "includeDescription": false
}
```

### Output

Three record types share one dataset: job rows (no `type` field), one free `board` record per board read, and free `error` records.

**Job** ($0.0006). A real row from Himalayas, description shortened:

```json
{
  "jobId": "himalayas:microsourcing/jobs/junior-team-lead",
  "board": "himalayas",
  "boardName": "Himalayas",
  "source": "Himalayas",
  "sourceUrl": "https://himalayas.app",
  "title": "Junior Team Lead",
  "company": "MicroSourcing",
  "companyLogo": "https://cdn-images.himalayas.app/ljb1cfz67e0mktgbg8fiz42jr9hk",
  "location": "Philippines",
  "regions": [
    "Philippines"
  ],
  "worldwide": false,
  "timezones": [
    8
  ],
  "employmentType": "full-time",
  "employmentTypeRaw": "Full Time",
  "seniority": "entry",
  "seniorityRaw": "Entry-level",
  "category": "customer-support",
  "categoriesRaw": [
    "Customer Service",
    "Customer-Support-Team-Lead",
    "Customer-Service-Lead",
    "Support-Team-Lead",
    "Customer-Support-Specialist",
    "QA-Specialist"
  ],
  "tags": [
    "Customer-Support-Team-Lead",
    "Customer-Service-Lead",
    "Support-Team-Lead",
    "Customer-Support-Specialist",
    "QA-Specialist"
  ],
  "salaryMin": 40000,
  "salaryMax": 50000,
  "salaryCurrency": "PHP",
  "salaryPeriod": "month",
  "salaryText": "PHP 40,000 – 50,000 per month",
  "salaryAnnualMin": 480000,
  "salaryAnnualMax": 600000,
  "descriptionText": "Discover your 100% YOU with MicroSourcing !\nPosition: Junior Team Lead\nLocation: Metro Manila\nWork setup & shift: Work From Home | Shifting\nWhy join MicroSourci…",
  "descriptionHtml": "<h3>Discover your 100% YOU with <a href=\"https://himalayas.app/companies/microsourcing\">MicroSourcing</a>!</h3><p><strong>Position: </strong>Junior Team Lead<st…",
  "postedAt": "2026-11-03T14:33:52.000Z",
  "expiresAt": "2027-01-02T14:33:51.000Z",
  "url": "https://himalayas.app/companies/microsourcing/jobs/junior-team-lead",
  "applyUrl": "https://himalayas.app/companies/microsourcing/jobs/junior-team-lead?utm_source=api",
  "alsoOn": [],
  "scrapedAt": "2026-11-03T15:40:12.000Z"
}
```

A Hacker News row, parsed from the `Company | Role | Location | Type | Salary | link` line of the post (the full post is in the description fields):

```json
{
  "jobId": "hackernews:50350981",
  "board": "hackernews",
  "title": "Senior Full-Stack Engineer (Frontend-Leaning)",
  "company": "Marker Learning",
  "location": "Remote, US only",
  "regions": [
    "USA"
  ],
  "worldwide": false,
  "employmentType": "full-time",
  "seniority": "senior",
  "category": "engineering",
  "salaryText": "$180k–$200k",
  "salaryAnnualMin": 180000,
  "salaryAnnualMax": 200000,
  "postedAt": "2026-11-03T12:07:36.000Z",
  "url": "https://news.ycombinator.com/item?id=50350981",
  "applyUrl": "https://www.markerlearning.com",
  "thread": "Ask HN: Who is hiring? (November 2026)",
  "hnAuthor": "john-the-marker"
}
```

| Field | Type | Notes |
|---|---|---|
| `jobId` | string | `board:id`, stable; what the alert checkpoint remembers. |
| `board`, `boardName`, `source`, `sourceUrl` | string | Which board the row comes from, and the name the board asks to be credited with. |
| `title`, `company`, `companyLogo` | string or null | As the board publishes them. On Hacker News, parsed from the post's first line; a post with no recognisable role gets `Open roles at <company> (see the post)`. |
| `location`, `regions`, `worldwide`, `timezones` | misc | The board's wording, its normalized regions (`Worldwide`, `USA`, `Europe`, `UK`, `LATAM`, `APAC`, country and city names), whether it is open anywhere (`null` when the board states nothing), and Himalayas' UTC offsets. |
| `employmentType`, `employmentTypeRaw` | string or null | `full-time`, `part-time`, `contract`, `freelance`, `internship`, from the board's field or the title; the raw wording next to it. |
| `seniority`, `seniorityRaw` | string or null | `entry`, `mid`, `senior`, `lead`, `executive` from the board's level or the title (`Senior`, `Staff`, `Head of`, `Director`, `Junior`). |
| `category`, `categoriesRaw`, `tags` | misc | One of 18 categories mapped from the board's categories and the title; the board's own categories and tags as given. |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`, `salaryText` | misc | Structured from Himalayas, Jobicy and Remote OK (annual USD there); parsed from the text elsewhere. Null when the posting states no salary. |
| `salaryAnnualMin`, `salaryAnnualMax` | number or null | The stated range annualized in its own currency (monthly × 12, weekly × 52, daily × 260, hourly × 2,080). |
| `descriptionText`, `descriptionHtml` | string or null | The full posting; null when `includeDescription` is off. |
| `postedAt`, `expiresAt` | string or null | ISO 8601 UTC; `expiresAt` from Himalayas only. |
| `url`, `applyUrl` | string | The listing on the board (the link the boards ask you to keep) and the application link when the board publishes one. |
| `alsoOn` | array | Other boards that list the same company and title: `{board, boardName, url}`. |
| `thread`, `hnAuthor` | string | Hacker News rows only: the thread title and the posting account. |

**`board`** (free, one per board): `status` is `COMPLETE`, `PARTIAL` (your spending limit or `maxJobs` cut it), `EMPTY` or `ERROR`; `stoppedBy` is `endOfBoard`, `maxJobs`, `checkpoint`, `chargeLimit` or `error`:

```json
{
  "type": "board",
  "board": "himalayas",
  "boardName": "Himalayas",
  "boardUrl": "https://himalayas.app",
  "jobsFetched": 150,
  "jobsMatched": 150,
  "newSinceLastRun": null,
  "duplicatesRemoved": 2,
  "jobsDelivered": 148,
  "pagesRead": 8,
  "jobsOnBoard": 116257,
  "newestPostedAt": "2026-11-03T14:33:52.000Z",
  "oldestFetchedAt": "2026-11-03T08:55:18.000Z",
  "topCategories": [
    {
      "name": "engineering",
      "count": 32
    },
    {
      "name": "data",
      "count": 18
    },
    {
      "name": "marketing",
      "count": 15
    },
    {
      "name": "sales",
      "count": 13
    },
    {
      "name": "operations",
      "count": 12
    }
  ],
  "topRegions": [
    {
      "name": "USA",
      "count": 64
    },
    {
      "name": "Philippines",
      "count": 26
    },
    {
      "name": "Canada",
      "count": 13
    },
    {
      "name": "UK",
      "count": 11
    },
    {
      "name": "Germany",
      "count": 6
    }
  ],
  "status": "COMPLETE",
  "stoppedBy": "endOfBoard",
  "note": null
}
```

**`error`** (free): `{"type": "error", "board": "jobicy", "boardName": "Jobicy", "error": "Jobicy rate-limited this run (HTTP 429). Jobicy asks for at most one pass an hour; run again later."}`. A board that fails never fails the run: the other boards are delivered.

### Pricing and cost examples

**Try it free.** The first 50 jobs each calendar month are free for every Apify account, with nothing to enter: the actor keeps count in a small key-value store in your account (`free-slice-remote-jobs-scraper`) and charges only from the 51th on. The free results are real results you keep; the counter resets on the first of each month.

| Job | Jobs | Cost |
|---|---|---|
| A daily alert for one profile: keywords, region and salary floor, about 20 new matches a day | 600 a month | $0.36 a month |
| Everything new on the six boards today (no filters, `postedAfter: 24h`) | ≈ 300 | $0.18 |
| A snapshot of the newest 150 listings per board, deduplicated | ≈ 650 | $0.39 |
| A month of remote engineering postings for research | 5,000 | $3.00 |

Platform compute is included, descriptions too. Filtered-out listings, `board` records and errors cost nothing; the start fee is $0.00005 per run.

**Discounts for paid Apify plans**, applied automatically to the buyer's plan: Bronze 10% off, Silver 25% off, Gold and enterprise tiers 40% off the prices above. Free-plan users pay the listed price.

### Alerts: new jobs every morning

1. Create a task from this actor with your profile (`keywords`, `categories`, `locations`, `seniority`, `minSalary`) and `onlyNewSinceLastRun: true`.
2. Add an Apify schedule (daily is plenty; hourly at most, which is what the boards ask for).
3. Add an integration on the task: Slack, e-mail, Google Sheets, Make, Zapier, n8n or a webhook. Each run delivers only listings you have not seen; the `board` records tell you per board how much was read.

The checkpoint lives in the key-value store named in `checkpointStoreName`. To start over, change the name or delete the store.

### Run it from your code

Node.js:

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('agentsgearbox/remote-jobs-scraper').call({
    keywords: ['python'], locations: ['Worldwide', 'Europe'], seniority: ['senior', 'lead'], postedAfter: '7d', maxJobs: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((i) => i.jobId).map((i) => [i.title, i.company, i.regions.join('/'), i.salaryText, i.boardName, i.url]));
```

Python:

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("agentsgearbox/remote-jobs-scraper").call(run_input={
    "categories": ["design", "product"], "worldwideOnly": True, "requireSalary": True, "postedAfter": "30d", "maxJobs": 200})
jobs = [i for i in client.dataset(run["defaultDatasetId"]).iterate_items() if "jobId" in i]
```

cURL (synchronous, returns the dataset):

```bash
curl -X POST "https://api.apify.com/v2/acts/agentsgearbox~remote-jobs-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["react"], "locations": ["Worldwide"], "maxJobs": 50, "includeDescription": false}'
```

### For AI agents

Give your agent hands. Six job boards are six websites to read; this actor returns their listings as one JSON schema with regions, levels and annualized salaries already normalized, priced per job and known in advance. "Find me remote senior Python jobs open to Europe that pay at least 100k, posted this week" becomes one tool call.

- **MCP, this actor only:** add `https://mcp.apify.com?tools=agentsgearbox/remote-jobs-scraper` to Claude Desktop, Claude Code, Cursor or any MCP client (with your Apify token), then ask for "remote data engineering jobs open worldwide posted in the last 7 days with a stated salary".

* **MCP, all agentsgearbox actors:** `https://mcp.apify.com?tools=agentsgearbox/telegram-channel-scraper,agentsgearbox/google-play-reviews-scraper,agentsgearbox/substack-scraper,agentsgearbox/google-news-scraper,agentsgearbox/brand-name-generator,agentsgearbox/ai-readiness-audit,agentsgearbox/company-lookup,agentsgearbox/app-intelligence,agentsgearbox/app-store-reviews-scraper,agentsgearbox/company-jobs-scraper,agentsgearbox/apple-podcasts-scraper,agentsgearbox/remote-jobs-scraper`

- **No Apify account?** This actor is eligible for Apify's agentic payments: an agent can buy a spend-capped token through [agi.apify.com](https://agi.apify.com) (x402, MPP or Skyfire) and call the API directly.
- Prices are per job and known in advance, so the agent can set a spending limit; a board that cannot be read comes back as a free `error` record, not as a failed run.

### Limitations, stated plainly

- The actor reads what the boards publish: Remote OK and Working Nomads expose their newest listings only (about 100 and a few dozen), Himalayas and Jobicy page back as far as you ask, We Work Remotely gives the newest 100 per feed (category feeds are read when you filter by category or ask for more than 100), and the Hacker News thread is one month of posts.
- Hacker News posts are free text. The row is parsed from the first line's `Company | Role | Location | …` convention; posts that do not follow it get the company and `Open roles at … (see the post)` as the title, and candidates' own adverts are skipped. Read `descriptionText` for the details.
- Regions, categories, seniority and employment type are normalized from each board's fields and the title with rules, not guessed by a model; a job whose level the title does not reveal has `seniority: null`, and the raw values are kept next to the normalized ones.
- Salaries are copied or parsed, never estimated, and currencies are not converted: `minSalary` compares each posting in its own currency. Remote OK's ranges are what the employer entered on Remote OK, sometimes a wide placeholder.
- A listing's `worldwide` is `null` when the board states no restriction either way (Remote OK leaves most locations empty).
- Remotive is opt-in: Remotive delays its listings by 24 hours and asks for a few requests a day, so add it to hourly or daily schedules only. Arbeitnow is not read because its site licence is non-commercial.
- Postings are written by employers and belong to them, and each board asks to be credited: keep `boardName` and `url` next to any listing you republish, send applicants to the original posting, and do not resubmit listings to other job sites.

### Troubleshooting

| Symptom | Cause and fix |
|---|---|
| `jobsMatched: 0` with `jobsFetched` > 0 | The filters removed everything; the `board` record's `topCategories` and `topRegions` show what the board holds. Widen `locations` (a job open to `Europe` does not match `Germany`) or drop `seniority` (many titles state no level). |
| 0 jobs with the checkpoint on | Nothing new since the last run; `stoppedBy` is `checkpoint`. |
| `status: "PARTIAL"` | Your spending limit or `maxJobs` cut the run short; the `note` says which. Raise it or narrow the filters. |
| `error` from Jobicy with HTTP 429 | Jobicy allows one pass an hour; the other boards were delivered. Schedule the actor hourly at most. |
| A job you saw on a board is missing | It was delivered under another board that listed it first; look for it in `alsoOn`, or set `dedupeAcrossBoards: false`. |
| Hacker News rows with odd titles | The post did not follow the `Company | Role | Location` line; the description holds the full post. |

### Track record

- Published 3 November 2026 and tested every day since by an automated run on the Apify platform. The Store's run statistics on this page reflect those runs with a delay of up to a day.
- No browser, so a run cannot fail on Chrome crashes or memory limits; the six boards answer in a few seconds.
- Every actor from this account is monitored daily, so a change on a board's side is normally fixed the same day.

### More from agentsgearbox

- [Telegram Channel Scraper](https://apify.com/agentsgearbox/telegram-channel-scraper): public Telegram channels as JSON, no API key.
- [Google Play Reviews Scraper](https://apify.com/agentsgearbox/google-play-reviews-scraper): Google Play reviews with replies and versions, any market.
- [Substack Scraper](https://apify.com/agentsgearbox/substack-scraper): Substack posts with full text and comments, custom domains too.
- [Google News Scraper](https://apify.com/agentsgearbox/google-news-scraper): Google News with real publisher URLs and full text.
- [Brand & Business Name Generator](https://apify.com/agentsgearbox/brand-name-generator): brand names verified live on domains, handles and app stores.
- [AI Readiness Audit](https://apify.com/agentsgearbox/ai-readiness-audit): how well AI search engines and agents can read a site: crawler access, llms.txt, structured data, content without JavaScript, scored with fixes.
- [Company Lookup](https://apify.com/agentsgearbox/company-lookup): one row per domain with legal identity and VAT validation, contacts, socials, tech stack, open jobs, apps, news and Wikidata facts.
- [App Intelligence](https://apify.com/agentsgearbox/app-intelligence): App Store and Google Play in one run: search, top charts, full app details and each app's twin on the other store.
- [App Store Reviews Scraper · iOS + Google Play, Any Country](https://apify.com/agentsgearbox/app-store-reviews-scraper): Reviews of any iOS or Android app from both stores in one run: stars, text, version, votes, developer replies, since-last-run checkpoint, rating trend per app..
- [Company Jobs Scraper](https://apify.com/agentsgearbox/company-jobs-scraper): every open job on a company's careers page: nine applicant tracking systems, one schema, salaries where stated, hiring signals free.
- [Apple Podcasts Scraper](https://apify.com/agentsgearbox/apple-podcasts-scraper): Apple Podcasts search, charts, episodes with audio links and listener reviews, any country.

All of them are pay-per-event, run without a browser, and are compared with their alternatives on [agentsgearbox.com](https://agentsgearbox.com/actors/).

### Support

Open an issue on this actor's Issues tab, usually answered within a day, or email <support@agentsgearbox.com>. More actors and daily comparisons of scrapers for 200+ websites at [agentsgearbox.com](https://agentsgearbox.com).

### Legal and fair use

This actor is an independent tool, not affiliated with Himalayas, Jobicy, Remote OK, We Work Remotely, Working Nomads, Remotive, Hacker News or Y Combinator; their names are used only to say which boards it reads. It uses the public feeds and APIs those boards publish for developers, without keys, logins or workarounds, and follows each board's stated conditions: it names the source board on every row and links back to the listing, makes at most one pass per board per run, and reads Remotive only when you opt in. Keep those conditions downstream: credit the board next to any listing you display, link to `url`, send applicants to the original posting, and do not resubmit listings to other job sites or use the boards' logos. Postings belong to the employers who wrote them; store and index them for your own use and do not republish descriptions as your own content.

# Actor input Schema

## `boards` (type: `array`):

Which boards to read. Default: Himalayas, Jobicy, Remote OK, We Work Remotely, Working Nomads and the current Hacker News "Who is hiring?" thread. Remotive is opt-in: it delays listings by 24 hours and asks for a few requests a day, so add it only to runs that are scheduled hourly or less often.

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

Keep only jobs whose title or tags contain any of these (case-insensitive; a value with spaces is matched as a phrase), for example `python`, `product manager`, `react`. Empty means all jobs.

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

Drop jobs whose title contains any of these, for example `senior`, `intern`, `sales`.

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

Keep only jobs in these categories (the actor maps every board's own categories and titles to this list).

## `locations` (type: `array`):

Keep only jobs whose stated location or region contains any of these, for example `Worldwide`, `USA`, `Europe`, `UK`, `Germany`, `LATAM`, `APAC`. The actor normalizes each board's wording into regions (`Anywhere in the World` becomes `Worldwide`, `US only` becomes `USA`).

## `worldwideOnly` (type: `boolean`):

Keep only jobs open to candidates anywhere in the world.

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

Keep only these types. Jobs whose board states no type are dropped when this filter is set.

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

Keep only these levels, from the board's own field where it has one and otherwise from the title (`Senior`, `Staff`, `Head of`, `Director`, `Junior`, `Intern`). Jobs with no recognisable level are dropped when this filter is set.

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

Drop jobs whose stated salary, annualized, is below this amount. Compared in the posting's own currency (most are USD); jobs that state no salary pass unless `requireSalary` is on.

## `requireSalary` (type: `boolean`):

Drop jobs that state no salary.

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

Skip jobs posted before this: an ISO date such as `2026-10-01` or a relative value such as `24h`, `7d`, `30d`, `12w`. Jobs without a posting date are skipped too when this is set.

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

Newest first across all boards, after the filters and deduplication.

## `maxJobsPerBoard` (type: `integer`):

How far back each board is read, newest first. With filters or the checkpoint on, the actor reads at least 1,000 per board so that the filters have something to match.

## `includeDescription` (type: `boolean`):

Full description as text and HTML. Turn off for a lighter dataset; salary parsing still uses the description.

## `dedupeAcrossBoards` (type: `boolean`):

The same company and title on several boards is delivered once (the first board in your list keeps it) and the other listings are recorded in `alsoOn`.

## `hackerNewsThreads` (type: `integer`):

How many monthly "Who is hiring?" threads to read, newest first (1 = the current month).

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

For job alerts. Remembers the job IDs already delivered in a named key-value store and returns only new listings next time.

## `checkpointStoreName` (type: `string`):

Key-value store that keeps the list of seen job IDs (created automatically in your account). Use different names for independent alerts.

## Actor input object example

```json
{
  "boards": [
    "himalayas",
    "jobicy",
    "remoteok",
    "weworkremotely",
    "workingnomads",
    "hackernews"
  ],
  "keywords": [
    "engineer",
    "developer"
  ],
  "excludeKeywords": [],
  "categories": [],
  "locations": [],
  "worldwideOnly": false,
  "employmentTypes": [],
  "seniority": [],
  "requireSalary": false,
  "postedAfter": "7d",
  "maxJobs": 100,
  "maxJobsPerBoard": 200,
  "includeDescription": true,
  "dedupeAcrossBoards": true,
  "hackerNewsThreads": 1,
  "onlyNewSinceLastRun": false,
  "checkpointStoreName": "remote-jobs-state"
}
```

# Actor output Schema

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

Remote jobs as JSON (one item per job, one schema for every board), plus one free board summary per board read and free error records.

# 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 = {
    "boards": [
        "himalayas",
        "jobicy",
        "remoteok",
        "weworkremotely",
        "workingnomads",
        "hackernews"
    ],
    "keywords": [
        "engineer",
        "developer"
    ],
    "postedAfter": "7d",
    "maxJobs": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("agentsgearbox/remote-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 = {
    "boards": [
        "himalayas",
        "jobicy",
        "remoteok",
        "weworkremotely",
        "workingnomads",
        "hackernews",
    ],
    "keywords": [
        "engineer",
        "developer",
    ],
    "postedAfter": "7d",
    "maxJobs": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("agentsgearbox/remote-jobs-scraper").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 '{
  "boards": [
    "himalayas",
    "jobicy",
    "remoteok",
    "weworkremotely",
    "workingnomads",
    "hackernews"
  ],
  "keywords": [
    "engineer",
    "developer"
  ],
  "postedAfter": "7d",
  "maxJobs": 100
}' |
apify call agentsgearbox/remote-jobs-scraper --silent --output-dataset

```

## MCP server setup

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

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/sduVY5y1ARuBoZbwL/builds/oa0rJK6Rqah9FirsP/openapi.json
