# We Work Remotely Jobs Scraper (`automation-lab/weworkremotely-full-description-jobs`) Actor

Collect public We Work Remotely jobs as normalized records with company, title, region, category, dates, canonical URL, and full description.

- **URL**: https://apify.com/automation-lab/weworkremotely-full-description-jobs.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.48 / 1,000 item extracteds

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

## We Work Remotely Jobs Scraper

Collect current **we work remotely jobs** from the site's public RSS feeds and turn them into normalized vacancy records. Each result includes a stable job ID, company, title, region, category, publication date, canonical URL, and the full description in both HTML and plain text.

Use the Actor for recurring remote-job aggregation, recruiting research, alerts, spreadsheets, or data pipelines. It runs without a We Work Remotely account, browser, or proxy.

### What does this We Work Remotely scraper do?

The Actor reads the official public We Work Remotely RSS feeds.

It can:

- collect the all-jobs feed or selected job categories;
- search titles, companies, regions, categories, and descriptions by keyword;
- filter by region, country, or state text;
- keep only jobs published after a supplied timestamp;
- deduplicate jobs that occur in more than one selected feed;
- return newest jobs first;
- preserve the source description HTML;
- provide normalized plain-text descriptions for analysis;
- limit output from 1 to 1,000 matching jobs.

It does not submit applications, scrape private employer data, or create a historical database for you.

### Who is this Actor for?

**Job aggregators** can add a source-attributed We Work Remotely feed to a multi-board catalog.

**Recruiting teams** can collect remote vacancies by category or candidate region.

**Labor-market analysts** can schedule snapshots and compare stable job IDs, dates, categories, and descriptions downstream.

**Developers** can use it as a simple weworkremotely API through the Apify API, SDK, webhooks, or MCP.

**Automation teams** can send datasets to Google Sheets, Airtable, a warehouse, or an alerting workflow.

### Why use the RSS-based route?

The public feeds already contain the complete job descriptions required by this Actor.

That means a typical run needs:

- one lightweight HTTP request for the all-jobs feed;
- no browser rendering;
- no login or cookies;
- no proxy transfer;
- no request to every individual job page.

The Actor validates the response content type and RSS shape. Transient timeouts, rate limits, and server errors receive bounded retries with backoff. Stable input or response errors fail clearly instead of returning a misleading empty dataset.

### We Work Remotely job categories

Choose `all` by itself, or combine specific categories:

| Input value | Feed scope |
| --- | --- |
| `all` | All current jobs in the public all-jobs feed |
| `programming` | Programming jobs |
| `customer-support` | Customer support jobs |
| `design` | Design jobs |
| `devops-sysadmin` | DevOps and system administration jobs |
| `product` | Product jobs |
| `sales-marketing` | Sales and marketing jobs |
| `management-finance` | Management and finance jobs |
| `all-other` | Jobs in the all-other category |

Do not combine `all` with a specific category. The Actor rejects that input because the all-jobs feed already includes the category feeds.

### Getting started

1. Open the Actor in Apify Console.
2. Keep **All jobs** selected, or choose one or more categories.
3. Optionally add keyword, region, or publication-date filters.
4. Set **Maximum jobs** to the largest dataset you need.
5. Click **Start**.
6. Open the default dataset to preview or export the normalized records.
7. Schedule the Task if you need recurring collection.

A useful first input is:

```json
{
  "categories": ["all"],
  "maxItems": 25
}
```

### Input parameters

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `categories` | string array | `["all"]` | One all-jobs feed or one or more specific RSS categories. |
| `keywords` | string array | `[]` | Case-insensitive phrases matched against title, company, region, category, and full description. |
| `matchAllKeywords` | boolean | `false` | Require every keyword instead of any keyword. |
| `regions` | string array | `[]` | Case-insensitive phrases matched against region, country, and state. |
| `publishedAfter` | ISO date-time string | none | Exclude jobs older than this instant. |
| `maxItems` | integer | `100` | Save at most 1–1,000 matching jobs, newest first. |

