# We Work Remotely Jobs Scraper (`solidcode/weworkremotely-scraper`) Actor

\[💰 $1.00 / 1K] Extract remote job listings from We Work Remotely. Filter by keyword, category, region, employment type and recency. Get titles, companies, every region a role is open to, salary bands, exact posting times, full descriptions and listing URLs.

- **URL**: https://apify.com/solidcode/weworkremotely-scraper.md
- **Developed by:** [SolidCode](https://apify.com/solidcode) (community)
- **Categories:** Jobs, Automation, Developer tools
- **Features:** Limited permissions
- **Stats:** 8 total users, 2 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.
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

Extract every remote job posted on We Work Remotely — title, company, every region the role is open to, salary, employment type, the exact publication time, the full description and the listing's own URL — in one structured dataset. Built for recruiters sourcing remote candidates, job-board aggregators, salary-data analysts, and ATS integrations that need fresh remote-job data without reading listing pages by hand.

### Why This Scraper?

- **Whole-board coverage: 11 selectable category pages, 10 real category labels** — Full-Stack, Front-End, Back-End, Design, DevOps & Sysadmin, Management & Finance, Product, Customer Support, Sales & Marketing and All Other Remote Jobs, each selectable from a dropdown. The 11th page, Software Developer, is We Work Remotely's cross-listing surface — its jobs all belong to one of the other 10 — so a full board sweep in September 2026 returned 336 jobs carrying 10 distinct `category` values.
- **5 region presets that respect "Anywhere in the World"** — Anywhere, USA Only, Americas, EMEA and APAC. Each preset is matched against the job's full eligibility list rather than a single headline badge, so a worldwide-open role is never dropped from a USA-only run — and on the live board 295 of 336 jobs are open to anywhere in the world.
- **Salary parsed into `salaryMin`, `salaryMax`, `salaryCurrency` and `salaryInterval` — and never invented** — the human-readable string is preserved as `salaryRaw`. We Work Remotely leaves pay off most postings: 60 of 336 jobs (17.9%) on a full board sweep showed a band, and 51 of those 60 also carried a machine-readable amount. Where there is no real figure all five fields come back empty, instead of a placeholder currency and interval that would poison your averages.
- **3 employment-type options + 5 "posted within" windows** — Full-Time or Contract; 24 hours, 3 days, 7 days, 30 days, or Any time. Every date window is measured against the job's exact publication timestamp, which is filled on 100% of rows in both light and full modes.
- **`includeDescription` toggle for cheap light-mode scans** — turn full descriptions off to skim the whole 336-job board in one pass at a fraction of the cost, or leave it on (the default) for `descriptionText`, `descriptionHtml`, parsed salary amounts and `companyWebsite`. Titles, companies, regions, listing chips, most logos, card salary bands and exact posting times come back either way.
- **Full-text keyword search across title, company and the entire job description** — a search for `python` returns every posting that mentions it anywhere in the job text, not just the ones carrying it in the headline: 45 matches on a live 336-job board against the 6 that name it in the title or company. Keywords match as whole words, so `java` returns 12 genuine Java roles and leaves out the 17 listings that only ever mention JavaScript.
- **`startUrls` accepts any We Work Remotely category or search URL** — paste a saved filter URL to pick the pages you want, and your keyword, region, employment type and date window still narrow what comes back.
- **Cross-category deduplication** — a job tagged Full-Stack *and* Front-End appears exactly once. Sweeping all 11 category pages returned 336 rows and 336 distinct jobs: zero repeats.
- **Every listing chip captured in a `categories` array** — employment type, region and country labels and the "Top 100" badge, non-empty on 100% of rows. Switch full descriptions on and every row also gains its category label plus any named skills the employer listed, such as React, Figma or Ruby on Rails: 78 of 336 jobs (23.2%) carry skills, a median of 3 each.

### Use Cases

**Recruitment & Talent Sourcing**

- Build a daily feed of new remote Senior Engineer roles in a target stack
- Surface contract-only postings for a freelance bench
- Track competing remote employers hiring for the same role
- Identify worldwide-eligible jobs to widen your candidate funnel

**Market & Salary Research**

- Benchmark the pay bands that are published, by category and region, with parsed `salaryMin`/`salaryMax`
- Track the share of Full-Time vs. Contract roles over time
- Measure hiring velocity by counting `postedWithin=24h` snapshots day over day
- Identify which categories publish pay at all — roughly 18% of live postings show a band

**Job Board & Aggregator Operations**

- Power a niche remote-jobs vertical with a clean, deduped feed
- Cross-post curated remote roles into a Slack or Discord community
- Auto-update a static jobs site from a scheduled We Work Remotely pull
- Run keyword digests (e.g. "rust", "Postgres", "Figma") on a daily schedule

**ATS & CRM Enrichment**

- Enrich a CRM of remote-friendly companies with their currently open roles
- Attach employer logos to partner records for the roughly one listing in three that carries one
- Stream new postings into Zapier for inbox or Slack alerts
- Match candidate profiles against postings within hours of publication

### Getting Started

#### Minimal — one category, default cap

```json
{
    "categories": ["remote-full-stack-programming-jobs"],
    "maxResults": 25
}
```

#### Keyword + region filter

```json
{
    "searchQuery": "rust",
    "region": "usa",
    "maxResults": 50
}
```

#### Multi-category, last 7 days

```json
{
    "categories": [
        "remote-full-stack-programming-jobs",
        "remote-customer-support-jobs"
    ],
    "postedWithin": "7",
    "maxResults": 100
}
```

#### Direct URL, light mode (no descriptions)

```json
{
    "startUrls": [
        "https://weworkremotely.com/categories/remote-customer-support-jobs"
    ],
    "includeDescription": false,
    "maxResults": 30
}
```

### Input Reference

#### Search

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `searchQuery` | string | `""` | Free-text keyword such as 'python', 'designer', or 'marketing manager'. Matches anywhere in the posting — job title, company name and the full job description — as a whole word, so 'java' will not return JavaScript jobs while plurals still match ('designer' finds 'designers'). Leave empty for no keyword filter. |
| `categories` | string\[] | `[]` | Pick one or more job categories. Leave empty to include all categories. Options: Full-Stack Programming, Front-End Programming, Back-End Programming, Software Developer (general), Design, DevOps & Sysadmin, Management & Finance, Product, Customer Support, Sales & Marketing, All Other Remote Jobs. |
| `region` | select | `Any region` | Geographic eligibility filter. We Work Remotely tags each listing with a region. Options: Any region, Anywhere in the World, USA Only, Americas Only, EMEA Only, APAC Only. |
| `employmentType` | select | `Any` | Filter by employment type. Options: Any, Full-Time, Contract. |
| `postedWithin` | select | `Any time` | Only show jobs posted within this time window. Options: Any time, Last 24 hours, Last 3 days, Last 7 days, Last 30 days. |
| `startUrls` | string\[] | `[]` | Optional. Paste full We Work Remotely search or category URLs (e.g., `https://weworkremotely.com/categories/remote-design-jobs`) to choose which pages are read. This replaces the Categories dropdown and the built-in search; the keyword, region, employment-type and posted-within filters still apply to what those pages return. |

#### Results

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `maxResults` | integer | `100` | Maximum number of jobs to collect across all categories/URLs in this run. Set to 0 for no cap. |
| `includeDescription` | boolean | `true` | On by default: fetch the full description, the parsed salary amount and the company website from each listing's own page. Turn it off for faster, cheaper light scans — `descriptionHtml`, `descriptionText`, the four salary amount fields and `companyWebsite` are then left empty. Everything else, including the exact posting time, the card salary band, region, the listing's chips and most logos, comes back either way. With descriptions on, `categories` also gains the job's category label and any named skills the employer listed. |

### Output

Each result is a flat one-row-per-job record. Here is a real row from a default run. `descriptionHtml` is omitted for length. Salary amounts, `companyWebsite` and `companyLogo` are filled only where We Work Remotely itself publishes them — the fill notes under each table below give the measured rates.

```json
{
    "url": "https://weworkremotely.com/remote-jobs/samsara-staff-software-engineer",
    "guid": "samsara-staff-software-engineer",
    "title": "Staff Software Engineer",
    "company": "Samsara",
    "companyWebsite": "https://www.samsara.com/",
    "category": "remote-full-stack-programming-jobs",
    "categories": ["Full-Time", "United States of America", "Full-Stack Programming"],
    "region": "United States of America",
    "location": "Remote",
    "employmentType": "Full-Time",
    "salaryRaw": "$100,000 or more USD",
    "salaryMin": 100000,
    "salaryMax": 100000,
    "salaryCurrency": "USD",
    "salaryInterval": "year",
    "datePosted": "2026-08-17T13:57:14+00:00",
    "datePostedRelative": "18d",
    "descriptionText": "About the role: Samsara (NYSE: IOT) sits at the center of hardware, software, AI...",
    "applyUrl": null,
    "companyLogo": "https://we-work-remotely.imgix.net/logos/0154/3705/logo.gif?ixlib=rails-4.0.0&w=50&h=50&dpr=2&fit=fill&auto=compress",
    "scrapedAt": "2026-09-04T15:21:30.315663+00:00"
}
```

#### Core Job Info

| Field | Type | Description |
|-------|------|-------------|
| `url` | string | Canonical We Work Remotely job detail URL |
| `guid` | string | Stable slug used as a unique identifier across runs |
| `title` | string | Job title |
| `company` | string | Hiring company name |
| `category` | string | The category We Work Remotely itself assigns to the job — one of 10 slugs, regardless of which listing page it was found on |
| `categories` | string\[] | Every chip on the listing — employment type, region and country labels and the "Top 100" badge. With full descriptions on, the job's category label is added, plus any named skills the employer listed in the listing's own Skills box (78 of 336 jobs, a median of 3 each) |
| `region` | string | Every region the job is open to, comma-separated when there is more than one — a worldwide label ("Anywhere in the World"), a single country ("United States of America"), or a full country list. 15 of 336 jobs on a live board list several, the longest naming 51 countries. Note the asymmetry with the `region` input filter, which has 5 coarse presets: filtering by USA Only still surfaces rows reading "United States of America" and "Anywhere in the World", because both are genuinely US-eligible. |
| `location` | string | Free-text company headquarters from the listing card |
| `employmentType` | string | Normalized "Full-Time" or "Contract" |
| `datePosted` | string | Exact publication timestamp, to the second — filled on 100% of rows whether full descriptions are on or off, and identical in both modes on 335 of 336 jobs cross-checked |
| `datePostedRelative` | string | Freshness label exactly as the listing shows it ("New", "1d", "16d") — always present, on every run type |
| `scrapedAt` | string | ISO timestamp of data extraction |

#### Salary & Compensation

| Field | Type | Description |
|-------|------|-------------|
| `salaryRaw` | string | Human-readable salary string as displayed on the listing (e.g. "$100,000 or more USD") |
| `salaryMin` | number | Parsed minimum salary value |
| `salaryMax` | number | Parsed maximum salary value |
| `salaryCurrency` | string | Three-letter currency code (e.g. "USD", "EUR") |
| `salaryInterval` | string | Pay interval (year, month, week, day, hour) |

We Work Remotely publishes compensation on a minority of postings, and how many you see depends on which jobs your run covers. A full 336-job sweep showed a pay band on 60 listings (17.9%), and 51 of those 60 also carried a machine-readable amount — 15.2% of the whole board. A capped run reads the top of every category page, where the upgraded listings sit, so it lands higher: 27 of 100 rows on a default 100-job run. Postings without a real figure return all five fields empty. Where a listing shows a range, We Work Remotely publishes only its floor as a machine-readable number, so `salaryMax` equalled `salaryMin` on all 51 — `salaryRaw` keeps the full band as written.

#### Company & Description

| Field | Type | Description |
|-------|------|-------------|
| `companyWebsite` | string | The employer's own site, taken from the listing's own page. How often it is there depends on the category: a full 336-job sweep filled it on 120 rows (35.7%), from 65% of All Other Remote Jobs and 61% of Design roles down to 12% of Full-Stack Programming. A capped run reads the top of every category page, where the upgraded listings sit, and does better still — 55 of 100 rows on a default 100-job run. Where We Work Remotely holds no employer URL the field is empty; it never points at the job board itself |
| `companyLogo` | string | Employer logo image URL. We Work Remotely only publishes a logo on upgraded listings — 104 of 336 jobs (31.0%) on a light board sweep, rising to 121 of 336 (36.0%) with full descriptions on, because some listings show a logo on their own page that the card omits |
| `descriptionText` | string | Plain-text job description |
| `descriptionHtml` | string | Original HTML job description with formatting preserved |
| `applyUrl` | string | Direct apply link. We Work Remotely keeps this behind a login, so it is empty on every row — the `url` field opens the listing's own page, where the apply button lives |

### Tips for Best Results

- **Start with `maxResults: 25`** on your first run to confirm the filter combo returns what you expect, then scale up.
- **Use `includeDescription: false` for cheap snapshots** — titles, companies, regions, listing chips, most logos, card salary bands and the exact posting time all come back from a single pass over each category.
- **For salary research, run one category at `maxResults: 0` and filter the sheet on `salaryRaw`** — it is the widest net at 60 of 336 live postings (17.9%), and 51 of those 60 also carry parsed `salaryMin`/`salaryMax` amounts. Sizing a study on `salaryRaw` first tells you how big a sample you actually have.
- **To monitor a niche keyword, schedule the actor daily with `postedWithin: "1"`** and `searchQuery` set to your term — each run returns only fresh postings from the last 24 hours.
- **Cross-reference `region: "anywhere"` against `region: "usa"`** to surface roles that are worldwide-eligible but specifically include the US, versus roles that are US-only.
- **Sort on `datePosted` for true recency** — it is the exact publication time on every row, in both light and full runs. `datePostedRelative` is the board's own label, so a refreshed listing reads "New" while `datePosted` keeps its original time: the two answer different questions.
- **`applyUrl` is behind a We Work Remotely login and is empty on every row** — use `url`, which opens the listing's own page with its apply button. For CRM matching reach for `companyWebsite` instead: it filled 55 of 100 rows on a default capped run, and coverage is highest in All Other Remote Jobs, Design and Sales & Marketing and lowest in Full-Stack Programming, where it is closer to one row in eight.

### Pricing

**From $1.00 per 1,000 results** — pay only for what you get. No compute charges — you only pay per result returned. Your Apify discount tier sets your rate, and Gold subscribers pay the lowest.

| Results | No discount | Bronze | Silver | Gold |
|---------|-------------|--------|--------|------|
| 100 | $0.12 | $0.11 | $0.11 | $0.10 |
| 1,000 | $1.20 | $1.13 | $1.06 | $1.00 |
| 10,000 | $12.00 | $11.30 | $10.65 | $10.00 |
| 100,000 | $120.00 | $113.00 | $106.50 | $100.00 |

Tiered rates take effect on 19 September 2026; until then every plan pays $1.00 per 1,000 results. A "result" is any job row in the output dataset. Platform fees (compute, storage) are additional and depend on your Apify plan.

### Integrations

Export data in JSON, CSV, Excel, XML, or RSS. Connect to 1,500+ apps via:

- **Zapier** / **Make** / **n8n** — Workflow automation
- **Google Sheets** — Direct spreadsheet export
- **Slack** / **Email** — Notifications on new postings
- **Webhooks** — Custom API integrations
- **Apify API** — Full programmatic access

### Legal & Ethical Use

This actor is designed for legitimate recruitment research, market analysis, and job-aggregation use cases. Users are responsible for complying with applicable laws and We Work Remotely's Terms of Service. Do not use extracted data for spam, harassment, or any illegal purpose. Respect candidate privacy and the hiring company's stated application channels.

# Actor input Schema

## `searchQuery` (type: `string`):

Free-text keyword such as 'python', 'designer', or 'marketing manager'. Matches anywhere in the posting - job title, company name and the full job description - not just the headline. The keyword has to appear as a whole word, so 'java' won't return JavaScript jobs, while plurals still match ('designer' finds 'designers'). It also narrows any pages you paste into Direct URLs. Leave empty for no keyword filter.

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

Pick one or more job categories. Leave empty to include all categories.

## `region` (type: `string`):

Geographic eligibility filter. Jobs open to anywhere in the world are kept by every preset, since they are eligible everywhere. Leave on 'Any' for no region filter.

## `employmentType` (type: `string`):

Filter by employment type. Leave on 'Any' for both.

## `postedWithin` (type: `string`):

Only show jobs posted within this time window.

## `startUrls` (type: `array`):

Optional. Paste full We Work Remotely search or category URLs (e.g., https://weworkremotely.com/categories/remote-design-jobs) to choose which pages are read - this replaces the Categories dropdown and the built-in search. The Search Keyword, region, employment-type and posted-within filters still apply to the jobs found on those pages.

## `maxResults` (type: `integer`):

Maximum number of jobs to collect across all categories/URLs in this run. Set to 0 for no cap.

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

On by default. Fetches the full description, the parsed salary amount and the company website from each listing's own page. Turn it off for faster, cheaper light scans - descriptionHtml, descriptionText, the salary amount fields and companyWebsite are then left empty. Everything else, including the exact posting time, the card salary band, region, the listing's chips and most logos, comes back either way. With descriptions on, categories also gains the job's category label and any named skills the employer listed.

## Actor input object example

```json
{
  "searchQuery": "",
  "categories": [],
  "region": "",
  "employmentType": "",
  "postedWithin": "",
  "startUrls": [],
  "maxResults": 100,
  "includeDescription": true
}
```

# Actor output Schema

## `overview` (type: `string`):

Table of jobs with the most useful fields: title, company, category, region, salary, and link.

## `details` (type: `string`):

Full per-job rows including the job description, the salary breakdown and the company website.

# 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 = {
    "searchQuery": "",
    "categories": [],
    "region": "",
    "employmentType": "",
    "postedWithin": "",
    "startUrls": [],
    "maxResults": 100,
    "includeDescription": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("solidcode/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 = {
    "searchQuery": "",
    "categories": [],
    "region": "",
    "employmentType": "",
    "postedWithin": "",
    "startUrls": [],
    "maxResults": 100,
    "includeDescription": True,
}

# Run the Actor and wait for it to finish
run = client.actor("solidcode/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 '{
  "searchQuery": "",
  "categories": [],
  "region": "",
  "employmentType": "",
  "postedWithin": "",
  "startUrls": [],
  "maxResults": 100,
  "includeDescription": true
}' |
apify call solidcode/weworkremotely-scraper --silent --output-dataset

```

## MCP server setup

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