# WeWorkRemotely Scraper | Remote Jobs + Full Descriptions (`tqm/weworkremotely-scraper`) Actor

Scrape WeWorkRemotely job listings with the FULL job description, not a listing-page snippet: company, salary, region, job type, category and detected tech stack. Pure HTTP - no browser, no proxy, no login. Filter by category, tech stack or minimum salary, and export to JSON, CSV or Excel.

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

## Pricing

from $1.60 / 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.
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?

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

WeWorkRemotely Job Scraper collects remote job postings from [WeWorkRemotely](https://weworkremotely.com) — one of the longest-running remote job boards — and returns them as structured rows with the **full job description**, company, salary, category and a link to the original posting.

It reads WeWorkRemotely's public category feeds over plain HTTP. **No browser, no proxy, no login.** A nine-feed run finishes in seconds.

### What data can I extract from WeWorkRemotely?

| Field | Description |
|---|---|
| `title` | Job title as posted |
| `company` | Hiring company |
| `jobUrl` | Link to the original WeWorkRemotely posting |
| `description` | Full posting body, HTML stripped, truncated to 1,000 characters |
| `location` | Region or location string as posted |
| `salary` | Salary string as posted |
| `salaryMin` / `salaryMax` | Parsed salary bounds |
| `currency` | Salary currency |
| `jobType` | Employment type, e.g. full-time or contract |
| `category` | WeWorkRemotely category the posting came from |
| `techStack` / `skills` | Technologies detected in the title and description |
| `postedAt` | Publication date |
| `jobId` | Stable id, useful as a deduplication key |
| `scrapedAt` | When this run collected the row |

### How do I use WeWorkRemotely Job Scraper?

1. Click **Try for free**.
2. Leave the input empty to sweep every category feed, or narrow it — `categories: ["Programming", "DevOps"]` or `techStackFilter: ["aws", "django"]`.
3. Click **Save & Start**.
4. Export the results as JSON, CSV, Excel or XML from the **Storage** tab.

### Input reference

| Option | Type | Default | What it does |
|---|---|---|---|
| `maxJobs` | integer | `100` | How many postings to return, up to **300**. |
| `categories` | array | *(none)* | Restrict to WeWorkRemotely categories, e.g. `["Programming", "Design", "DevOps"]`. |
| `techStackFilter` | array | *(none)* | Keep only postings mentioning these technologies. Matched on word boundaries over the title and description, so `go` does not match *going*. |
| `minSalary` | integer | `0` | Drop postings below this annual figure. Postings with no stated salary are also dropped once this is set. |
| `failOnZeroResults` | boolean | `true` | Fail the run, with a reason, when it returns nothing. |

#### Input sample

```json
{
  "maxJobs": 200,
  "categories": ["Programming", "DevOps and Sysadmin"],
  "techStackFilter": ["kubernetes", "terraform"],
  "failOnZeroResults": true
}
```

### Output sample

```json
{
  "source": "weworkremotely",
  "jobId": "wwr-remote-senior-backend-engineer-acme",
  "title": "Senior Backend Engineer",
  "company": "Acme Systems",
  "jobUrl": "https://weworkremotely.com/remote-jobs/acme-systems-senior-backend-engineer",
  "description": "Acme Systems is hiring a senior backend engineer to work on our distributed ingestion pipeline...",
  "location": "Europe only",
  "salary": "$100,000 - $140,000",
  "salaryMin": 100000,
  "salaryMax": 140000,
  "currency": "USD",
  "jobType": "Full-Time",
  "category": "Programming",
  "techStack": ["go", "kubernetes", "postgresql"],
  "skills": ["go", "kubernetes", "postgresql"],
  "postedAt": "2026-09-02",
  "scrapedAt": "2026-09-04T09:14:02.551Z"
}
```

### How many jobs can I scrape from WeWorkRemotely?

**Up to about 300, and `maxJobs` is capped there for a measured reason.**

WeWorkRemotely publishes one un-paginated feed per category. The ceiling is however many postings those feeds currently hold — measured at roughly 300 across a nine-feed sweep. There is no deeper pagination to reach for, so an actor promising "1,000 jobs" from this board is promising rows that do not exist.

To accumulate more than the board holds at one moment, schedule the actor daily and deduplicate on `jobId`.

#### Feeds are fetched with rate-limiting in mind

WeWorkRemotely rate-limits rapid sequential feed requests with a `403`. This actor handles that per feed rather than letting one refusal end the run — an earlier version discarded every feed already collected when a single later one was refused, turning a 245-row run into zero. Feeds that do get refused are reported in the run log rather than silently dropped.

### A run that returns nothing tells you why

With `failOnZeroResults: true` (the default), an empty run **fails** and its status message names the cause — filters that removed everything, every feed rate-limited, or a genuinely empty board. On pay-per-result pricing a silent zero-row "success" is you paying for nothing and unable to tell a broken actor from a quiet day. Set it to `false` for scheduled monitoring runs where quiet nights are expected.

### How much does it cost?

Cheap: this actor makes a handful of HTTP requests and parses XML. There is no headless browser and no proxy, which is what dominates the cost of most job-board scrapers. Filtering happens after the fetch, so a narrow filter costs the same as a broad one.

For an exact figure, run it once with your real input and read the cost from the **Runs** tab.

### Who is this for?

- **Recruiters** tracking what remote-first companies are hiring for, and at what salary.
- **Job seekers** who want the whole board as a spreadsheet, with full descriptions rather than teaser text.
- **Market researchers** studying remote-work adoption, salary bands and category mix over time.
- **Lead generation** — each posting identifies a company actively investing in a team.
- **Developers** wanting a maintained remote-jobs feed as JSON.

### FAQ

#### Do I need a WeWorkRemotely account?

No. Everything this actor reads is public and requires no login, cookie or session. There is no account to be banned.

#### Will I get blocked?

The actor paces its feed requests deliberately to stay within WeWorkRemotely's rate limits. If a feed is refused anyway, the run keeps the rows it already has and reports which feed was refused.

#### Does it return the full job description?

Yes — this is the board's real strength, and the reason it is worth scraping. Descriptions come back complete (truncated to 1,000 characters in the output row), not as a listing-page snippet.

#### Is it legal to scrape WeWorkRemotely?

This actor collects only publicly published job listings and extracts no private user data. Results may nevertheless contain personal data such as a hiring manager's name inside a description. You should not scrape or store personal data without a legitimate reason; if you are unsure whether yours qualifies, consult your lawyers. Apify has useful background on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

#### Can I export to Excel or Google Sheets?

Yes — JSON, CSV, XML and Excel are all one click from the **Storage** tab, and Apify integrates directly with Google Sheets.

### Integrations and API

Trigger runs and collect results through the [Apify API](https://docs.apify.com/api/v2), the JavaScript or Python client, or Apify's built-in integrations: **Zapier, Make, Slack, Google Drive, GitHub and generic webhooks**. A completion webhook can push each day's new remote roles straight into your ATS, CRM or Slack channel.

### Support

Missing a field, or seeing something that looks wrong? Open an issue on this actor's **Issues** tab and it will reach the maintainers.

# Actor input Schema

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

Maximum postings to return. WeWorkRemotely's feeds are single un-paginated pages, so the real ceiling is however many they currently hold: measured 2026-08-27, the default all-jobs feed carried 89 postings and all nine category feeds together carried ~250. Asking for more cannot return more.

## `techStackFilter` (type: `array`):

Only return jobs mentioning these technologies

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

Filter by categories (e.g., Programming, Design, DevOps)

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

Filter jobs with salary below this amount

## `failOnZeroResults` (type: `boolean`):

When on (default), a run that finds no postings FAILS with a message explaining why — too-narrow filters, every feed rate-limited, an empty feed, or a change in WeWorkRemotely's RSS format. Turn it off if you run this on a schedule and want quiet runs to stay green.

## Actor input object example

```json
{
  "maxJobs": 100,
  "techStackFilter": [],
  "categories": [],
  "minSalary": 0,
  "failOnZeroResults": true
}
```

# Actor output Schema

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

Every job posting this run returned from WeWorkRemotely's category feeds, one row each, with the full job 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("tqm/weworkremotely-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("tqm/weworkremotely-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 '{}' |
apify call tqm/weworkremotely-scraper --silent --output-dataset

```

## MCP server setup

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