Each keyword and region phrase can contain up to 80 characters. Each list accepts up to 20 values.

### Keyword and region filtering examples

Find jobs containing either `engineer` or `developer`:

```json
{
  "categories": ["all"],
  "keywords": ["engineer", "developer"],
  "matchAllKeywords": false,
  "maxItems": 100
}
```

Require both `python` and `ai` somewhere in the searchable job record:

```json
{
  "categories": ["programming"],
  "keywords": ["python", "ai"],
  "matchAllKeywords": true,
  "maxItems": 100
}
```

Collect location-unrestricted jobs:

```json
{
  "categories": ["all"],
  "regions": ["Anywhere in the World"],
  "maxItems": 100
}
```

Filtering occurs after parsing the current RSS records. A keyword match does not infer skills or eligibility that the source did not state.

### Output fields

Every accepted job is saved to the run's default dataset.

| Field | Meaning |
| --- | --- |
| `jobId` | Stable identifier derived from the canonical job URL. |
| `company` | Hiring company parsed from the RSS title, or `null`. |
| `title` | Job title without the company prefix. |
| `region` | Candidate region or location restriction. |
| `country` | Country supplied by the RSS item, or `null`. |
| `state` | State or province supplied by the RSS item, or `null`. |
| `category` | Detailed source category. |
| `employmentType` | Employment type when supplied. |
| `skills` | Source skill values normalized as an array. |
| `publishedAt` | ISO 8601 publication timestamp. |
| `expiresAt` | ISO 8601 expiry timestamp when supplied. |
| `url` | Canonical public job URL. |
| `descriptionHtml` | Full description HTML from the RSS feed. |
| `descriptionText` | Full description converted to plain text. |
| `feedCategories` | Selected feeds in which the job appeared. |
| `source` | `weworkremotely.com`. |
| `scrapedAt` | ISO 8601 extraction timestamp. |

Nullable source fields remain `null` rather than being invented.

### Example job record

A current run returned the following shape; the description is shortened here for readability:

```json
{
  "jobId": "evaboot-agentic-python-engineer",
  "company": "Evaboot",
  "title": "Agentic Python Engineer",
  "region": "Anywhere in the World",
  "country": null,
  "state": "Harjumaa (Tallinn)",
  "category": "Back-End Programming",
  "employmentType": "Full-Time",
  "skills": ["Python and Engineer"],
  "publishedAt": "2026-08-31T15:05:39.000Z",
  "expiresAt": "2026-09-30T15:05:39.000Z",
  "url": "https://weworkremotely.com/remote-jobs/evaboot-agentic-python-engineer",
  "descriptionHtml": "<p>...</p>",
  "descriptionText": "Full job description text...",
  "feedCategories": ["all"],
  "source": "weworkremotely.com",
  "scrapedAt": "2026-08-31T21:20:18.931Z"
}
```

Source records can change or expire after extraction. Treat the canonical URL and source dates as the current source of truth.

### How much does it cost to collect We Work Remotely jobs?

The Actor uses pay-per-event pricing:

- a **$0.005 start fee** per run;
- one **Item extracted** event for each normalized record saved;
- a BRONZE item price of **$0.0008 per job**;
- lower per-job prices on higher subscription tiers.

At BRONZE pricing:

| Useful jobs | Example total |
| ---: | ---: |
| 10 | $0.013 |
| 50 | $0.045 |
| 100 | $0.085 |

A run that finds no matching jobs pays only the start fee. Failed, rejected, duplicate, and filtered records do not receive an Item extracted event charge. Apify Console shows the applicable tier and final charge before and after each run.

### Recurring monitoring workflow

To build a recurring vacancy monitor:

1. Save a tested input as an Apify Task.
2. Schedule it at an interval suitable for your use case.
3. Export each dataset or connect a webhook.
4. Compare `jobId`, `publishedAt`, `expiresAt`, and relevant content in your database.
5. Trigger alerts for IDs not seen in the prior snapshot.
6. Retain your own history if changes over time matter.

