# We Work Remotely Jobs Scraper (`muhammadafzal/we-work-remotely-jobs-scraper`) Actor

Extract We Work Remotely jobs with titles, companies, regions, skills, categories, descriptions, dates, and URLs for recruiting and job alerts.

- **URL**: https://apify.com/muhammadafzal/we-work-remotely-jobs-scraper.md
- **Developed by:** [Muhammad Afzal](https://apify.com/muhammadafzal) (community)
- **Categories:** Jobs, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 remote job records

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

**Free plan limit:** Free-plan users can receive up to **5 result records per run**. Paid-plan and local/unknown runs retain the Actor's existing limits.

Extract current remote jobs from We Work Remotely into clean, schema-validated records for recruiting, job alerts, market research, spreadsheets, and AI agents.

The Actor uses We Work Remotely's public first-party RSS feeds. It does not automate the Cloudflare-protected HTML job board, solve challenges, require login cookies, or depend on an external data provider.

### What it extracts

| Field | Meaning |
| --- | --- |
| `jobId`, `jobUrl` | Stable listing slug and canonical We Work Remotely URL |
| `title`, `company` | Normalized position title and hiring company |
| `region`, `country`, `state` | Remote eligibility fields provided by the source |
| `category`, `employmentType`, `skills` | Source job classification and skill labels |
| `headquarters`, `companyWebsite` | Company information parsed from the listing header |
| `descriptionText`, `descriptionHtml` | Clean text and optional source-formatted description |
| `postedAt`, `expiresAt`, `isExpired` | Normalized listing dates and calculated expiry state |
| `logoUrl` | Source company logo URL when available |
| `sourceFeedUrl`, `scrapedAt` | Provenance and extraction time |

Use it when you need current public listings, keyword/category/location filtering, structured downstream automation, or repeatable scheduled exports. Do not use it for historical jobs no longer present in the feeds, application submission, applicant data, inferred work authorization, contact enrichment, or private employer information.

### Input

The default input returns up to 100 newest jobs from the main public feed:

```json
{
  "feedUrls": ["https://weworkremotely.com/remote-jobs.rss"],
  "searchTerms": [],
  "categories": [],
  "regions": [],
  "employmentTypes": [],
  "skills": [],
  "maxResults": 100,
  "includeDescriptionHtml": true,
  "maxRequestRetries": 2
}
```

For a narrower developer search:

```json
{
  "feedUrls": [
    "https://weworkremotely.com/categories/remote-programming-jobs.rss"
  ],
  "searchTerms": ["Python", "TypeScript"],
  "regions": ["Anywhere in the World"],
  "employmentTypes": ["Full-Time"],
  "postedWithinDays": 30,
  "maxResults": 50,
  "includeDescriptionHtml": false,
  "maxRequestRetries": 2
}
```

Filters are applied after records from up to 10 feeds are deduplicated by stable job ID. `searchTerms`, `regions`, and `skills` match any supplied phrase. `categories` and `employmentTypes` use case-insensitive exact matching. Empty filter arrays accept all values.

#### Run through the Apify API

Replace `YOUR_USERNAME` and `YOUR_TOKEN` with your own values:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/YOUR_USERNAME~we-work-remotely-jobs-scraper/runs?token=YOUR_TOKEN" \
  -H "content-type: application/json" \
  -d '{"searchTerms":["Python"],"maxResults":10}'
```

For production integrations, send the token in an authorization header instead of a URL, and retrieve results from the run's default dataset URL.

### Output example

```json
{
  "jobId": "evaboot-agentic-python-engineer",
  "title": "Agentic Python Engineer",
  "company": "Evaboot",
  "region": "Anywhere in the World",
  "country": null,
  "state": "Harjumaa (Tallinn)",
  "skills": ["Python", "Engineer"],
  "category": "Back-End Programming",
  "employmentType": "Full-Time",
  "headquarters": "Estonia",
  "companyWebsite": "https://evaboot.com/",
  "descriptionText": "Evaboot | Agentic Python Engineer | REMOTE...",
  "descriptionHtml": "<p>Evaboot | Agentic Python Engineer | REMOTE...</p>",
  "postedAt": "2026-08-31T15:05:39.000Z",
  "expiresAt": "2026-09-30T15:05:39.000Z",
  "isExpired": false,
  "logoUrl": "https://wwr-pro.s3.amazonaws.com/logos/0171/6290/logo.gif",
  "jobUrl": "https://weworkremotely.com/remote-jobs/evaboot-agentic-python-engineer",
  "sourceFeedUrl": "https://weworkremotely.com/remote-jobs.rss",
  "scrapedAt": "2026-08-31T18:45:00.000Z"
}
```

Business records go only to the default dataset. `SUMMARY` and `OUTPUT` records in the default key-value store report `data`, `empty`, `blocked`, or `failed` outcomes, requested/fetched feed counts, parsed and delivered job counts, filters, warnings, and timestamps. A valid no-match search returns an empty dataset with explicit diagnostics and no result-event charges.

### Pay-per-event pricing

This Actor uses **pay-per-event** pricing. These are the current Apify Store event prices:

| Event | Price (USD) | When it is charged |
|---|---:|---|
| `apify-actor-start` | $0.00005 | Actor Start — Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). |
| `apify-default-dataset-item` | $0.001 | Remote job record — One normalized, schema-valid We Work Remotely job written to the default dataset. |

Apify platform usage for this Actor run is included alongside the event prices above; no separate per-run platform-usage fee is passed to users.

This covers Apify platform usage for this Actor run. Other Apify products or usage outside this Actor run may still follow your account plan.

### Reliability and limits

The scraper starts with the cheapest direct-source route: static HTTPS requests to first-party RSS. Requests use a consistent browser-like identity, a 30-second timeout, and bounded exponential retries for temporary failures. Multiple feeds are deduplicated before output. The Actor does not silently replace blocked data with fabricated jobs.

The current RSS feed determines coverage and history. Some source fields are legitimately blank and appear as `null` or empty arrays. Description formatting and company URL placement vary by employer; critical records are validated before they are saved. A failure to read every requested feed produces a warning while preserving valid results from feeds that succeeded. If all feeds fail, the run records a truthful diagnostic and does not charge result events.

### Legal and responsible use

Use the Actor only for lawful purposes and follow We Work Remotely's terms, robots guidance, and applicable privacy, employment, database, and copyright rules. Job descriptions may contain personal or sensitive information supplied by employers; minimize retention, avoid discriminatory profiling, and do not republish full descriptions without the necessary rights. This Actor is an independent tool and is not affiliated with or endorsed by We Work Remotely.

For support, open an issue on the Actor page with a run ID, redacted input, expected outcome, and actual outcome. Never post API tokens or private applicant information.

### Pricing

This Actor uses **pay-per-event** pricing. These are the current Apify Store event prices:

| Event | Price (USD) | When it is charged |
|---|---:|---|
| `apify-actor-start` | $0.00005 | Actor Start — Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). |
| `apify-default-dataset-item` | $0.001 | Remote job record — One normalized, schema-valid We Work Remotely job written to the default dataset. |

Apify platform usage for this Actor run is included alongside the event prices above; no separate per-run platform-usage fee is passed to users.

This covers Apify platform usage for this Actor run. Other Apify products or usage outside this Actor run may still follow your account plan.

# Actor input Schema

## `feedUrls` (type: `array`):

Use this when you want the main feed or specific We Work Remotely category feeds. Enter 1–10 HTTPS URLs ending in .rss, for example https://weworkremotely.com/categories/remote-programming-jobs.rss. Defaults to the main remote-jobs.rss feed; ordinary HTML job pages are not accepted.

## `searchTerms` (type: `array`):

Use this to match at least one keyword or phrase across title, company, location, category, skills, and description. Example: Python. Empty means no keyword filter; this is not a search-engine query syntax.

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

Use this to keep exact category names from the feed, for example Full-Stack Programming or Sales and Marketing. Matching ignores letter case. Empty means every category; this is not a category URL field.

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

Use this to match at least one phrase in the region, country, or state fields. Example: Anywhere in the World. Empty means every location; this does not geocode or infer work authorization.

## `employmentTypes` (type: `array`):

Use this to keep exact feed types such as Full-Time or Contract. Matching ignores letter case. Empty means every type; this does not infer a type from description text.

## `skills` (type: `array`):

Use this to match at least one skill phrase supplied by We Work Remotely, for example Python. Empty means every skill; jobs whose feed skill field is blank will not match a non-empty filter.

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

Use this to keep only recently posted jobs. Enter 1–365; for example 7 keeps the last seven days. Omit it to include the entire current RSS feed; this is not an expiry filter.

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

Use this to cap unique dataset records and result-event charges. Enter 1–1000; the default is 100. This limit is applied after filters and deduplication, not per feed.

## `includeDescriptionHtml` (type: `boolean`):

Use this when you need the source formatting as well as clean descriptionText. Defaults to true. Disable it for smaller records; this does not remove descriptionText.

## `maxRequestRetries` (type: `integer`):

Use this to retry temporary 429, 5xx, timeout, or connection errors. Enter 0–5; the default is 2 with exponential backoff. Permanent non-RSS responses are still reported truthfully.

## Actor input object example

```json
{
  "feedUrls": [
    "https://weworkremotely.com/remote-jobs.rss"
  ],
  "searchTerms": [],
  "categories": [],
  "regions": [],
  "employmentTypes": [],
  "skills": [],
  "maxResults": 100,
  "includeDescriptionHtml": true,
  "maxRequestRetries": 2
}
```

# Actor output Schema

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

Normalized We Work Remotely jobs in the default dataset.

## `summary` (type: `string`):

Counts, applied filters, warnings, and data/empty/blocked status.

## `output` (type: `string`):

Machine-readable result counts and diagnostics for agent workflows.

# 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("muhammadafzal/we-work-remotely-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 = {}

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,muhammadafzal/we-work-remotely-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/1cb9CQDUOlCqRT4FO/builds/gQeqgsMo3DtJ5pbEp/openapi.json
