# Remote Jobs API: Remote Jobs from Company Career Sites (`steady-scrape/remote-jobs-api`) Actor

Remote-only jobs straight from employer career sites (Greenhouse, Lever, Ashby, Workday, Workable and more), not job-board reposts. Fully remote vs remote-optional vs hybrid, eligible countries, regions and time zones, seniority, category, dedupe and only-new mode.

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

## Pricing

from $1.50 / 1,000 remote job results

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?

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

## Remote Jobs API: Remote Jobs from Company Career Sites

Get **remote jobs straight from employers' own career sites**, not job-board reposts. One run searches **1.3 million+ open jobs from 37,000+ company career sites** (Greenhouse, Lever, Ashby, Workday, Workable, BambooHR, Recruitee, Personio, Rippling, Teamtailor, Breezy HR, Gem, Oracle Cloud HCM), keeps only the remote ones, and tells you **where you can actually work from**. The index is rebuilt daily from the employers' public job board APIs.

- 🏠 **Real remote classification:** every job is labelled `FULLY_REMOTE`, `REMOTE_OPTIONAL` (remote possible, offices also listed or "remote-friendly") or `HYBRID`, with a confidence level and the evidence behind it
- 🌍 **Eligibility:** worldwide / region / country scope, eligible countries (ISO codes), regions (EMEA, LATAM, APAC…), US states, and stated time zones (e.g. "UTC-3 to UTC+1", "PST hours")
- 🕐 **Filter by where you live:** your countries, regions, or your time zone ± N hours
- 🔎 **Filters:** keywords, exclude keywords, seniority, job category, department, employment type, salary listed, posted within N days, company, ATS
- 🧹 **Dedupe:** the same role posted in 12 "Remote - <state>" locations comes back once, with all locations kept
- 🆕 **Only new since last run:** for daily remote-job alerts, newsletters and job boards
- 📄 **Full descriptions on demand** for Greenhouse, Lever, Ashby and Workday jobs, which also refine the classification ("3 days a week in our office", "must be located in…") and skip closed jobs

### Why this Actor?

Remote job boards are mostly reposts: delayed, duplicated, and vague about *where* "remote" means. Career sites are the source of truth. This Actor reads the employers' own boards, combines the ATS's own remote flag with the location and title text, and outputs one clean record per remote role.

### Quick start

```json
{
  "keywords": ["software engineer", "developer", "devops"],
  "remoteTypes": ["FULLY_REMOTE"],
  "workerCountries": ["US"],
  "postedWithinDays": 14,
  "maxResults": 50
}
```

More examples:

- Europe-friendly data roles within 2 h of Lisbon: `{"keywords": ["data"], "regions": ["Europe"], "workerTimezone": "Europe/Lisbon", "maxTimezoneDiffHours": 2}`
- Senior remote roles open to Canada, with descriptions: `{"workerCountries": ["CA"], "seniority": ["SENIOR", "LEAD"], "includeDescriptions": true}`
- Daily alert: add `"onlyNewSinceLastRun": true` and schedule the Actor

### Output

One item per remote job (overview view shown in the Console). Key fields:

| Field | Example |
|---|---|
| `title`, `company`, `jobUrl`, `applyUrl` | "Senior DevOps Engineer", "Acme Inc" |
| `remoteType` | `FULLY_REMOTE` / `REMOTE_OPTIONAL` / `HYBRID` |
| `remoteConfidence` | `high` (ATS flag and text agree), `medium` (one clear signal), `low` (conflicting) |
| `remoteEvidence` | `["ats:REMOTE", "location:Remote - US"]` |
| `remoteScope` | `WORLDWIDE` / `REGION` / `COUNTRY` / `UNSPECIFIED` |
| `eligibleCountries`, `eligibleRegions`, `eligibleSubdivisions` | `["US","CA"]`, `["North America"]`, `["Ohio"]` |
| `timezones`, `utcOffsetMin`, `utcOffsetMax`, `timezoneSource` | `["US Pacific"]`, -8, -7, `explicit` |
| `remoteLocations`, `officeLocations` | `["Remote - US"]`, `["New York, NY"]` |
| `seniority`, `jobCategory` | `SENIOR`, `Engineering` |
| `salary`, `employmentType`, `department`, `postedAt` | |
| `mergedPostings`, `mergedJobIds` | 3, `["greenhouse:acme:123", …]` |

