# Remote Jobs Scraper: We Work Remotely, RemoteOK, Python.org (`humble-echidna/remote-jobs`) Actor

Remote and work-from-home job listings from We Work Remotely, Remote OK and Python.org Jobs in one clean format, with salary, employment type and categories. Filter by keyword, region, category or date, merge duplicates across boards, or get only jobs new since your last run. Links to each source.

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

## Pricing

from $1.40 / 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

### What does Remote Jobs Scraper do?

**Remote Jobs Scraper** collects **remote and work-from-home job listings** from **[We Work
Remotely](https://weworkremotely.com)**, **[Remote OK](https://remoteok.com)** and **[Python.org
Jobs](https://www.python.org/jobs/)** (its remote postings) through their official public feeds, and returns them in
**one clean format**, filtered by keyword, region, category or date, with the same job on several boards merged into
one record. No login.

The listings belong to the boards and the employers who posted them. Every record says which board it came from and
links to the original listing there.

[Input fields](https://apify.com/humble-echidna/remote-jobs/input-schema) ·
[API](https://apify.com/humble-echidna/remote-jobs/api) ·
[Use it from Claude, ChatGPT or Cursor (MCP)](#can-i-use-remote-jobs-scraper-from-an-ai-agent-mcp)

**Jump to:** [Monitor](#monitor-new-remote-jobs) · [Fields](#what-data-does-remote-jobs-scraper-return) ·
[Price](#how-much-does-it-cost-to-scrape-remote-jobs) · [How to use](#how-to-scrape-remote-jobs) ·
[Input](#input) · [Output](#output) ·
[Sources](#where-the-remote-jobs-come-from-and-the-boards-terms) ·
[AI agents (MCP)](#can-i-use-remote-jobs-scraper-from-an-ai-agent-mcp) · [Limits](#limits) ·
[FAQ](#faq)

**Try it in one click:** the input comes pre-filled with all three boards and a limit of 50 jobs, newest first.
That's roughly $0.10 (50 × $0.002 per job, plus $0.00005 for the run start). **Then add your own keywords, regions
or categories.**

### Monitor new remote jobs

Remote Jobs Scraper can check the boards on a schedule and give you only the jobs you haven't had yet. Set it up once:

1. **Save a task.** Set your **Keywords**, **Locations / regions** or **Categories**, turn on **Only jobs new since my
   last run** (`onlyNewJobs: true` in the API), then click **Save as a new task** at the top right of the actor's
   page. The first run returns everything that matches (up to **Max jobs per run**); later runs return only jobs you
   haven't had yet.
2. **Schedule it.** In Apify Console, open **Schedules**, click **Create new**, pick the task and set how often it runs
   (for example every 6 hours, cron `0 */6 * * *`).
3. **Send the new jobs where you work,** from the task's **Integrations** tab:
   - **Slack:** a message in the channel you choose when a run succeeds (you pick the events and can edit the
     message).
   - **Email:** *Send results email via Gmail* sends the run's results, with the dataset attached.
   - **Webhook:** a POST to your URL on the `ACTOR.RUN.SUCCEEDED` event. The payload's `resource.defaultDatasetId`
     points to the new jobs: `GET https://api.apify.com/v2/datasets/<defaultDatasetId>/items?format=json` with your
     API token.
   - **Make, Zapier or n8n:** each has an Apify step that starts on a finished run and reads its dataset.

A run that finds nothing new returns 0 jobs and costs only the $0.00005 start fee. Slack and email are sent for every
successful run, including a quiet one; to hear only about new jobs, use the webhook or Make/Zapier/n8n and skip runs
whose dataset is empty. Add the **run failed** event too, so a failed run doesn't go unnoticed. Keep the task's
filters fixed: the memory is per board and per filter combination, so changing them starts a fresh search. If you
republish the jobs, keep each job's `source` and `url` (see the boards' terms below).

### What data does Remote Jobs Scraper return?

| Field | Example | Notes |
|---|---|---|
| `title` | `Software Developer Security Analytics` | |
| `companyName` | `RedMimicry` | |
| `source`, `url` | `Remote OK`, `https://remoteOK.com/remote-jobs/...` | The board and the original listing: keep both when you use the job. |
| `location`, `locations`, `country` | `Georgia, United States`, `United States` | Where candidates can work from; `country` only when exactly one country is named. |
| `employmentType` | `FULL_TIME` | One of `FULL_TIME`, `PART_TIME`, `CONTRACT`, `TEMPORARY`, `INTERNSHIP`, `VOLUNTEER`, or `null`. |
| `postedAt` | `2026-09-22T09:00:01Z` | ISO 8601 UTC; `null` for Python.org jobs (its feed has no dates). |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod` | `69000`, `77000`, `EUR`, `YEAR` | `null` when the listing gives no pay. |
| `salaryText`, `salarySource` | `EUR 69,000 – 77,000`, `description` | `ats` from the board's salary field, `description` from the job text. |
| `categories`, `tags` | `software-development`, `golang` | Every board's categories mapped onto one list. |
| `description` | `Remote - Location: Mostly remote...` | Plain text. |
| `alsoListedOn` | `[]` | The same job on another board, when it was merged. |
| `id` | `remoteok:redmimicry:1137417` | Stable across runs, for deduplication. |

Every job has the same fields; the full record is under [Output](#output).

### How much does it cost to scrape remote jobs?

You pay per job returned: **$2.00 per 1,000 jobs**, plus $0.00005 each time a run starts. Filters and duplicate
merging happen before you're charged, so you only pay for jobs you keep, and a repeat run with nothing new costs only
the start fee.

**It's cheaper on paid Apify plans:** $1.80 per 1,000 jobs on Starter, $1.60 on Scale and $1.40 on Business. The prices on this page are the Free-plan price, so on a paid plan you pay less than the examples show.

- **The example below:** 50 jobs × $0.002 = $0.10, plus the $0.00005 start fee.
- **A month, for example:** a first run of all ~350 current jobs ($0.70), then, if about 40 new jobs a day match your
  filters, 1,200 × $0.002 = $2.40: **about $3.10**, plus the run starts.
- **Caps:** **Max jobs per run** in the input (pre-filled with 50 in the form, 100 when an API call leaves it out;
  raise it, e.g. to 1000, for every matching job), and **Maximum cost per run** in the run options; it stops cleanly
  at whichever comes first. Jobs are returned newest first. If the maximum cost
  doesn't cover a single job, nothing is fetched at all.

### How to scrape remote jobs

1. Open the actor. All three boards are selected under **Job boards**.
2. Add **Keywords** (e.g. `python`), **Locations / regions** (e.g. `Europe`) or **Categories** to narrow the list.
3. Click **Start**.
4. Open the **Output** tab and export the jobs as JSON, CSV or Excel, or read them through the API.
5. For job alerts, save it as a task and schedule it (see *Monitor new remote jobs* above).

### Example: the newest 50 jobs, then the next run

The pre-filled input (all boards, the 50 newest jobs), with **Only jobs new since my last run** turned on:

```json
{"sources": ["weworkremotely", "remoteok", "pythonorg"], "maxResults": 50, "onlyNewJobs": true}
```

One of the 50 jobs (real output from a local run on 2026-09-25; `description` and `tags` shortened):

```json
{
  "id": "remoteok:redmimicry:1137417",
  "platform": "remoteok",
  "source": "Remote OK",
  "companyName": "RedMimicry",
  "title": "Software Developer Security Analytics",
  "remote": true,
  "employmentType": "FULL_TIME",
  "postedAt": "2026-09-22T09:00:01Z",
  "url": "https://remoteOK.com/remote-jobs/remote-software-developer-security-analytics-redmimicry-1137417",
  "salaryMin": 69000.0,
  "salaryMax": 77000.0,
  "salaryCurrency": "EUR",
  "salaryPeriod": "YEAR",
  "salaryText": "EUR 69,000 – 77,000",
  "salarySource": "description",
  "description": "Remote - Location: Mostly remote (within Germany), with monthly in-person collaboration at our Berli...",
  "tags": ["golang", "infosec", "dev", "..."],
  "categories": ["software-development", "data", "security"]
}
```

Where a job can be done from comes back as plain text and a country name. A We Work Remotely listing from the same
run, whose employer (headquartered in Atlanta) picked the country Georgia for the US state:

```json
{
  "id": "weworkremotely:iterable:iterable-email-deliverability-consultant",
  "location": "Georgia, United States",
  "locations": ["Georgia, United States"],
  "country": "United States"
}
```

The default input without the 50-job cap returned 349 jobs that day (before Python.org was added). With the cap, a second run straight after returned the
next 50 it hadn't returned yet; once the backlog is used up, runs return only newly posted jobs.

### Ready-to-run examples

Each example opens with the input already filled in. Run it as it is, or change the input first.

- **[Find remote Python developer jobs](https://apify.com/humble-echidna/remote-jobs/examples/remote-python-jobs)**: Collect remote Python jobs from We Work Remotely, RemoteOK and the Python.org job board in one list, de-duplicated, with company, salary where posted and apply link.
- **[Get new remote jobs every day without duplicates](https://apify.com/humble-echidna/remote-jobs/examples/daily-new-remote-jobs)**: Run daily and get only remote jobs posted since the last run across several boards, with duplicates across boards removed.

### Input

| Field | What it does |
|---|---|
| **Job boards** | We Work Remotely, Remote OK and Python.org Jobs (remote postings only). All three by default. |
| Keywords | Keep jobs whose title or tags contain any of these words (case-insensitive). |
| Exclude title keywords | Drop jobs whose title contains any of these words. |
| Locations / regions | Keep jobs open to candidates in any of these (e.g. `USA`, `Europe`, `Germany`), matched against the listing's location or region. A country's short form finds its full name (`USA` finds "United States", `UK` "United Kingdom"). Jobs open worldwide always match; jobs that give no location are dropped. |
| Categories | Keep jobs in any of these categories (software development, DevOps, data, security, design, product, customer support, sales and marketing, management and finance, writing, HR, other). |
| Posted within (days) | Only recently published jobs. |
| Only jobs new since my last run | First run returns everything that matches; later runs return only jobs you haven't had yet. Remembered in your own Apify storage, per board and per filter combination. |
| Merge duplicates across boards | On by default. |
| Max jobs per run | Cap the total number of jobs, newest first. Pre-filled with 50 in the console; 100 when left out of an API call. Raise it (e.g. 1000) for every matching job. |

```json
{
  "sources": ["weworkremotely", "remoteok", "pythonorg"],
  "keywords": ["python", "backend"],
  "excludeKeywords": ["intern"],
  "locations": ["Europe", "Germany"],
  "categories": ["software-development"],
  "postedWithinDays": 7,
  "onlyNewJobs": true,
  "maxResults": 200
}
```

### Output

Every job has the same fields. Fields a board doesn't publish are `null`.

```json
{
  "id": "remoteok:omega-enterprises:1137418",
  "platform": "remoteok",
  "source": "Remote OK",
  "sourceUrl": "https://remoteok.com",
  "company": "omega-enterprises",
  "companyName": "Omega Enterprises",
  "title": "Junior Digital Assets Operations Analyst",
  "department": null,
  "team": null,
  "location": null,
  "locations": [],
  "country": null,
  "remote": true,
  "workplaceType": "remote",
  "employmentType": "PART_TIME",
  "postedAt": "2026-09-22T14:36:54Z",
  "updatedAt": null,
  "url": "https://remoteOK.com/remote-jobs/remote-junior-digital-assets-operations-analyst-omega-enterprises-1137418",
  "applyUrl": "https://remoteOK.com/remote-jobs/remote-junior-digital-assets-operations-analyst-omega-enterprises-1137418",
  "salaryMin": 60000,
  "salaryMax": 80000,
  "salaryCurrency": "USD",
  "salaryPeriod": "YEAR",
  "salaryText": "USD 60,000 - 80,000 per year",
  "salarySource": "ats",
  "description": "Plain-text job description…",
  "tags": ["other", "crypto", "remote", "education", "web3", "bitcoin", "ethereum", "part time", "finance",
           "blockchain", "defi", "junior", "analyst", "ops"],
  "categories": ["management-finance"],
  "alsoListedOn": [],
  "scrapedAt": "2026-09-24T16:00:00Z"
}
```

- `source` and `url`: the board and the original listing. Keep both when you use the job.
- `location`, `locations` and `country`: where candidates can work from, as the board lists it, cleaned up.
  `country` is a plain country name ("United States", "South Korea") when the listing names exactly one country,
  else `null`: several countries, a region ("North America"), a city with no country ("London"), or nothing.
  - We Work Remotely: "Anywhere in the World" becomes `Worldwide`, used only when the listing names nothing
    narrower; a state is given with its country ("California, United States"); several places are separated by
    `; ` in `location` and listed one by one in `locations`. The boards' flag emojis and long official names
    ("United Kingdom of Great Britain and Northern Ireland") are replaced by short names. Employers in the US state
    of Georgia often pick the country Georgia: a listing whose only country is Georgia (or Georgia and the US) is
    read as the US state when anything in it points to the US (the US itself, a US state, or a headquarters line
    such as "Atlanta" or ", GA"); otherwise it stays the country.
  - Remote OK: the employer's own text, with repeated and empty parts removed ("Austin, Austin, Texas, United
    States" becomes "Austin, Texas, United States"); `country` is read from its last part when that names a
    country or a US state. A bare "Georgia" is left as an unknown country.
  - Python.org Jobs: the posting's location line, cleaned the same way ("Remote, Remote, Worldwide" becomes
    "Remote, Worldwide").
- `description`: plain text. For Remote OK jobs it ends with Remote OK's anti-spam line, unchanged (see below).
- `postedAt`: a listing dated in the future (it happens) is given the run's time instead. Python.org's feed
  publishes no dates, so its jobs have `postedAt: null`: **Posted within (days)** keeps them (undated jobs are never
  silently dropped) and they come after the dated jobs, newest first.
- Python.org Jobs is a Python job board, not a remote one: only postings whose location or title says remote,
  anywhere, worldwide or telecommute are returned. Each is tagged `python`; its employment type is `null` (the feed
  doesn't give one).
- `alsoListedOn`: the same job on other boards, each with `source`, `url` and `id`.
- `salarySource`: `ats` when the board's own salary field gave it, `description` when it came from the job text.
- `id` is stable across runs, so you can use it to deduplicate.

### Where the remote jobs come from, and the boards' terms

Each board allows its listings to be reused **on conditions**, and this actor keeps them. If you publish the
jobs somewhere, **you need to keep them too**:

| Board | What it asks | What the actor does |
|---|---|---|
| **We Work Remotely** ([terms](https://weworkremotely.com/remote-job-rss-feed)) | "Anyone can use the feed, all we ask is that you attribute the links back to We Work Remotely." | Every record has `source` and the original listing `url` on weworkremotely.com. |
| **Remote OK** ([API terms](https://remoteok.com/api), [legal](https://remoteok.com/legal)) | Link back to the job's URL on Remote OK (a normal "follow" link, no `nofollow`) and mention Remote OK as the source, wherever you use the data. Don't use the Remote OK logo. | Every record has `source` and its Remote OK `url`. No logos are included. Requests keep the 1-second crawl delay in Remote OK's robots.txt. |
| **Python.org Jobs** ([legal statements](https://www.python.org/about/legal/), [feed](https://www.python.org/jobs/feed/rss/)) | Job postings are the employers' content, and under "Third-Party Content" their providers "grant the PSF and all other users of the web site an irrevocable, worldwide, royalty-free, nonexclusive license to reproduce, distribute, transmit, display, perform, and publish such content". The rest of python.org is the PSF's, all rights reserved. | Only the postings from the public jobs feed are taken, nothing else from python.org. Every record has `source` and the posting's `url` on python.org. One request per run. |

**Never present these jobs as your own postings,** and keep each job's `source` and `url` wherever you show it.
The actor identifies itself honestly to each board and follows each board's robots.txt.

**Remote OK's anti-spam line:** every Remote OK description ends with a line like "Please mention the word …
and tag … when applying". It is part of how Remote OK protects its listings and traces reuse, so the actor
passes it on exactly as Remote OK wrote it, in `description`, and does not strip or change it.

### Run it on a schedule, or from your own code

- **Schedule:** save the input as a [task](https://docs.apify.com/platform/actors/running/tasks) and add it to a
  [schedule](https://docs.apify.com/platform/schedules), as in *Monitor new remote jobs* above.
- **[API](https://apify.com/humble-echidna/remote-jobs/api):** fetch a task's latest results with
  `GET https://api.apify.com/v2/actor-tasks/<task id>/runs/last/dataset/items?status=SUCCEEDED&format=csv` and your
  API token (`format` can also be `json` or `xlsx`).
- **Webhooks and automation:** a [webhook](https://docs.apify.com/platform/integrations/webhooks) when a run
  succeeds, or Make, Zapier or n8n through [Apify's integrations](https://docs.apify.com/platform/integrations).

#### Can I use Remote Jobs Scraper from an AI agent (MCP)?

Yes, through [Apify's MCP server](https://docs.apify.com/platform/integrations/mcp), from Claude, ChatGPT, Cursor or
any other MCP client. Add this to your client's MCP configuration (or let the agent find it with the server's actor
search); your client signs you in to Apify:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=humble-echidna/remote-jobs"
    }
  }
}
```

To use an [Apify API token](https://console.apify.com/settings/integrations) instead of signing in, add
`"headers": {"Authorization": "Bearer <APIFY_TOKEN>"}` next to `url`.

The agent passes the same input JSON as above. Have it set **Max jobs per run** (`maxResults`) to keep answers small.

### Who it's for

Remote-job boards and newsletters that republish listings (with the attribution the boards ask for), people running
their own remote-job alerts, and salary and market research (pay ranges as numbers, with currency and period, across
boards). The recurring job: schedule it every few hours with **Only jobs new since my last run**, and each run
returns a deduplicated list of the jobs you haven't had yet, in the same format as our company career-page scrapers.

### Why this one?

- **One flat price, no usage bill.** You pay per result at the price above and nothing else: no compute, proxy or storage charges on top, apart from the $0.00005 run-start fee, so you know what a run costs before it starts. Results you don't get aren't charged.
- **Three boards, one format.** Employment type is always one of `FULL_TIME`, `PART_TIME`, `CONTRACT`,
  `TEMPORARY`, `INTERNSHIP`, `VOLUNTEER`; dates are ISO 8601 UTC; each board's categories and tags are mapped
  onto one category list. The format is the same as our
  [Company Career Page Jobs Scraper](https://apify.com/humble-echidna/ats-jobs), so results from both can go in
  one table.
- **Duplicates merged.** When the same company posts the same job title on several boards, you get it once: the
  most complete listing, with the other boards' listings kept in `alsoListedOn` (name and link).
- **Salary as numbers** with currency and period, from the board's own salary field, or from the job text when
  the employer wrote the pay range there ("$100,000-$125,000", "£20–£40/hour"). Obvious placeholders (a range
  of "1 - 2", or "10,000 - 750,000") are dropped rather than passed on.
- **Only new jobs since your last run**, for job alerts on a schedule.
- **Attribution built in.** Every record carries the `source` and original `url` the boards' terms ask for.
- **Reliable.** A board that's down never affects the others in your run, and a listing that doesn't parse is
  skipped instead of failing its board. The run log and the `RUN_STATS` record say exactly which board had a
  problem and why.

### Limits

- Each board's feed carries its **recent** listings, not its whole archive: currently about 100 on Remote OK, each
  We Work Remotely category's current listings (about 250 in total), and the 20 newest Python.org postings (about
  half of them remote). Running regularly with
  **Only jobs new since my last run** is how you build a complete history.
- The location filter matches words, not geography: `Europe` doesn't match a job that only says `Germany`. Add
  both. A job whose only location is a city ("Stockholm", "London") has no country, so a country filter won't
  match it.
- Three boards only (see the FAQ for why). Python.org jobs have no posting date.

### FAQ

#### Can I publish these remote jobs on my own site?

The boards allow it on their conditions: credit the board and link
each job to its original listing (a normal "follow" link for Remote OK), and don't present the jobs as your own
postings. Read each board's terms (linked above) before you do.

#### Why only these three boards?

The actor only includes boards whose published terms allow this kind of automated, commercial reuse in a way it
can keep for every user, with a public feed that needs no key and that robots.txt allows. More than 25 other
job boards were reviewed (September 2026) and left out for now: most license their listings for personal,
non-commercial use only or forbid automated access; some ask that their jobs not be passed on to other job sites or
job boards; some need an API key or registration; some limit how often they can be polled in a way that can't be
guaranteed across many users running the actor at once; and some have no feed at all. More boards may be added
when their terms fit.

#### Why does something that used to work now fail or return fewer results?

A board may have changed its feed without
notice, or one of its feeds may be down. The run's status message and log name the board and what went wrong
(a whole board, or one of We Work Remotely's category feeds), and the rest of the run is unaffected. With **Only
jobs new since my last run**, jobs that were missing only because a feed failed are not returned again once it
recovers. Please open an issue with the input you used.

#### Is it legal to scrape remote jobs from these boards?

It reads only the official public feeds of these boards, whose terms allow reuse (quoted above: We Work Remotely
and Remote OK on attribution, Python.org by the licence its posters grant every user of the site), follows their
robots.txt and their stated conditions, uses no login or key, and collects no personal data: job listings only.
Keep each job's `source` and `url` wherever you use it.

### Related actors

| Actor | Use it when |
|---|---|
| [Company Career Page Jobs Scraper](https://apify.com/humble-echidna/ats-jobs) | You want every open job from companies you name, straight from their career pages (Greenhouse, Lever, Ashby, Recruitee, Personio, Teamtailor), in this same format, so both can go in one table. |
| [Dataset Transformer](https://apify.com/humble-echidna/dataset-transform) | You want to filter, dedupe and export CSV for a job board or newsletter. |

### Feedback and support

Found a bug, or need a field or board that isn't here? Open an issue on the **Issues** tab with the input you used.

### Versions

Current version: **1.2**. See the Changelog tab for what changed in each version.

# Changelog

This Actor's version history is a separate document: https://apify.com/humble-echidna/remote-jobs/changelog.md

# Actor input Schema

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

Which remote job boards to read: `weworkremotely` (We Work Remotely), `remoteok` (Remote OK) and/or `pythonorg` (Python.org Jobs, its remote postings only). Default all three. A board that is down never affects the others.

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

Keep only jobs whose title or tags contain any of these words (case-insensitive), one per line, e.g. python, designer. Leave empty (the default) for all jobs.

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

Drop jobs whose title contains any of these words, one per line, e.g. senior, intern. Leave empty (the default) to drop nothing.

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

Keep only jobs open to candidates in any of these, matched against the job's location or region text, e.g. USA, Europe, Canada, UK. Jobs open worldwide ("Anywhere", "Worldwide") always match. Jobs that give no location are dropped when this is set.

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

Keep only jobs in any of these categories. Each board's own categories and tags are mapped onto this one list. Leave empty for all.

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

Keep only jobs published in the last N days, e.g. 7. Minimum 1; leave empty (the default) for all.

## `onlyNewJobs` (type: `boolean`):

Default false. When true, the first run returns all matching jobs and later runs return only jobs you haven't had yet. What was returned is remembered in your own Apify account, separately for each board and each combination of filters, so different searches never hide each other's jobs. Changing the filters starts a fresh search.

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

Default true: when the same company posts the same job title on more than one board, return it once. The most complete listing is kept, and the other boards' listings stay credited in its alsoListedOn field with their own links.

## `maxResults` (type: `integer`):

Stop after this many jobs in total, newest first, 1 or more (default 100, pre-filled with 50 in the form). Raise it (e.g. 1000) to get every matching job, typically several hundred with the other defaults; a small number keeps agent answers small. The run also stops cleanly at the maximum cost per run you set in the run options, whichever comes first.

## Actor input object example

```json
{
  "sources": [
    "weworkremotely",
    "remoteok",
    "pythonorg"
  ],
  "onlyNewJobs": false,
  "dedupe": true,
  "maxResults": 50
}
```

# Actor output Schema

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

No description

## `runStats` (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 = {
    "sources": [
        "weworkremotely",
        "remoteok",
        "pythonorg"
    ],
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("humble-echidna/remote-jobs").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "sources": [
        "weworkremotely",
        "remoteok",
        "pythonorg",
    ],
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("humble-echidna/remote-jobs").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "sources": [
    "weworkremotely",
    "remoteok",
    "pythonorg"
  ],
  "maxResults": 50
}' |
apify call humble-echidna/remote-jobs --silent --output-dataset

```

## MCP server setup

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

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/oH4TDRSFwW86iiw2x/builds/FxsLYLeSJKhfutDCe/openapi.json
