# Remote Jobs Scraper — We Work Remotely & RemoteOK (`novel_virginiacreeper/remote-jobs-scraper`) Actor

Scrape remote jobs from We Work Remotely and RemoteOK with onlyNewJobs deduplication, salary filters, and n8n/Slack automation. Two sources in one run, unlike single-board scrapers.

- **URL**: https://apify.com/novel\_virginiacreeper/remote-jobs-scraper.md
- **Developed by:** [Haruto G](https://apify.com/novel_virginiacreeper) (community)
- **Categories:** Jobs, Developer tools
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Remote Jobs Scraper — RemoteOK

**Scrape structured remote job listings in seconds.** This Apify Actor collects clean, export-ready job data from [RemoteOK](https://remoteok.com/) — a widely used remote job board for developers, recruiters, and market researchers.

No custom code. No brittle scripts. Run it on a schedule, pipe results into your stack, and get consistent JSON every time.

**New:** enable `onlyNewJobs` to get **only fresh listings since your last run** — the killer feature for daily Slack alerts, spreadsheet syncs, and recurring automations without duplicate noise.

***

### Why teams buy this Actor

| Pain point | What you get |
|---|---|
| Manual copy-paste from job boards | Automated extraction at scale |
| Duplicate alerts every morning | `onlyNewJobs` — diff-only output via KVS cache |
| Inconsistent data shapes | One normalized schema for every record |
| Fragile DIY scrapers that break | Maintained RemoteOK API integration |
| Slow research cycles | Filter by keyword, salary, or skill tags |

Built for **speed, reliability, and integration** — the three things that matter when you're paying per result or running daily pipelines.

***

### RemoteOK attribution (required)

RemoteOK's [terms](https://remoteok.com/legal) require that you:

1. **Credit Remote OK as the source** when displaying or redistributing job data
2. **Link directly** to each job's URL on `remoteok.com` (no redirects)
3. **Link back to RemoteOK** on any page or app screen where you show this data

This Actor helps by including these fields on every record:

| Field | Purpose |
|---|---|
| `url` / `applyUrl` | Direct link to the job on RemoteOK |
| `sourceAttribution` | `"Remote OK"` |
| `sourceSiteUrl` | `https://remoteok.com` |

**Your responsibility:** if you build a dashboard, Slack bot, or public job board with this data, include the attribution and links above in the UI — not just in the raw JSON.

***

### Automate without code (n8n · Make · Zapier)

You don't need to be an engineer to build a job-alert system. Connect this Actor to your favorite iPaaS tool and let it run on autopilot.

#### Typical no-code flow

```
Schedule (daily 8 AM)
    → Run Remote Jobs Scraper (onlyNewJobs: true)
    → If new jobs found
        → Send to Slack / Google Sheets / Email
```

**Why `onlyNewJobs` matters for automation:** without it, every scheduled run sends the same 50–100 jobs again. With it, your Slack channel or spreadsheet only receives **genuinely new postings**.

***

### Daily new-job alert workflow (recommended)

#### Step 1 — Configure the Actor

```json
{
  "maxItems": 100,
  "searchKeyword": "python",
  "onlyNewJobs": true,
  "minSalary": 80000
}
```

#### Step 2 — Schedule on Apify

1. Open the Actor → **Schedules** → **Create schedule**
2. Set cron: `0 8 * * *` (every day at 8:00 AM)
3. Paste the input above
4. Enable **Save dataset** and optional **Webhook on success**

#### Step 3 — Connect your tool

| Tool | What to do |
|---|---|
| **n8n** | Apify Trigger → Get Dataset Items → Slack / Google Sheets |
| **Make** | Apify Watch Actor Runs → Iterator → Add Row / Send Message |
| **Zapier** | Apify integration → Filter (itemCount > 0) → Slack / Gmail |

***

### Data fields

Every record is normalized into a consistent schema:

| Field | Description |
|---|---|
| **title** | Job title |
| **company** | Hiring company name |
| **location** | Remote region or geography |
| **tags** | Skills and category labels |
| **salary** / **salaryMin** / **salaryMax** | Compensation when listed |
| **url** | Direct link to the job on RemoteOK |
| **applyUrl** | Apply link on RemoteOK |
| **sourceAttribution** | `"Remote OK"` |
| **sourceSiteUrl** | `https://remoteok.com` |
| **postedAt** | ISO 8601 posting date |
| **jobId** | Stable deduplication key |

Additional fields: `description`, `currency`, `externalId`, `scrapedAt`.

***

### Example output

```json
[
  {
    "jobId": "remoteok:123456",
    "title": "Senior Python Developer",
    "company": "Acme Corp",
    "location": "Worldwide",
    "tags": ["Python", "Django"],
    "salary": "$120,000 - $160,000",
    "salaryMin": 120000,
    "salaryMax": 160000,
    "currency": "USD",
    "url": "https://remoteok.com/remote-jobs/123456",
    "applyUrl": "https://remoteok.com/remote-jobs/123456",
    "source": "remoteok",
    "sourceAttribution": "Remote OK",
    "sourceSiteUrl": "https://remoteok.com",
    "postedAt": "2026-07-17T08:42:51Z"
  }
]
```

***

### Quick start

#### Example input

```json
{
  "maxItems": 100,
  "searchKeyword": "python",
  "minSalary": 80000,
  "onlyNewJobs": true,
  "tags": ["python"]
}
```

#### Call via API (cURL)

```bash
curl -X POST "https://api.apify.com/v2/acts/YOUR_USERNAME~remote-jobs-scraper/runs?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "maxItems": 100,
    "searchKeyword": "python",
    "onlyNewJobs": true
  }'
```

#### Call via Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("YOUR_USERNAME/remote-jobs-scraper").call(
    run_input={
        "maxItems": 100,
        "searchKeyword": "python",
        "onlyNewJobs": True,
    }
)
jobs = client.dataset(run["defaultDatasetId"]).list_items().items
print(f"New jobs: {len(jobs)}")
```

***

### Input parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `maxItems` | integer | `100` | Maximum records to collect (1–1000) |
| `searchKeyword` | string | — | Case-insensitive filter on title, company, tags |
| `minSalary` | integer | — | Minimum salary filter (USD, when disclosed) |
| `onlyNewJobs` | boolean | `false` | Output only jobs not seen in previous runs |
| `tags` | string\[] | `[]` | RemoteOK tag filter (e.g. `python`, `devops`) |

#### How `onlyNewJobs` works

1. The Actor loads a cache of previously seen `jobId` keys from the **Apify Key-Value Store**
2. It fetches up to `maxItems` listings from RemoteOK
3. Only listings **not in the cache** are pushed to the Dataset
4. All scraped job keys are merged into the cache for the next run

First run with `onlyNewJobs: true` returns all scraped jobs (empty cache). Every subsequent scheduled run returns only the delta.

***

### Data source

| Source | Method | Notes |
|---|---|---|
| **RemoteOK** | Public JSON API (`remoteok.com/api`) | Fast bulk fetch, salary ranges, skill tags |

***

### Legal & fair use

- Data is fetched from RemoteOK's public API feed
- Each record includes attribution fields required by RemoteOK terms
- **You must** credit Remote OK and link back when displaying data in apps, dashboards, or public pages
- Use reasonable `maxItems` and respect RemoteOK's API access policies
- Do not republish personal data beyond what the listing exposes

***

### Support

Questions or feature requests? Open an issue on the Actor page or contact the author via the Apify Console.

**Keywords:** remote jobs scraper, RemoteOK API, job board data, n8n job alerts, Zapier remote jobs, Slack job notifications, Google Sheets job scraper, only new jobs, daily job alerts, recruiter automation.

# Actor input Schema

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

Maximum number of remote job records to collect and export. Controls cost on pay-per-result pricing. Range: 1–1000.

## `searchKeyword` (type: `string`):

Return only jobs that contain this keyword (case-insensitive). Matches title, company, location, tags, and description. Examples: python, senior, react, devops, designer.

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

Filter out jobs whose maximum disclosed salary is below this amount. Applied only when structured salary data is available; jobs without salary information are still included.

## `tags` (type: `array`):

Filter RemoteOK listings by skill or category tags (e.g. python, javascript, devops, marketing).

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

When enabled, output only job listings that were not seen in previous runs. The Actor stores job IDs/URLs in the Apify Key-Value Store and compares against that cache. Perfect for daily Slack, email, or spreadsheet alerts without duplicate notifications.

## Actor input object example

```json
{
  "maxItems": 100,
  "tags": [
    "python"
  ],
  "onlyNewJobs": false
}
```

# 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 = {
    "maxItems": 100,
    "searchKeyword": "",
    "minSalary": 0,
    "tags": [
        "python"
    ],
    "onlyNewJobs": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("novel_virginiacreeper/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 = {
    "maxItems": 100,
    "searchKeyword": "",
    "minSalary": 0,
    "tags": ["python"],
    "onlyNewJobs": False,
}

# Run the Actor and wait for it to finish
run = client.actor("novel_virginiacreeper/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 '{
  "maxItems": 100,
  "searchKeyword": "",
  "minSalary": 0,
  "tags": [
    "python"
  ],
  "onlyNewJobs": false
}' |
apify call novel_virginiacreeper/remote-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,novel_virginiacreeper/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/S7m1GUjSpudEXDmmi/builds/YDRjjhxVS3OxXFLVB/openapi.json
