# Remotive Remote Jobs Scraper (`devilscrapes/remotive-remote-jobs-scraper`) Actor

Pull the full Remotive remote-jobs feed in one call and filter it by category, keyword search, company name, or job type. Returns typed rows — title, company, category, tags, job type, location, salary, plain-text description, posted date.

- **URL**: https://apify.com/devilscrapes/remotive-remote-jobs-scraper.md
- **Developed by:** [DevilScrapes](https://apify.com/devilscrapes) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

<div align="center">
  <img src=".actor/icon.svg" width="160" alt="Devil Scrapes mark" />

## Remotive Remote Jobs Scraper

**$1.70 / 1 000 results**  ·  pay only for results  ·  no credit card to try

*We do the dirty work so your dataset stays clean.* 😈

Pull Remotive's entire live remote-jobs feed in one call and filter it by category, keyword search, company name, or job type. Returns typed rows — title, company, category, tags, job type, location, salary, plain-text description, posted date. Export straight to JSON, CSV, or Excel.

</div>

***

### 🎯 What this scrapes

Remotive (remotive.com) publishes its entire current remote-jobs feed as a
single public JSON object at `https://remotive.com/api/remote-jobs`. This
Actor fetches that feed once per run and filters it **client-side** by
category, search keywords, company name, and/or job type, cleans every HTML
job description down to plain text, and lands one typed dataset row per
matching job — no pagination, no login, no per-job page visits required.

Remotive's own documented `category`/`search`/`company_name`/`limit` query
parameters are supposed to filter server-side, but a live probe on
2026-09-10 showed they currently don't: eight different parameter
combinations against the live endpoint all returned the identical payload.
This Actor never depends on that working — every filter runs in Python
against the full fetched feed, so your results are correct today and stay
correct if Remotive ever fixes the bug.

### 🔥 Features

- 🛡️ **We rotate browser fingerprints** — `curl-cffi` impersonation replays real Chrome / Firefox TLS handshakes, with an explicit identifying `User-Agent` on top, on every request.
- 🔁 **We retry with exponential backoff** on `408 / 429 / 5xx` — up to 5 attempts, honouring `Retry-After` whenever the target sends it.
- 🧱 **We fail loud, not silent** — a broken upstream feed surfaces as a failed run with a clear status message, never a quiet empty dataset. A narrow filter that legitimately matches nothing still succeeds, with a status message naming exactly what was searched.
- 🧊 **We keep the dataset clean** — Pydantic-validated typed rows, HTML descriptions stripped to plain text, salary/logo/location fields null-normalized instead of guessed. One malformed record in the feed is skipped with a warning, never crashes the run.
- 🔍 **We don't trust the server's own filters** — category, search, company, and job-type filtering all run client-side against the full feed, so results are correct even on days the upstream filter is a no-op.
- 💰 **You pay only for results that land** — Pay-Per-Event pricing. No data, no charge.

### 💡 Use cases

- Recruiter tooling — pull today's remote-friendly openings for a given category or tech stack.
- Job-board aggregators — mirror Remotive's feed into your own listings alongside the rest of the Devil Scrapes job-board fleet.
- SDR / lead-gen — find companies actively hiring for roles that signal budget or growth.
- Market research — track which categories and job types are trending in remote postings over time.

### ⚙️ How to use it

1. Click **Try for free** at the top of the page.
2. Optionally set `categories`, `search`, `company_name`, or `job_types` to narrow the feed — leave everything blank to pull the whole current feed (capped by `maxItems`).
3. Click **Start**. Output streams into the run's dataset.
4. Export from **Storage → Dataset** as JSON, CSV, or Excel — or fetch via the API.

#### Call it from Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")

run = client.actor("DevilScrapes/remotive-remote-jobs-scraper").call(
    run_input={
        "categories": ["Information Technology", "Customer Service"],
        "search": [],
        "company_name": "",
        "job_types": [],
        "maxItems": 100,
        "proxyConfiguration": {"useApifyProxy": False},
    }
)

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

### 📥 Input

| Field | Type | Required | Default | Notes |
|---|---|:--:|---|---|
| `categories` | `array` | no | `[]` | Keep jobs whose category matches ANY of these (case-insensitive, name-or-slug — e.g. `"Software Development"` or `"software-development"` both work). |
| `search` | `array` | no | `[]` | Keep jobs whose title or description contains ANY keyword (case-insensitive substring). |
| `company_name` | `string` | no | `""` | Case-insensitive substring match on company name. |
| `job_types` | `array` | no | `[]` | One or more of `full_time` / `part_time` / `contract` / `freelance` / `internship`. |
| `maxItems` | `integer` | no | `100` | Cap on rows emitted, applied after filtering (1-1000). |
| `proxyConfiguration` | `object` | no | `{"useApifyProxy": false}` | Standard Apify Proxy config — optional for this public feed. |

#### Example input

```json
{
  "categories": ["Information Technology", "Customer Service"],
  "search": [],
  "company_name": "",
  "job_types": [],
  "maxItems": 100,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

### 📤 Output

Every row is one dataset item.

| Field | Type | Notes |
|---|---|---|
| `job_id` | `string` | Remotive job ID, stringified. |
| `title` | `string` | Job title. |
| `company_name` | `string` | Hiring company name. |
| `company_logo` | `string \| null` | Logo URL; `null` when Remotive reports an empty value. |
| `category` | `string` | Remotive category (human-readable name). |
| `tags` | `array` | Tags/skills attached to the posting. |
| `job_type` | `string \| null` | Employment type; `null` when empty/missing. |
| `candidate_required_location` | `string \| null` | Free-text location requirement; `null` when empty. |
| `salary` | `string \| null` | Free-text salary, unparsed; `null` when empty. |
| `description` | `string` | HTML stripped to clean plain text. |
| `publication_date` | `string` | Naive ISO-8601 timestamp, passed through from the API. |
| `url` | `string` | Remotive job page URL. |

#### Example output

```json
{
  "job_id": "2091045",
  "title": "Tier III Service Desk Engineer",
  "company_name": "Unio Digital",
  "company_logo": "https://remotive.com/job/2091045/logo",
  "category": "Information Technology",
  "tags": ["azure", "cisco", "security", "helpdesk", "MSP", "ticketing"],
  "job_type": "full_time",
  "candidate_required_location": "Worldwide",
  "salary": null,
  "description": "Unio Digital is an Arizona-based managed service provider...",
  "publication_date": "2026-09-07T01:10:43",
  "url": "https://remotive.com/remote-jobs/information-technology/tier-iii-service-desk-engineer-2091045"
}
```

### 💰 Pricing

Pay-Per-Event — you pay only when these events fire:

| Event | USD | What it is |
|---|---:|---|
| `actor-start` | $0.20 | One-off warm-up charge per run |
| `result` | $0.0015 | Per dataset item (→ $1.50 / 1 000 results) |

Example: 1,000 results at the rates above ≈ **$1.50**. No subscription, no minimum, no card to start — Apify gives every new account $5 of free credit.

### 🚧 Limitations

Remotive's public feed exposes its *current* live listings only — there's
no historical archive and no working pagination cursor, so this Actor
returns a single snapshot per run. All filtering happens client-side
against that one snapshot; the Actor never depends on the server's own
`category`/`search`/`company_name` parameters actually filtering anything,
since a live probe on 2026-09-10 found they currently don't. Salary is
Remotive's own free-text field (e.g. `"$50-$75 /hour"`, `"$20k -$35k"`) —
we pass it through as a string rather than parsing it into a number.

### ❓ FAQ

**Is this legal?**

We only fetch content the source makes publicly available via its own
documented feed. Respect Remotive's terms of service before using output
commercially.

**Why do `categories` filters accept both a name and a slug?**

Remotive's own category taxonomy uses both forms interchangeably
(`"Software Development"` in the feed, `"software-development"` in the
docs). This Actor normalizes both sides before comparing, so either form
works.

**Why is `salary` null on most rows?**

Remotive's feed itself only populates that field on a minority of
postings — we pass through exactly what the source reports, as `null`
when it's missing, rather than inventing a number.

**What happens if my filters match nothing?**

The run still succeeds, with zero rows and a status message naming the
filters that were applied — a narrow filter combination is a legitimate
outcome, not an error.

### 💬 Your feedback

Spotted a bug, hit a weird edge case, or need a new field? Open an
issue on the Actor's **Issues** tab on Apify Console — we ship fixes
weekly and we read every report.

***

<div align="center">

Built by **[Devil Scrapes](https://apify.com/DevilScrapes)** 😈 — a small fleet of
opinionated public-data Actors. Honest pricing, real engineering, zero fine print.

</div>

# Actor input Schema

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

Keep jobs whose category matches ANY of these (case-insensitive, matches either the human name like "Software Development" or the slug like "software-development"). Leave empty to skip this filter.

## `search` (type: `array`):

Keep jobs whose title or description contains ANY of these keywords (case-insensitive substring match). Leave empty to skip this filter.

## `company_name` (type: `string`):

Keep jobs whose company name contains this text (case-insensitive substring match). Leave blank to skip this filter.

## `job_types` (type: `array`):

Keep jobs whose job type is in this list. Leave empty to skip this filter.

## `max_items` (type: `integer`):

Cap the number of rows emitted, applied after all filters.

## `proxyConfiguration` (type: `object`):

Apify Proxy configuration. Optional for this Actor — enable it if you want every request routed through Apify Proxy for IP diversity or compliance reasons.

## Actor input object example

```json
{
  "categories": [
    "Information Technology",
    "Customer Service"
  ],
  "search": [],
  "company_name": "",
  "job_types": [],
  "max_items": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

All dataset items as JSON.

## `datasetItemsCsv` (type: `string`):

Same data exported to CSV.

## `datasetView` (type: `string`):

Open the run dataset in the Console.

# 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": [
        "Information Technology",
        "Customer Service"
    ],
    "search": [],
    "job_types": [],
    "max_items": 100,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("devilscrapes/remotive-remote-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 = {
    "categories": [
        "Information Technology",
        "Customer Service",
    ],
    "search": [],
    "job_types": [],
    "max_items": 100,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("devilscrapes/remotive-remote-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 '{
  "categories": [
    "Information Technology",
    "Customer Service"
  ],
  "search": [],
  "job_types": [],
  "max_items": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call devilscrapes/remotive-remote-jobs-scraper --silent --output-dataset

```

## MCP server setup

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