# We Work Remotely Jobs Scraper & API: Remote Jobs as JSON (`dododata/weworkremotely-jobs-scraper`) Actor

Every job in We Work Remotely's public RSS feeds as clean JSON: company, category, countries, pay read from the text, full description. $1 per 1,000.

- **URL**: https://apify.com/dododata/weworkremotely-jobs-scraper.md
- **Developed by:** [Dodo Data](https://apify.com/dododata) (community)
- **Categories:** Jobs, Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

## We Work Remotely Jobs Scraper & API: Remote Jobs as JSON

**Every job in We Work Remotely's public RSS feeds, as clean JSON.** Company, category, the countries a job is open to, the employer's website and headquarters, pay read out of the text, the full description, and the link back to the job on weworkremotely.com. **253 jobs in 15 seconds, 0 failures**, measured on Apify on 25 September 2026.

We Work Remotely publishes these feeds for reuse. Its RSS page says: "Anyone can use the feed, all we ask is that you attribute the links back to We Work Remotely." This Actor reads those feeds and nothing else, and every row links back.

### What you get

A real row from that run, description shortened:

```json
{
  "id": "weworkremotely:beefree-sale-manager-saas",
  "source": "weworkremotely",
  "source_name": "We Work Remotely",
  "company": "Beefree",
  "company_website": "https://beefree.io",
  "company_headquarters": "San Francisco",
  "title": "Sale Manager (SaaS)",
  "category": "Sales and Marketing",
  "location": "United States of America",
  "locations": ["United States of America"],
  "country": "United States of America",
  "workplace_type": "remote",
  "remote": true,
  "employment_type": "Full-Time",
  "salary_min": 165000,
  "salary_max": 185000,
  "salary_currency": "USD",
  "salary_period": "year",
  "salary_text": "Salary: $165,000 - $185,000",
  "salary_source": "description",
  "tags": ["Sales and Marketing"],
  "posted_at": "2026-09-02T22:25:26.000Z",
  "expires_at": "2026-10-02T22:25:26.000Z",
  "description": "Salary: $165,000 - $185,000 OTE Bonus: $75,000 Total OTE: $240,000 - $260,000 Remote from anywhere in the United States ...",
  "apply_url": "https://weworkremotely.com/remote-jobs/beefree-sale-manager-saas",
  "url": "https://weworkremotely.com/remote-jobs/beefree-sale-manager-saas",
  "scraped_at": "2026-09-25T18:09:21.427Z"
}
```

39 fields per row, in the same shape as the other Dodo Data job Actors, so rows from this one drop into the same table as rows from company career pages or other remote boards. The Dataset tab lists every field and what it means.

### How much is in the feeds

We Work Remotely publishes one feed of its newest jobs and one feed per category. The newest-jobs feed held 80 jobs on 25 September 2026; all twelve feeds together held **253 distinct jobs**. A run reads the newest-jobs feed first, then the category feeds, and delivers each job once however many feeds list it.

| Category | Jobs on 25 Sept 2026 |
|---|---|
| Sales and Marketing | 77 |
| All Other Remote | 53 |
| Full-Stack Programming | 40 |
| Customer Support | 30 |
| DevOps and Sysadmin | 16 |
| Management and Finance | 16 |
| Product | 8 |
| Design | 7 |
| Back-End Programming | 6 |

The feeds are a window on the newest jobs, not the whole archive of the site. For a running record, put the Actor on a daily schedule with a monitor name (below).

### Fields worth knowing about

- **company** and **title**: We Work Remotely writes them as one ("Beefree: Sale Manager (SaaS)"). They are split at the first colon.
- **locations** and **country**: the countries We Work Remotely shows under "Country" on the job page, flags removed. When it lists none, `locations` holds its region instead: "Anywhere in the World", "North America Only", "USA Only". `country` is filled when exactly one country is listed. 67 of the 253 jobs listed countries. WWR's "Georgia" is usually the US state, not the country, and it is passed on as WWR wrote it.
- **company\_website**: the employer's site, from the line We Work Remotely puts at the top of each job. **124 of 253** had one.
- **company\_headquarters**: what the employer typed into We Work Remotely's Headquarters box, as written, on 243 of 253 jobs. Often a city ("San Francisco"); on jobs imported from an employer's hiring system it is often a place of work instead ("REMOTE - US").
- **skills**: We Work Remotely's skills list, on about a third of jobs (83 of 253 in the last run on 25 September), as written. Mostly accurate, but some lists do not describe the job (a sales development role lists Architecture and Bug Tracking, a marketing internship Infrastructure Orchestration), so the keyword filter does not search it.
- **Pay**: We Work Remotely publishes no pay field, so pay is read out of the description, only when a range sits next to a pay word such as Salary, Compensation or Pay range. **78 of 253** jobs had one: 71 yearly, 7 hourly; 69 in US dollars, 4 in Canadian dollars, 3 in euros, 1 in Australian dollars, and 1 whose currency could not be told. `salary_text` holds the words it was read from, so you can check any row. A bare `$` is read by the job's country when exactly one is listed (CAD for Canada), as US dollars when none is, and left empty when that one country does not settle it. A range written per week, per day or per month is left out rather than converted.

Every one of those figures was checked by hand against its text before this was published. Two were wrong and are fixed: "US$65-$85" had been read as Singapore dollars, and a monthly "$3500-$5000" printed beside an annual figure had been read as a yearly salary. A range under 10,000 is now never called a year's pay.

### Filters, applied before a row is saved

You pay per row, so every filter runs before anything is saved and you are never charged for what you filter out.

| Filter | What it does |
|---|---|
| **Categories** | any of We Work Remotely's categories; empty for all |
| **Keywords** | keep a job if its title or category contains any of these words |
| **Exclude keywords** | drop a job if its title contains any of these words |
| **Region restrictions** | `Europe`, `UK`, `United States`, `North America`, `LATAM` or a country. Region names cover their countries, and matching is on whole words, so `UK` never matches Ukraine. A job marked "Anywhere in the World" is kept only if you add `Worldwide` |
| **Only jobs with pay** | keep only jobs whose description states a range |
| **Minimum salary** | a yearly figure: hourly pay is annualised first, and only US dollars, euros, pounds, Swiss francs, Canadian and Australian dollars are compared |
| **Posted within (days)** | by We Work Remotely's publication date |

Measured: Programming and DevOps, Worldwide only, 20 rows, took **3 seconds and 3 requests**. When the newest-jobs feed alone fills your row limit, no other feed is read.

### A daily feed of only the jobs you have not had

Give the run a **Monitor name** and put it on a daily schedule. Every row then says whether it is `new`, `updated` or already delivered, with `first_seen_at`. With **Only changes** on, jobs you already have are left out and not billed.

Measured, two runs of the same monitor on the Design category, minutes apart:

```text
run 1   Monitor "wwr-verify": 7 new · 0 updated · 0 already delivered before
run 2   Monitor "wwr-verify": 0 new · 0 updated · 7 already delivered before
```

The second run returned nothing and billed nothing. Because a feed only shows the newest jobs, this Actor never reports a job as removed: leaving the feed does not mean the job was filled.

### Where the data comes from

The public RSS feeds We Work Remotely lists on its own RSS page (https://weworkremotely.com/remote-job-rss-feed): the all-jobs feed and its eleven category feeds. Nothing else is read: not the job pages, not the search, nothing behind a login. robots.txt allows the feeds and asks for no delay; this Actor reads them one a second anyway.

`url` and `apply_url` both point at the job on weworkremotely.com, where its Apply button is. That is the one thing We Work Remotely asks of anyone using its feed, so this Actor does not replace it with the employer's own application link. If you show these jobs to people, keep those links.

**No personal data is collected.** E-mail addresses and phone numbers that appear inside a description are removed before the row is saved; 12 of the 81 descriptions in the newest-jobs feed contained an e-mail address on 25 September 2026, and none of them reached a row.

### Price

**$1 per 1,000 jobs**, pay per event, plus Apify's start event of $0.00005 per run at the default 1 GB. All 253 jobs cost about $0.25.

| You want | Rows | Cost |
|---|---|---|
| everything in the feeds today | about 250 | about $0.25 |
| a daily monitor with Only changes on, for a month | the new jobs only: the feeds held 216 jobs posted in the 30 days before 25 Sept, about 7 a day | about $0.25 |

### Also from Dodo Data

- [Remote Jobs Search](https://apify.com/dododata/remote-jobs-search): remote jobs from Himalayas, Remote OK, Jobicy and Arbeitnow in this same row shape, de-duplicated across boards.
- [Jobs API](https://apify.com/dododata/job-search-api): search about 168,000 jobs from company career pages by words, location and remote.

### Changelog

- 2026-09-25: first version. Last verified on Apify: 25 September 2026.

# Actor input Schema

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

Leave empty for every category. These are We Work Remotely's own categories, each with its own feed. The newest jobs of all categories are read first, then each chosen category's feed, which reaches further back.

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

Keep a job if its title or category contains any of these words. Case and accents are ignored. Leave empty for every job.

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

Drop a job if its title contains any of these words, for example senior, intern, sales.

## `regions` (type: `array`):

Keep a job only if We Work Remotely says it can be worked from one of these, for example Europe, UK, United States, North America, LATAM. Region names cover their countries, because WWR lists countries (United States of America, Canada). A job WWR marks "Anywhere in the World" with no country list is kept only when you include Worldwide.

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

Keep only jobs whose description states a pay range next to a pay word (Salary, Compensation, Pay range and similar). About 3 in 10 WWR jobs do: 78 of 253 on 25 Sept 2026.

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

Keep only jobs whose published pay reaches at least this much a year. Hourly and monthly pay is annualised first (x2,080 and x12). Compared in the job's own currency, and only for pay in US dollars, euros, pounds, Swiss francs, Canadian or Australian dollars: a job paid in another currency, or with no published pay, is left out when this is set.

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

Keep only jobs posted in the last N days, by WWR's publication date.

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

The full description as plain text, with contact details removed. Turn off for a much smaller dataset.

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

Turns on change tracking. Pick any name, for example remote-backend-watch, and use the same name on every run. Each row then says whether it is new, updated or unchanged since the previous run under that name. The first run marks everything new. State is kept in a key-value store on your own Apify account.

## `onlyChanges` (type: `boolean`):

Needs a monitor name. Jobs you already received and that have not changed are left out of the results and not billed.

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

Stop after this many jobs. You pay per row, so this is also your budget cap. WWR's feeds held 253 distinct jobs on 25 Sept 2026.

## `maxConcurrency` (type: `integer`):

Parallel requests. The feeds are read one a second whatever this says, so 2 is enough.

## `useProxy` (type: `boolean`):

Off by default: We Work Remotely publishes these feeds for anyone to use. Turn it on only if a run reports being rate-limited or blocked.

## Actor input object example

```json
{
  "categories": [
    "programming",
    "devops-sysadmin"
  ],
  "keywords": [],
  "excludeKeywords": [],
  "regions": [],
  "onlyWithSalary": false,
  "includeDescription": true,
  "onlyChanges": false,
  "maxItems": 500,
  "maxConcurrency": 2,
  "useProxy": false
}
```

# Actor output Schema

## `results` (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 = {
    "categories": [
        "programming",
        "devops-sysadmin"
    ],
    "keywords": [],
    "excludeKeywords": [],
    "regions": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("dododata/weworkremotely-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 = {
    "categories": [
        "programming",
        "devops-sysadmin",
    ],
    "keywords": [],
    "excludeKeywords": [],
    "regions": [],
}

# Run the Actor and wait for it to finish
run = client.actor("dododata/weworkremotely-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 '{
  "categories": [
    "programming",
    "devops-sysadmin"
  ],
  "keywords": [],
  "excludeKeywords": [],
  "regions": []
}' |
apify call dododata/weworkremotely-jobs-scraper --silent --output-dataset

```

## MCP server setup

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