The Actor provides stable records for this workflow but does not retain cross-run history or label records as new, changed, or removed.

For an incremental date window, set `publishedAfter` dynamically in the API input. Leave overlap between windows if your downstream system deduplicates by `jobId` and you want resilience to delayed source updates.

### Export and integrations

Apify datasets can be exported as JSON, CSV, Excel, XML, RSS, or JSONL.

Common integrations include:

- Google Sheets for a recruiting watchlist;
- Airtable for candidate-market research;
- Make or Zapier for alerts;
- webhooks for downstream ETL;
- Python or JavaScript clients for scheduled ingestion;
- BigQuery, Snowflake, PostgreSQL, or another warehouse;
- Apify MCP for agent-driven collection.

For repeat runs, consume the dataset through its run-specific URL. Do not depend on local storage paths.

### API usage with cURL

Start a run and wait for its dataset response:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~weworkremotely-full-description-jobs/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "categories": ["all"],
    "keywords": ["engineer"],
    "maxItems": 20
  }'
```

Keep tokens in environment variables or a secret manager. Do not commit them to source control.

### API usage with JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client
  .actor('automation-lab/weworkremotely-full-description-jobs')
  .call({
    categories: ['customer-support'],
    maxItems: 50,
  });

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

Use the returned `defaultDatasetId` so each integration reads the intended run.

### API usage with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

run = client.actor(
    "automation-lab/weworkremotely-full-description-jobs"
).call(run_input={
    "categories": ["all"],
    "regions": ["Anywhere in the World"],
    "maxItems": 100,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["company"], item["title"], item["url"])
```

The Python client can also start asynchronous runs for larger workflows.

### Use with Apify MCP

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/weworkremotely-full-description-jobs"
```

#### Claude Desktop

Add this remote server to Claude Desktop's MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/weworkremotely-full-description-jobs"
    }
  }
}
```

#### Cursor

Add the same JSON under **Cursor Settings → MCP**, then enable the `apify` server.

#### VS Code

Add the same remote MCP URL to your VS Code MCP server configuration and start the `apify` server from the MCP panel.

#### Claude Code

The `claude mcp add` command above installs the same Actor-specific remote server from your terminal.

Example prompts:

- "Collect the latest 20 We Work Remotely jobs mentioning Python."
- "Export current customer support jobs with full descriptions."
- "Find jobs marked Anywhere in the World and summarize the role categories."

MCP executes the same Actor input contract and returns links to run outputs.

### Reliability and retry behavior

The Actor validates status, content type, and recognizable RSS structure.

It retries only transient conditions:

- network resets and timeouts;
- HTTP 408 and 425;
- HTTP 429 rate limiting;
- temporary 5xx source errors.

Each feed receives at most three attempts with exponential backoff and jitter. Invalid input, stable 4xx responses, malformed RSS, and unexpected job hosts fail without blind retries.

When multiple specific categories are selected, the Actor fetches at most three feeds concurrently. It does not rotate proxies or open browsers as a hidden fallback.

### Limitations

- Results cover the jobs currently present in We Work Remotely's public RSS feeds.
- The source controls feed size, freshness, field completeness, and expiration.
- Some RSS records omit company subdivisions, country, state, skills, type, or expiry.
- Company parsing relies on the source's `Company: Title` RSS convention.
- Keyword filtering is literal and case-insensitive; it is not semantic search.
- Region filtering uses the source text and does not infer remote-work eligibility.
- Full descriptions are source-provided content and may contain formatting or outbound links.
- The Actor does not scrape company profiles, salary data not present in the feed, or private application data.
- The Actor does not maintain cross-run state or send alerts by itself.

### Responsible use and legality

This Actor reads publicly accessible RSS feeds and public job records.

You remain responsible for:

- following applicable laws and website terms;
- collecting only data needed for a legitimate purpose;
- respecting intellectual-property rights in job descriptions;
- applying appropriate retention and access controls;
- avoiding discriminatory recruiting or automated decision-making;
- honoring deletion or correction obligations that apply to your system.

