# Remote Jobs Feed: Daily New Remote Job Alerts & Company Boards (`southern-data/remote-jobs-feed`) Actor

One de-duplicated feed of remote jobs from Jobicy, Remote OK, Working Nomads, Arbeitnow and Greenhouse/Lever/Ashby/Workday boards. Filter by title, country, salary; get only new jobs daily.

- **URL**: https://apify.com/southern-data/remote-jobs-feed.md
- **Developed by:** [Southern Data](https://apify.com/southern-data) (community)
- **Categories:** Jobs, Automation, Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 new 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.
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 Feed: daily new remote jobs, de-duplicated

Get a **daily feed of new remote jobs** from four public job feeds (Jobicy, Remote OK, Working Nomads, Arbeitnow) plus any **company job boards** you want to watch (Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio, Teamtailor, BambooHR, Workday, Breezy). Filter by keyword, country or region and employment type. The same job listed on several sources becomes one row. In **new jobs** mode each run returns only the jobs you haven't seen yet. Every row has the same 31 columns, so it drops straight into a spreadsheet, Airtable, a Slack alert or a job board.

### Read this first: what it can and can't do

- **It is only as wide as its sources.** About 1,700 remote jobs a week (measured 1 Nov 2026, last 7 days, after merging duplicates) plus whatever company boards you add. That's not every remote job on the internet: LinkedIn, Indeed and others aren't included.
- **Jobicy** (most of the remote jobs) serves only the **last 7 days**, and its feed runs about 3 hours behind the site. **Remote OK** serves only its latest ~100 jobs and **Working Nomads** its latest ~35. Schedule the Actor daily and you won't miss them; a one-off run can't go back further.
- **Arbeitnow** is mostly **Germany/Europe and mostly on-site**. Its "remote" flag isn't reliable, so we also read "remote" / "Homeoffice" in the location and title.
- **Excluded on purpose:** Remotive, Himalayas and We Work Remotely forbid this kind of reuse in their terms.
- **Location matching is text-based.** "Australia" matches jobs whose location says Australia, APAC / Asia Pacific (unless you turn that off), or Worldwide / Anywhere. You can also enter `Worldwide` (only jobs open worldwide) or `Remote` (worldwide jobs plus jobs that just say "Remote"). Many Remote OK jobs give no location at all ("unspecified"). They are left out when you filter by location, unless you turn on *includeUnspecifiedLocation*. Always check the job page for the real country rules.
- **The same job posted for several countries becomes one row.** Its matching locations are joined, e.g. "Germany; France; Spain". The other postings' links are in `otherJobUrls`.
- **Some company boards don't say if a job is remote** (workplaceType `unknown`). Lever, Ashby and Workday boards don't publish the company name, so we use the board's name: "palantir" → "Palantir".
- **"New" means new to your monitor.** Feeds don't always list every job on every read, so a job can first reach you a day or two after it was posted. Compare `firstSeenAt` with `postedAt`.
- **Working Nomads links** go through Working Nomads to the employer's own job or apply page.
- **Show it with credit.** The free feeds ask that you name them and link to the job page. Every row has `jobUrl`, `sourceName` and an `attribution` line. Apply links for Jobicy, Working Nomads and Arbeitnow open the job page on that site.
- **Bad input costs nothing.** A wrong mode or source, a website instead of a board link, or a typo gets a plain-English message and a free run.

### How to use it

1. **Daily feed:** set *keywords* (e.g. `python`, `data engineer`; matched in job titles at the start of words, so `engineer` also matches "Engineering Manager". Turn on *searchTags* or *searchDescriptions* to look wider) and *locations* (e.g. `Australia`). Leave mode on **New jobs only** and save the input as a **task** with a daily **schedule**. The first run returns the current matching jobs once (`isNew = false`). After that, each run returns only jobs that appeared since the previous run (`isNew = true`).
2. **Everything right now:** mode **All matching jobs**.
3. **Watch companies too:** add their board links to *companyBoards*, e.g. `https://jobs.lever.co/acme` or `greenhouse:acme`. Only have websites? Our **Company Jobs Finder** finds the board from a website.

The monitor's memory lives in a named key-value store (`remote-jobs-<monitorName>`). Jobs are remembered *before* filtering, so changing filters never makes old jobs look new. Jobs that a capped run (maxJobs or max cost) didn't return come back on the next run only if they are genuinely new.

### Input example

```json
{
  "mode": "new_jobs",
  "keywords": ["python", "data engineer"],
  "locations": ["Australia"],
  "excludeKeywords": ["senior"],
  "companyBoards": ["greenhouse:gitlab"],
  "monitorName": "python-remote-au"
}
```

### Output (one row per job, always these columns)

Lists (tags, alsoListedOn, otherJobUrls, matchedKeywords) are plain text, so a CSV or Excel export always has exactly these 31 columns, in this order.

| Column | Meaning |
|---|---|
| jobKey | Stable unique key (source + its job id) |
| title, company, location | As the source writes them |
| remoteScope | `worldwide` / `restricted` (limited to named places, see location) / `unspecified` (just "Remote") / null if not remote |
| workplaceType | remote / hybrid / onsite / unknown |
| employmentType | full_time, part_time, contract, internship, freelance, temporary or null |
| seniority, category, tags | When the source gives them |
| salaryMin, salaryMax, salaryCurrency, salaryPeriod, salaryText | When published |
| postedAt, ageDays | Earliest posting date across sources |
| jobUrl, applyUrl | Job page / application link |
| source, sourceName, sourceJobId | Where the row comes from |
| alsoListedOn, otherJobUrls | Other sources listing the same job (merged) |
| companyBoardUrl | For company-board jobs |
| matchedKeywords | Which of your keywords matched |
| isNew, firstSeenAt | New-jobs mode |
| descriptionText | Only with includeDescription |
| attribution, scrapedAt | Source credit line, run time |

There are also two records in the key-value store. **SOURCES** shows every feed and board with its status, jobs read and any error. **RUN_SUMMARY** shows counts, jobs removed per filter, duplicates merged and what was charged.

Sample row:

```json
{"title":"Senior Data Engineer","company":"WOO X","location":"APAC","remoteScope":"restricted","workplaceType":"remote","postedAt":"2026-10-28T14:53:27.000Z","jobUrl":"https://jobicy.com/jobs/157598-senior-data-engineer-6","sourceName":"Jobicy","matchedKeywords":"data engineer","isNew":false}
```

### Pricing (pay per event)

| Event | Price |
|---|---|
| Feed check: once per run in which at least one source was read | $0.0015 |
| Company job board read (each board you add, per run) | $0.001 |
| Job returned (all_jobs mode, or a current job on a monitor's first run) | $0.0015 |
| New job returned (new_jobs mode) | $0.0025 |

**Store discount tiers:** free-plan and Bronze users pay the prices above. Silver gets 10% off and Gold (and higher) gets 20% off on returned jobs and new jobs (the per-run feed check and company board fees are the same on every tier).

Filtered-out jobs, merged duplicates, already-seen jobs, failed sources, invalid input and self-tests are free. **Example:** a daily feed that finds 5 new jobs a day costs about 30 × ($0.0015 + 5 × $0.0025) = **$0.42 a month**. Set a *maximum cost per run* in the run options for a hard cap.

### Reliability

- Each source is read on its own. If one fails, the others still deliver; the failure is listed in SOURCES and is free. If *every* source fails, the run fails and nothing is charged.
- **Self-test:** run with `{"selfTest": true}` for a free health check: 34 checks (parsers on saved samples, location rules, filters, merging, monitor, input rules, plus a live read of every feed). We run it every day.

### FAQ

**Why did a first run return jobs marked `isNew: false`?** That's the baseline: the jobs that existed before your monitor started. Turn off *includeExistingOnFirstRun* to start silent (the first run then charges only the feed check).

**Can I get jobs older than 7 days?** From Arbeitnow and company boards yes (set *postedWithinDays*, 0 = no limit). Jobicy, Remote OK and Working Nomads don't publish older jobs.

**Can it apply for me or send e-mail alerts?** No. Connect the dataset to Slack, e-mail or Google Sheets with Apify integrations, Make or Zapier.

# Actor input Schema

## `mode` (type: `string`):

<b>new_jobs</b>: the Actor remembers every job it has seen (in a named key-value store) and each run returns only jobs that appeared since the last run. Schedule it daily for a "new remote jobs" feed. On the very first run it returns the current matching jobs once (turn off <i>includeExistingOnFirstRun</i> to start silent).<br><b>all_jobs</b>: every matching job, every run.

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

Keep jobs whose title contains ANY of these words (matched at the start of words, any case: "engineer" matches "Engineering Manager"). Leave empty for all jobs.

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

Countries or regions, e.g. "Australia", "Germany", "Europe", "APAC", "LATAM". A remote job matches when its location names one of them, or (by default) one of their regions ("Australia" also matches "APAC"), or says Worldwide / Anywhere. Enter "Worldwide" for jobs open worldwide only, or "Remote" for those plus jobs that just say "Remote". Leave empty for every location.

## `workplaceTypes` (type: `array`):

Which workplace types to keep. Default: remote only. Some company boards do not say; those jobs are "unknown".

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

Drop jobs posted longer ago than this (0 = no limit). Jobicy only serves the last 7 days, Remote OK and Working Nomads only their latest ~100 / ~35 jobs.

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

Public job feeds to read. Default: all four. Give an empty list to read only your company boards.

## `companyBoards` (type: `array`):

Also watch specific companies: their public job-board links (Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio, Teamtailor, BambooHR, Workday, Breezy), e.g. "https://jobs.lever.co/acme" or "greenhouse:acme". Max 500. Have only company websites? Use our Company Jobs Finder to find their boards.

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

Keep only these employment types. Leave empty for all.

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

Drop jobs whose title contains any of these words, e.g. "senior", "sales".

## `excludeCompanies` (type: `array`):

Drop jobs from these companies (exact company name, any case).

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

With locations set: also keep remote jobs open worldwide.

## `includeRegionalMatches` (type: `boolean`):

With locations set: "Australia" also matches jobs for "APAC" / "Asia Pacific", "Germany" matches "Europe" / "EMEA", and a region matches its countries.

## `includeUnspecifiedLocation` (type: `boolean`):

With locations set: also keep remote jobs that only say "Remote" (they may still be limited to one country; check the job page).

## `onlyWithSalary` (type: `boolean`):

Keep only jobs that publish a salary.

## `searchTags` (type: `boolean`):

Match keywords in the source's tags too (Remote OK, Working Nomads, Arbeitnow). Finds e.g. "python" jobs whose title doesn't say Python, but tags are broad (a recruiter job can be tagged "engineer").

## `searchDescriptions` (type: `boolean`):

Match keywords in the description too (more results, less precise).

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

Add the description as plain text (descriptionText, max 20,000 characters).

## `includeExistingOnFirstRun` (type: `boolean`):

new_jobs mode: on a monitor's first run, return the current matching jobs (isNew = false). Turn off to only remember them and start returning jobs from the next run (the first run is then free).

## `monitorName` (type: `string`):

new_jobs mode: name of this feed's memory, e.g. "python-remote-au". Runs with the same name share history. Default: the task id, or one derived from your feeds and boards. Changing filters keeps the history (jobs are remembered before filtering).

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

Stop after this many rows (newest first). Jobs not returned because of this cap are not remembered, so a later run returns them.

## `maxPagesPerSource` (type: `integer`):

Safety cap on pages read from Jobicy (100 jobs/page) and Arbeitnow (300 jobs/page). The default covers 7 days.

## `selfTest` (type: `boolean`):

Run the built-in health check instead of a search: no rows, nothing charged; the run fails if any check fails.

## Actor input object example

```json
{
  "mode": "new_jobs",
  "keywords": [
    "engineer"
  ],
  "workplaceTypes": [
    "remote"
  ],
  "postedWithinDays": 7,
  "sources": [
    "jobicy",
    "remoteok",
    "workingnomads",
    "arbeitnow"
  ],
  "includeWorldwide": true,
  "includeRegionalMatches": true,
  "includeUnspecifiedLocation": false,
  "onlyWithSalary": false,
  "searchTags": false,
  "searchDescriptions": false,
  "includeDescription": false,
  "includeExistingOnFirstRun": true,
  "maxJobs": 1000,
  "maxPagesPerSource": 30,
  "selfTest": false
}
```

# Actor output Schema

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

One row per job. Views: Jobs, Job details, All fields (CSV export).

## `sources` (type: `string`):

SOURCES record: every feed and company board with its status, jobs read, pages read and any error.

## `runSummary` (type: `string`):

RUN_SUMMARY record: jobs read, duplicates merged, jobs removed per filter, jobs returned per source, charged events, monitor store, any input problem or stop reason.

## `selfTest` (type: `string`):

SELF_TEST record: only present when the Actor runs with selfTest: true.

# 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": [
        "engineer"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("southern-data/remote-jobs-feed").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": ["engineer"] }

# Run the Actor and wait for it to finish
run = client.actor("southern-data/remote-jobs-feed").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": [
    "engineer"
  ]
}' |
apify call southern-data/remote-jobs-feed --silent --output-dataset

```

## MCP server setup

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

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/101TflHaJoSPCSGAd/builds/gRCreMg6ZkLiSPgrp/openapi.json
