# WeWorkRemotely Scraper | $1/1K — 7 Categories, No Login (`bovi/weworkremotely-scraper`) Actor

Collect remote job listings from WeWorkRemotely public RSS feeds. Get structured records with company, role, category, location, dates, skills, and descriptions. Run with category, keyword, limit, and description inputs. Pricing: $0.001 per result on Free, plus $0.00005 per Actor Start event.

- **URL**: https://apify.com/bovi/weworkremotely-scraper.md
- **Developed by:** [Vitalii Bondarev](https://apify.com/bovi) (community)
- **Categories:** Jobs, Lead generation, AI
- **Features:** Limited permissions
- **Stats:** 5 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.97 / 1,000 weworkremotely scraper | $1.50/1k — 7 categories, no logins

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

## WeWorkRemotely Jobs Scraper

Scrape remote job listings from WeWorkRemotely.com’s official public RSS feeds. Pay Per Event pricing on the Free plan: $0.001 per returned result, or $1.00 per 1,000 results, plus $0.00005 per Actor Start event. No login, API key or proxy is needed: the Actor reads WeWorkRemotely's public RSS feeds.

- Build remote-job aggregators from seven WWR categories or the all-jobs feed.
- Get company, role, region, location, and posting-date data for each job.
- Filter job titles by case-insensitive keywords.
- Extract raw HTML and plain-text descriptions when full listing content is needed.

### What you get

A field is `null` when the source does not provide the value.

| Field | Type | Description |
|---|---|---|
| `job_id` | string | URL slug used as the unique job identifier; `null` if no link or GUID is available. |
| `title` | string | Original `Company: Role` title; `null` when the source title is missing. |
| `company` | string | Text before the first colon in the title; `null` when the title has no company portion. |
| `role` | string | Text after the first colon in the title; when no colon is present, the full title is used as the role. |
| `category` | string | WWR category, such as `Product`; `null` when the source does not provide it. |
| `region` | string | RSS region, such as `Anywhere in the World`; `null` when the source does not provide it. |
| `location` | string | Best available location: state, country, then region; `null` when none is available. |
| `job_type` | string | Job type such as `Full-Time`, `Contract`, or `Part-Time`; `null` when the source does not provide it. |
| `skills` | string | Comma-separated skill tags when available; `null` when the source does not provide them. |
| `posted_at` | ISO 8601 string | ISO 8601 UTC posting date; `null` when missing; raw source string if unparseable. |
| `expires_at` | ISO 8601 string | ISO 8601 UTC expiry date; `null` for category-specific feeds or when unavailable. |
| `url` | string | Canonical WeWorkRemotely job page URL; `null` if both link and GUID are missing. |
| `description_html` | string | Raw HTML description when descriptions are enabled; `null` when disabled or unavailable. |
| `description_text` | string | Plain text converted from the HTML description; `null` when descriptions are disabled, unavailable, or empty after conversion. |
| `feed_type` | string | `all_jobs` or `category`. |
| `feed_slug` | string | RSS feed slug, such as `remote-programming-jobs` or `all-jobs`. |
| `parse_confidence` | number | Parse quality score from `0.0` to `1.0`. |
| `warnings` | array of strings | Machine-readable parsing warning codes; empty when no warnings are recorded. |

### Sample output

This sample is shortened: `description_html` and `description_text` are omitted.

```json
{
  "job_id": "committee-for-children-senior-product-manager-edtech-innovation",
  "title": "Committee for Children: Senior Product Manager - Edtech Innovation",
  "company": "Committee for Children",
  "role": "Senior Product Manager - Edtech Innovation",
  "category": "Product",
  "region": "Anywhere in the World",
  "location": "Florida",
  "job_type": "Full-Time",
  "skills": null,
  "posted_at": "2026-10-23T16:55:36Z",
  "expires_at": "2026-11-22T16:55:36Z",
  "url": "https://weworkremotely.com/remote-jobs/committee-for-children-senior-product-manager-edtech-innovation",
  "feed_type": "all_jobs",
  "feed_slug": "all-jobs",
  "parse_confidence": 1,
  "warnings": []
}
```

### Pricing

Pricing uses the Pay Per Event model. You pay only for the events listed below. This Actor does not use the Pay per event + usage option, so the platform usage of your runs (compute, proxy traffic and storage) is not billed to you separately.

| Event | Free-plan price | When charged |
|---|---:|---|
| `apify-actor-start` | $0.00005 per event on the Free plan | When the Actor starts. The number of events depends on Actor memory: one event per GB, with a minimum of one event. |
| `apify-default-dataset-item` | $0.001 per event on the Free plan | One scraped result with all fields. |

The events `category-filter` and `job-result` have no price, so the buyer is not charged for them.

Worked example on the Free plan: 1,000 results = 1,000 x $0.001 = $1.00 for dataset-item events, plus $0.00005 for one Actor Start event, so $1.00005 in total.

For 10,000 results on the Free plan: 10,000 x $0.001 = $10.00 for dataset-item events, plus $0.00005 for one Actor Start event, so $10.00005 in total.

The Apify Free plan includes **$5 of monthly platform usage credit**. Using the exact Free-plan event prices, the $5 credit covers 4,999 results in one run (one Actor Start event plus 4,999 × $0.001), before considering other use of the credit.

### How to use

1. **Open** the Actor in Apify and run it with your Apify account.
2. **Choose** one or more category keys, or leave `categories` empty to fetch the all-jobs feed.
3. **Add** optional keywords to return jobs whose title or role contains at least one case-insensitive keyword.
4. **Set** `maxItems` to control the total number of returned jobs and use `includeDescriptions` to include or omit both description fields.
5. **Review** the dataset records, including parsed company and role fields, feed metadata, dates, descriptions, confidence scores, and warnings.
6. **Schedule** the run through Apify Schedules; daily is a suitable starting point for job listings, then adjust it to your workflow.

Example input:

```json
{
  "categories": ["programming", "devops"],
  "keywords": ["senior", "lead"],
  "maxItems": 50,
  "includeDescriptions": true
}
```

Export the dataset as JSON or CSV, or read it through the Apify dataset API.

### Input parameters

| Parameter | What it does | Default |
|---|---|---|
| `categories` | Array of category keys: `programming`, `design`, `devops`, `product`, `customer_support`, `sales_marketing`, or `management_finance`. An empty array fetches the all-jobs feed. | `[]` |
| `keywords` | Case-insensitive filter applied to job titles and roles. A job is returned when its title or role contains at least one keyword. | `[]` |
| `maxItems` | Maximum total jobs to return. Set to `0` for no limit. The minimum accepted value is `0`. | `200` |
| `includeDescriptions` | Includes `description_html` and `description_text` when `true`; setting it to `false` reduces output size. | `true` |
| `disableUsageStats` | Set to `true` to turn off the run summary described in Usage statistics. | `false` |

### Limits and edge cases

#### Feed selection

The Actor reads WeWorkRemotely’s public RSS feeds. These are the available category keys and their RSS slugs:

| Category key | RSS slug |
|---|---|
| `programming` | `remote-programming-jobs` |
| `design` | `remote-design-jobs` |
| `devops` | `remote-devops-sysadmin-jobs` |
| `product` | `remote-product-jobs` |
| `customer_support` | `remote-customer-support-jobs` |
| `sales_marketing` | `remote-sales-and-marketing-jobs` |
| `management_finance` | `remote-management-and-finance-jobs` |
| `[]` | `all-jobs` |

| Condition | What you see | What to do |
|---|---|---|
| `categories` is empty | The Actor fetches the all-jobs feed. | Keep it empty for the main feed, or select category keys for targeted feeds. |
| A category-specific feed is used | That feed does not supply `country`, `state`, `type`, `skills`, or `expires_at`; those fields can be `null` and `location` falls back to the region. | Use `categories: []` when those all-jobs fields are important. |
| `maxItems` is `0` | The Actor does not apply an item limit and returns available matching jobs. | Use `0` only when you want all available matches from the selected feeds. |
| `includeDescriptions` is `false` | `description_html` and `description_text` are `null`. | Enable it when listing content is required. |
| Multiple categories contain the same job | Duplicate records are removed by `job_id`. | Review the remaining unique records. |
| Keywords match no loaded jobs | The dataset is empty and the run reports `NO_MATCH_FOR_INPUT`. | Broaden or remove the keywords and retry. |
| A requested category key is invalid | The invalid category is skipped. If none of the requested categories is valid, the run fails and reports `no_valid_category`. | Use one of the seven documented category keys or leave the array empty. |
| A requested RSS feed fails | The failed feed is skipped; other feeds still return jobs, and `OUTPUT` lists the failed feeds. | Check `OUTPUT` and retry. |
| A feed fails and zero rows match | The run fails (`partial_feed_failure`), because it cannot confirm a complete search. Nothing is charged. | Retry; check `OUTPUT.failedDetails`. |
| A source date cannot be parsed | `posted_at` or `expires_at` holds the raw source string, not ISO 8601. | Check the value before using it as a date. |
| Rows are pushed during a run | Records reach the dataset in batches of up to 100. Pushed rows stay if the run stops; the current unpushed batch is lost. | Review delivered rows and rerun if needed. |
| Listings are no longer active | The feeds provide current live listings; the Actor does not provide historical data. | Run the Actor again to collect the listings currently available in the feeds. |

### FAQ

#### How much does it cost to scrape WeWorkRemotely jobs?

See Pricing for the Free-plan event prices and the 1,000-result worked example.

#### Why did the Actor return an empty dataset?

An empty dataset can mean that all selected feeds loaded successfully but no job matched the supplied keywords. Remove `keywords`, broaden the terms, or check that the selected category keys are valid. A feed failure is reported separately in the run output.

#### What happens if a category feed is unavailable?

The Actor skips the unavailable feed and continues with other requested feeds. If other feeds return jobs, review the partial-result status and `OUTPUT` failed-feed details; if no jobs are delivered, retry the run after checking the request.

#### Is it legal or allowed to use data from WeWorkRemotely?

The Actor accesses WeWorkRemotely’s public RSS data. Source terms and applicable law depend on your use case, so review the relevant terms and requirements before using the results.

### Related actors

- [WeWorkRemotely Programming Jobs](https://apify.com/bovi/weworkremotely-programming-jobs) — focused WeWorkRemotely programming RSS feed.
- [Ashby Jobs API Scraper](https://apify.com/bovi/ashby-job-scraper) — related job data with salary ranges and seniority information.
- [Google Jobs Scraper](https://apify.com/bovi/google-jobs-scraper) — related postings with multi-board apply links.

### Usage statistics

This Actor creates a small, content-free summary at the end of each run, used only to monitor reliability and improve this Actor. No input values, credentials or scraped data are sent.

A copy of the exact record for your run is saved as `USAGE_STATS` in your own Apify key-value store.

To opt out, set `disableUsageStats` to `true` in the input. Nothing is sent then.

[Full list of collected fields](https://api.apify.com/v2/key-value-stores/v9rgHjMKLDGtHf8tD/records/index.html)

# Actor input Schema

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

Which job categories to scrape. Leave empty to fetch ALL jobs from the main feed. Valid values: programming, design, devops, product, customer_support, sales_marketing, management_finance. Example: \["programming", "devops"].

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

Case-insensitive keyword filter applied to job titles. Only jobs whose title contains at least one keyword are returned. Example: \["senior", "lead"]. Leave empty for no filter.

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

Maximum total jobs to return. 0 = no limit (returns all available, typically 25–100 per category, ~97 for the all-jobs feed).

## `includeDescriptions` (type: `boolean`):

When enabled, each result includes description_html (raw HTML) and description_text (plain text stripped from HTML). Disable to reduce output size for large runs.

## `disableUsageStats` (type: `boolean`):

See the README Usage statistics section for details.

## Actor input object example

```json
{
  "categories": [],
  "keywords": [],
  "maxItems": 200,
  "includeDescriptions": true,
  "disableUsageStats": false
}
```

# Actor output Schema

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

Dataset containing Weworkremotely Scraper records (company, role, category, location, job_type, posted_at, url, feed_slug, parse_confidence, warnings).

# 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": [],
    "keywords": [],
    "maxItems": 200,
    "includeDescriptions": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("bovi/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 = {
    "categories": [],
    "keywords": [],
    "maxItems": 200,
    "includeDescriptions": True,
}

# Run the Actor and wait for it to finish
run = client.actor("bovi/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 '{
  "categories": [],
  "keywords": [],
  "maxItems": 200,
  "includeDescriptions": true
}' |
apify call bovi/weworkremotely-scraper --silent --output-dataset

```

## MCP server setup

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