Do not republish full descriptions without confirming that your use is permitted. Prefer canonical links and source attribution when displaying records to end users.

### Troubleshooting

**The dataset is empty**

Remove filters one at a time. A future `publishedAfter`, a narrow region, or keywords absent from the current feed can correctly produce zero results.

**My input fails before collection**

Check that `all` is used by itself, `maxItems` is from 1 to 1,000, and `publishedAfter` is a valid ISO 8601 date-time.

**A source request fails**

Review the run log. The Actor already retries temporary network, rate-limit, and server failures. A persistent invalid response is surfaced instead of hidden.

**I see fewer than `maxItems` records**

`maxItems` is an upper bound. The current feed and your filters may contain fewer matching jobs.

**A company is `null` or looks incorrect**

The source sometimes omits the usual `Company: Title` structure. The Actor preserves the remaining title rather than inventing a company.

**Do I need Apify Proxy?**

No. The current official RSS route works anonymously and the Actor does not expose a proxy mode.

### FAQ

**Is this an official We Work Remotely API?**

No. It is an independent Apify Actor built on public We Work Remotely RSS feeds.

**Does it include full job descriptions?**

Yes. Each accepted record includes both `descriptionHtml` and normalized `descriptionText` from the RSS item.

**Can I filter by country?**

Use `regions`. It matches the source's region, country, and state text without inferring eligibility.

**Can I request several categories?**

Yes. Select several specific categories. Duplicate canonical URLs are merged into one result with multiple `feedCategories` values.

**Can I monitor only newly posted jobs?**

Use `publishedAfter` for a time window and compare stable `jobId` values in your downstream store. The Actor does not remember prior runs.

**Can I extract more than the RSS feed contains?**

No. The Actor intentionally represents the current public feed, not historical listings absent from it.

**Are filtered-out jobs charged?**

No. The Job event is charged only for normalized records saved to the dataset.

### Related Automation Lab Actors

- [Built In Job Listings Scraper](https://apify.com/automation-lab/builtin-job-listings-scraper) for a distinct US job-board source.
- [Remote OK Jobs Feed Scraper](https://apify.com/automation-lab/remoteok-remote-jobs-feed) for Remote OK's public structured feed.
- [Remote Jobs Multi-Board Feed](https://apify.com/automation-lab/remote-jobs-multi-board-feed) for a normalized, deduplicated feed from multiple other remote-job sources.

Use this Actor when We Work Remotely coverage and its full RSS descriptions are the required source. Use a multi-board Actor when broader source coverage matters more than source-specific fields.

# Actor input Schema

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

RSS feeds to collect. Use All jobs by itself, or select one or more specific categories.

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

Keep jobs containing any of these case-insensitive phrases in the title, company, region, category, or full description. Enable Match all keywords to require every phrase.

## `matchAllKeywords` (type: `boolean`):

When enabled, a job must contain every keyword. When disabled, any keyword can match.

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

Keep jobs whose region, country, or state contains any supplied phrase, for example Anywhere in the World, USA, or Europe.

## `publishedAfter` (type: `string`):

Optional ISO 8601 date-time. Jobs published before this instant are excluded. Useful for scheduled incremental collection.

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

Maximum number of matching jobs saved to the default dataset, newest first.

## Actor input object example

```json
{
  "categories": [
    "all"
  ],
  "keywords": [],
  "matchAllKeywords": false,
  "regions": [],
  "maxItems": 20
}
```

# Actor output Schema

## `dataset` (type: `string`):

All matching jobs saved by this run.

# 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": [
        "all"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/weworkremotely-full-description-jobs").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": ["all"],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/weworkremotely-full-description-jobs").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": [
    "all"
  ],
  "maxItems": 20
}' |
apify call automation-lab/weworkremotely-full-description-jobs --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/weworkremotely-full-description-jobs"
        }
    }
}

```

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/VwVFl3Xu1veb2H1FC/builds/XCwFRiEc9RKzDhI6E/openapi.json
