How to use it: 3 steps
- Make a free Apify accountApify is the cloud platform where our tools run. The free plan gives you $5 of usage every month, no credit card needed. You pay Apify, not us.
- Paste your input and press StartNo code needed: you fill in a form (the input). It already has a working example. For example:
pythonin Keywords. Each start is one run. - Download the resultsWhen the run ends, the results are in a table (the dataset). Open Output, press Export and pick Excel or CSV. JSON and the API are there too.
This tool is an Apify Actor: a small program that runs on Apify. You can also run it on a schedule, for example every Monday. New to it? Read how it works, step by step and the 8 words you need first.
What it does
Remote Jobs Aggregator collects remote job listings from Remote OK, We Work Remotely and Himalayas and returns them as one dataset. The same job posted on two boards becomes one row. You can filter by keyword, category, location, date and salary, and on scheduled runs you can get only the jobs you have not seen before. You do not need a login or an API key for any of the boards.
- Reads the public job feeds of the boards you choose: the Remote OK public API, the We Work Remotely RSS feeds and the Himalayas public API. When you add keywords, Himalayas is searched with them; the other two boards are read in full and filtered.
- Keeps jobs that match your filters: keywords, exclude keywords, categories, allowed locations, posting date and "salary only".
- Merges the same job found on several boards into one row (same company and title, or the same link). The other boards are listed in
alsoFoundOn. - Writes the newest jobs first, up to Max jobs (
maxItems). - With Only new jobs (
onlyNew), remembers which jobs it returned and skips them next time.
Good for
- A daily or hourly remote job alert for one stack or role, without duplicates from three boards.
- A dataset of remote jobs with published salary ranges for research or a newsletter.
- A job board or Slack/Telegram feed that needs clean, structured rows with links back to the source board.
Not a good fit
- Only these three boards. It does not read LinkedIn, Indeed, company career sites or boards that need a login.
- It does not apply to jobs and does not collect data about candidates.
- One run returns at most about 1,000 unique jobs, because that is what the three public feeds offer (see Limits).
- Board data can be incomplete: some jobs have no salary, no location or no company website. Those fields are
null.
Who uses it
Remote job seekers
Get a daily list for your stack without duplicate jobs.
Newsletter writers
Find fresh remote jobs with published salary ranges.
Community managers
Post new remote jobs to Slack or Telegram.
Price
Pay per event: you pay for each result the tool saves, plus a small start fee for each run. The price includes Apify platform costs. Apify bills you, not us. Prices below are for the Apify free plan.
| What you pay for | Price | When |
|---|---|---|
| Start fee | $0.006 | Charged once per run. This tool uses 1 GB of memory or less by default; more memory costs more. |
| Job result | $0.0017 (from $0.0014 on paid Apify plans) | One remote job written to the Dataset after filters and duplicate merging. Filtered, merged and already-seen jobs are not charged. |
Examples
- One job: about $0.0077.
- 1,000 jobs: about $1.71.
- Every day 100 jobs, for 30 days: about $5.28 a month.
Free to try: the Apify free plan gives you $5 of usage every month, no credit card needed. That is enough for about 2,900 jobs.
Prices checked on 24 October 2026. See the current price on Apify.
Questions
Do I need a login for these job boards?
No. The tool uses public feeds of the three boards.
How many jobs can one run return?
About 1,000 unique jobs at most. That is what the three feeds offer.
How are duplicate jobs found?
Same company and title, or the same link. Other boards are listed in alsoFoundOn.
Can I add LinkedIn or Indeed?
No. The tool reads only Remote OK, We Work Remotely and Himalayas.
Do I need a login or API key for the boards?
No. The Actor uses only public feeds of the three boards. You need only your Apify account (and an Apify API token if you start runs through the API).
Why is the salary empty for many jobs?
Many companies do not publish a salary. The Actor copies the salary only when the board publishes it and never guesses one. Use salaryOnly to keep only jobs with a salary.
How fresh are the jobs?
Each run reads the boards at that moment. postedAt is the posting time from the board, fetchedAt is when the run read it. A closed job can still be in a feed until the board removes it.
Can I add another board?
Not in this Actor. Boards that need a login or forbid reuse are not supported. For company career pages, see the Related Actors below.
Details
Step by step on Apify
- Open the Input tab.
- The form already has Keywords (
keywords) =python, Posted within (days) (postedWithinDays) = 7 and Max jobs (maxItems) = 50. Change the keyword if you like. - Keep the other settings at their defaults: all three boards, description as plain text.
- Click Start.
- Open the Output tab. The Jobs view shows title, company, location, salary and the board.
Use cases
| Task | Input | You get | Key fields | Next step |
|---|---|---|---|---|
| Job alert for one stack | keywords, onlyNew = true, a schedule | Only new remote jobs | title, company, url, postedAt | Webhook to Slack, email or a sheet |
| Salary research | categories, salaryOnly = true, postedWithinDays = 90 | Jobs with published salary | salaryMin, salaryMax, salaryCurrency, salaryPeriod | Export CSV or Excel |
| Remote job feed for a region | locationsAllowed = ["Europe"] | Jobs open to Europe or worldwide | location, regions, isWorldwide | API into your site |
| Market overview | no keywords, maxItems = 2000, postedWithinDays = 90 | All jobs the three feeds offer | category, tags, company, source | Dataset export |
Tips for better results
- Use exclude keywords like senior to drop roles you do not want.
- Turn on salary only to keep jobs with a published salary.
- For more Himalayas jobs, raise the page limit to 25.
Limits and good to know
- About 1,000 unique jobs per run at most. The Remote OK feed has its ~100 newest jobs, the We Work Remotely feeds about 400, and Himalayas up to 25 pages of about 20 jobs. A run with no keywords, 90 days and
maxPagesPerSource25 returned 927 jobs in about one minute - Himalayas depth per keyword. With a popular keyword and the default 10 pages, Himalayas returns about 180 of its newest matching jobs (for
pythonthat was the last ~16 hours). For more, raisemaxPagesPerSourceto 25 or run without keywords and filter afterwards - Remote OK and We Work Remotely are read in full, then filtered, so keywords do not make them deeper
- Requests to each board are spaced (about one per second). All boards share one time limit: 120 seconds, or the run timeout minus 15 seconds if that is shorter. A run timeout under 30 seconds fails with
TIMEOUT_TOO_SHORT - Memory is fixed at 256 MB. A typical run takes 15–70 seconds
- If one board fails, you still get rows from the other boards, and
RUN_SUMMARY.statusisPARTIAL. You pay only for the rows written - If all boards fail, the run fails with status
ERRORand no rows. You pay only the start event - A run that is aborted keeps the rows already written;
RUN_SUMMARY.statusisCANCELLED
For developers
Sample result
One result from a real test run, in JSON. Real values change from run to run. In Excel or CSV each field is a column.
{
"source": "remoteok",
"sourceJobId": "1137475",
"url": "https://remoteok.com/remote-jobs/remote-senior-react-full-stack-developer-lemon-io-1137475",
"applyUrl": "https://remoteok.com/remote-jobs/remote-senior-react-full-stack-developer-lemon-io-1137475",
"title": "Senior React Full stack Developer",
"company": "Lemon.io",
"companyUrl": null,
"location": null,
"regions": [],
"isWorldwide": null,
"remoteType": "remote",
"employmentType": null,
"category": "programming",
"salaryMin": 80000,
"salaryMax": 200000,
"salaryCurrency": "USD",
"salaryPeriod": "year",
"tags": ["python", "react", "node", "typescript", "full stack"],
"postedAt": "2026-10-09T13:09:18.000Z",
"alsoFoundOn": [
{ "source": "weworkremotely", "url": "https://weworkremotely.com/remote-jobs/lemon-io-senior-react-full-stack-developer-7" }
],
"attribution": "Job via Remote OK — https://remoteok.com",
"dedupKey": "lemon io|senior react full stack developer"
}Use it from code
Actor ID: cliqtomedia/remote-jobs-aggregator. You need your Apify API token from Apify Console → Settings → API & Integrations.
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("cliqtomedia/remote-jobs-aggregator").call(run_input={
"keywords": [
"python"
],
"postedWithinDays": 7
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item)curl -X POST "https://api.apify.com/v2/acts/cliqtomedia~remote-jobs-aggregator/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"keywords": ["python"], "postedWithinDays": 7}'# pip install langchain-apify
# set APIFY_TOKEN in your environment
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("cliqtomedia/remote-jobs-aggregator")
result = tool.invoke({"run_input": {"keywords": ["python"], "postedWithinDays": 7}})
print(result)The cURL call waits for the results, up to 300 seconds. For longer runs, start a run (/runs) and get the results with a webhook or by checking the run. Apify API docs. LlamaIndex, MCP for AI agents and the JavaScript client: AI agents & MCP.
Data fields (28)
| Field | Type | Meaning |
|---|---|---|
source | string | Board this row was taken from: remoteok, weworkremotely or himalayas. |
sourceJobId | string | Job id on that board. |
url | string | Job page on the board. |
applyUrl | string | Direct apply link when the board gives one. |
title | string | Job title. |
company | string | Company name. |
companyUrl | string | Company website or company page on the board. |
companyLogo | string | Company logo URL. |
location | string | Location text as the board shows it, e.g. USA Only or Worldwide. |
regions | array | Countries or regions the job is open to; empty when unknown or worldwide. |
isWorldwide | boolean | true when open worldwide (Himalayas: no location restriction), false when restricted to regions, null when the board does not say. Worldwide jobs pass any location filter. |
remoteType | string | remote, hybrid or onsite (almost always remote). |
employmentType | string | full_time, part_time, contract, internship, temporary or other; null when unknown. |
category | string | Normalized category. |
seniority | string | Seniority when the board publishes it. |
salaryMin | number | Minimum salary as published; null when the board publishes none. Never estimated. |
salaryMax | number | Maximum salary as published; null when none. |
salaryCurrency | string | ISO currency, e.g. USD; null when no salary or no currency. |
salaryPeriod | string | year, month, week, day or hour; null when no salary. |
tags | array | Tags or skills from the board. |
postedAt | string | Posting time, ISO 8601 UTC. |
expiresAt | string | Expiry time when the board publishes it. |
descriptionText | string | Description as plain text (includeDescription text or both). |
descriptionHtml | string | Description as HTML (includeDescription html or both). |
alsoFoundOn | array | Other boards listing the same job (merged duplicates): source and url. |
attribution | string | Required source credit, e.g. Job via Remote OK — https://remoteok.com. |
dedupKey | string | Cross-board identity of the job (company + title, or URL). |
fetchedAt | string | When this run fetched the job, ISO 8601 UTC. |
Input settings (13)
The main fields of the input form. With the API you send them as JSON.
| Setting | Name in the API | Type | Example value |
|---|---|---|---|
| Keywords | keywords | array | ["python"] |
| Posted within (days) | postedWithinDays | integer | 7 |
| Max jobs | maxItems | integer | 50 |
| Job boards | sources | array | ["remoteok", "weworkremotely", "himalayas"] |
| Exclude keywords | excludeKeywords | array | |
| Match keywords in description too | searchInDescription | boolean | true |
| Categories | categories | array | |
| Allowed locations | locationsAllowed | array | |
| Only jobs with a salary | salaryOnly | boolean | false |
| Description format | includeDescription | string | "text" |
| Only new jobs (since previous runs) | onlyNew | boolean | false |
| State key | stateKey | string | "default" |
| Max pages per board | maxPagesPerSource | integer | 10 |