Plus every field of [Career Site Jobs Search](https://apify.com/steady-scrape/career-jobs-search) (`locations`, `descriptionText`, `source`, …). The run summary (counts by remote type, confidence, scope and platform, and index freshness) is saved as `OUTPUT` in the key-value store.

### How the classification works

1. **ATS flag:** Greenhouse, Lever, Ashby and others mark workplace type (remote / hybrid / on-site) on many postings.
2. **Location text:** "Remote - US", "Anywhere in EMEA", "Brazil (Remote)", "Home Office", "Hybrid - Berlin", multi-location lists mixing offices and remote.
3. **Title text:** "(Remote)", "Work From Home", "Hybrid".
4. **Guards** against false positives: "Remote Sensing", "Remote Pilot", "Remote Patient Monitoring", "temporarily remote", "remote until relocation", corporate "Home Office" addresses.
5. **Optional description pass** (`includeDescriptions`): hybrid schedules, on-site requirements, "must be located in", working-hours time zones.

`UNSPECIFIED` scope means the posting says remote but not where (e.g. a bare "Remote"). These are excluded when you filter by country/region/time zone unless you tick *Include jobs with unspecified eligibility*.

### Pricing

Pay per result: you are charged per job returned. Runs that return nothing (or only record an "only new" baseline) cost only the start fee. Use *Max results* and your run's maximum charge to cap spend.

### FAQ

**Is a FULLY_REMOTE job really open to me?** Check `remoteScope` and `eligibleCountries`. Many US companies say "Remote" but mean the US; when the posting doesn't say, scope is `UNSPECIFIED`.

**How fresh is it?** The index is refreshed daily; `OUTPUT.index.refreshedAt` tells you when. Use `includeDescriptions` to confirm a job is still open.

**Why is a company missing?** Only career sites on the supported ATSs are indexed. For a specific company list, use [ATS Job Feed](https://apify.com/steady-scrape/ats-job-feed).

### More tools from SteadyScrape

- [Career Site Jobs Search](https://apify.com/steady-scrape/career-jobs-search): search open jobs by keyword across tens of thousands of company career sites, with remote, country, company and date filters.
- [ATS Job Scraper](https://apify.com/steady-scrape/ats-job-feed): every open job from the company career sites you list (Greenhouse, Lever, Ashby, Workday and more), with new and removed job tracking.

# Actor input Schema

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

Job title/department keywords or phrases (any match). Leave empty for all remote jobs. Matched as whole words, e.g. 'software engineer', 'devops', 'customer success'.

## `excludeKeywords` (type: `array`):

Skip jobs whose title contains any of these.

## `remoteTypes` (type: `array`):

FULLY_REMOTE = remote job; REMOTE_OPTIONAL = remote possible but the posting also lists offices or says remote-friendly/flexible; HYBRID = some days in an office.

## `minConfidence` (type: `string`):

high = the ATS remote flag and the location text agree; medium = one clear signal (ATS remote flag, or 'Remote' in the location or title); low = conflicting signals (e.g. ATS says on-site but the title says remote).

## `workerCountries` (type: `array`):

Only jobs open to workers in these countries. ISO codes or names (US, GB, Germany, 'EU' for all EU members). Worldwide and matching-region jobs are included.

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

Only jobs open to workers in these regions (e.g. 'EMEA', 'Europe', 'LATAM' postings, or any country inside the region).

## `includeUnspecifiedEligibility` (type: `boolean`):

Many postings just say 'Remote' without saying where. When a country, region or time-zone filter is set, include those too (check the description).

## `workerTimezone` (type: `string`):

Only jobs whose eligible countries/regions/stated hours overlap your time zone. Offset like 'UTC-6', '+5:30', or an IANA zone like 'America/Costa_Rica'.

## `maxTimezoneDiffHours` (type: `integer`):

How far (in hours) the job's time-zone range may be from yours.

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

Only jobs posted (or first seen by us) in the last N days.

## `jobCategories` (type: `array`):

Only these categories (derived from title and department).

## `seniority` (type: `array`):

Only these seniority levels (derived from the title).

## `departments` (type: `array`):

Only jobs whose department contains any of these (as reported by the employer).

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

Only these employment types (when the board states one).

## `salaryOnly` (type: `boolean`):

Only jobs where the posting states a salary.

## `companies` (type: `array`):

Only these companies (name or board slug, partial match).

## `excludeCompanies` (type: `array`):

Skip these companies (e.g. staffing agencies).

## `platforms` (type: `array`):

Only these ATS platforms. Leave empty for all.

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

Maximum jobs to return, newest first.

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

Fetch each job's live description from the career site. Also refines the remote classification with description cues (hybrid schedules, 'must be located in…', working hours) and drops jobs that have closed.

## `dedupe` (type: `boolean`):

Merge the same role posted by the same company in several locations into one result (all locations and job IDs are kept).

## `onlyNewSinceLastRun` (type: `boolean`):

For scheduled runs: return only jobs not returned by an earlier run with the same filters (or the same state key).

## `firstRunEmitsAll` (type: `boolean`):

With 'Only new', the first run returns all current matches. Turn off to just record a baseline (no results, no charge) so later runs only alert on new jobs.

## `stateKey` (type: `string`):

Optional name for the 'only new' memory. Defaults to a hash of the filters.

## `stateStoreName` (type: `string`):

Named key-value store that keeps the 'only new' memory in your account.

## `maxConcurrency` (type: `integer`):

Parallel career-site requests when fetching descriptions.

## Actor input object example

```json
{
  "keywords": [
    "software engineer",
    "developer"
  ],
  "excludeKeywords": [
    "intern",
    "clearance"
  ],
  "remoteTypes": [
    "FULLY_REMOTE",
    "REMOTE_OPTIONAL"
  ],
  "minConfidence": "medium",
  "workerCountries": [
    "US",
    "CA"
  ],
  "includeUnspecifiedEligibility": false,
  "workerTimezone": "UTC-5",
  "maxTimezoneDiffHours": 3,
  "postedWithinDays": 14,
  "salaryOnly": false,
  "maxResults": 50,
  "includeDescriptions": false,
  "dedupe": true,
  "onlyNewSinceLastRun": false,
  "firstRunEmitsAll": true,
  "stateStoreName": "remote-jobs-api-state",
  "maxConcurrency": 8
}
```

# Actor output Schema

## `jobs` (type: `string`):

Dataset of remote jobs, one item per (deduplicated) job. Use /items without ?view for all fields.

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

Run summary JSON: counts by remote type, confidence, scope and platform, plus index freshness.

# 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 = {
    "keywords": [
        "software engineer",
        "developer"
    ],
    "postedWithinDays": 14,
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("steady-scrape/remote-jobs-api").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 = {
    "keywords": [
        "software engineer",
        "developer",
    ],
    "postedWithinDays": 14,
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("steady-scrape/remote-jobs-api").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 '{
  "keywords": [
    "software engineer",
    "developer"
  ],
  "postedWithinDays": 14,
  "maxResults": 50
}' |
apify call steady-scrape/remote-jobs-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steady-scrape/remote-jobs-api"
        }
    }
}
```

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/FMxJvYOnx77IBeSo8/builds/lG3MEyoqNb3dusQZ2/openapi.json
