# Remote Jobs Scraper & API: Direct From Company Career Sites (`atsfeed/remote-jobs-search`) Actor

Search remote jobs straight from company career sites on Greenhouse, Lever, Ashby, Workable and more. Every job is checked live, and closed jobs are not charged.

- **URL**: https://apify.com/atsfeed/remote-jobs-search.md
- **Developed by:** [Velavalapalli Mohana Durga Sai Ram](https://apify.com/atsfeed) (community)
- **Categories:** Jobs, Automation, Lead generation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 jobs

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

### What does Remote Jobs Scraper do?

Search remote jobs straight from company career sites on Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio and Breezy. About **97,000 open remote jobs** are indexed, about 10,000 of them naming no country. Every job is **checked live at its source during your run**, and **closed jobs are skipped at no charge**.

Use it as a **job postings API** or a jobs scraper: send keywords, places and filters, and get back clean records with pay, skills, seniority, workplace type and visa wording already pulled out. The data is ready for a job board, a recruiting pipeline, an AI agent or a sales list.

### Why use Remote Jobs Scraper?

- **No dead links.** Each job is read from the employer's own applicant tracking system while your run is in progress. If the job has closed, it is dropped and you pay nothing for it.
- **Location search that understands people.** Type `Bangalore` or `Bengaluru`, `UK` or `United Kingdom`, a city, a state or a country code. A city returns jobs in that city, not the whole country.
- **Predictable cost.** You pay per job returned. Set **Maximum jobs** and you know your top cost before the run starts.
- **Daily feeds without repeats.** Turn on **Only jobs not returned before**, schedule the Actor, and each run delivers only the jobs you have not seen.
- **Direct from employers.** Results come from company job boards, not from reposted aggregator listings.
- **Works with your tools.** Run it through the API, on a schedule, with webhooks, or from Zapier, Make, n8n, Google Sheets and AI agents.

#### Who uses job postings data like this?

- **Job boards** that fill a niche with fresh, direct-apply listings for one field or region.
- **Sales teams** looking for buying signals: a company hiring its third SDR or naming Salesforce in a posting is telling you something.
- **AI agents and automations** that search jobs in n8n, Make, Zapier or your own code.
- **Researchers** tracking who is hiring, what they pay and which tools they ask for.

### What data can Remote Jobs Scraper extract?

| Field | Type | Description |
|---|---|---|
| `title`, `company` | text | Job title as the employer wrote it, and the hiring company |
| `location`, `countries` | text, list | Location text and ISO country codes |
| `workplaceType` | text | `remote`, `hybrid`, `onsite` or `unspecified` |
| `salary` | object | Stated pay with `min`, `max`, `currency` and `period` |
| `skills` | list | Tools and technologies named in the description |
| `seniority`, `category` | text | Detected level, such as `senior`, and job family, such as `data_ai` |
| `visaSponsorship` | text | `offered` or `not_offered` when the posting says so |
| `postedDate`, `firstSeenDate` | date | When the job was posted, and when this index first saw it |
| `jobUrl`, `applyUrl`, `careersPageUrl` | link | The posting, the application form and the company's job board |
| `description` | text | Full description, read live during your run |
| `verifiedLive`, `checkedAt` | yes/no, date | Proof that the job was open when you received it |

### How to scrape remote jobs from company career sites

1. Enter **job title keywords**, such as `data engineer` or `"account executive"`.
2. Add **locations** and any other filters, or leave them empty.
3. Set **Maximum jobs** and click **Start**.
4. Download the results, or read them through the API.

#### Example input

```json
{
  "titleKeywords": [
    "software engineer",
    "data engineer"
  ],
  "locations": [
    "Europe"
  ],
  "postedWithinDays": 7,
  "maxResults": 200
}
```

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

You pay per job returned, and higher Apify plans pay less per job. The pricing panel on this page shows the price for your plan. On the Free and Starter plans:

| Jobs returned | Cost |
|---|---|
| 100 | $0.15 |
| 1,000 | $1.50 |
| 10,000 | $15.00 |

Closed jobs and jobs rejected by your description filters are not charged. Platform usage is included, so there is no separate compute bill, and Apify's free plan credit covers your first few thousand jobs each month.

### Input

See the **Input** tab for every option. The ones that matter most:

| Option | What it does |
|---|---|
| Job title keywords | Match any entry. Words in any order, or use double quotes for an exact phrase |
| Exclude title keywords | Skip titles containing these |
| Locations | City, state, country or area such as "Europe", in plain words |
| Only jobs that name no country | Remote jobs whose posting names no country or region |
| Posted within the last N days | 1 for today, 7 for a week, 0 for any date |
| Only these companies | Names, board names or website domains |
| Only these sources | Limit to specific applicant tracking systems |
| Seniority, category, employment type | Structured filters |
| Skills | Tools and technologies named in the description |
| Only jobs that state pay, minimum yearly pay | Pay filters |
| Visa and clearance filters | Based on the wording in the description |
| Description keywords | Checked against the live description. You pay only for jobs that pass |
| Only jobs not returned before | For scheduled runs: delivers only new jobs |

### Output

Download the dataset as JSON, CSV, Excel, XML, RSS or HTML. Each job looks like this:

#### Example output

```json
{
  "id": "greenhouse:acme:5470571008",
  "title": "Senior Data Engineer",
  "company": "Acme",
  "location": "Berlin, Germany",
  "countries": ["DE"],
  "workplaceType": "remote",
  "employmentType": "full_time",
  "seniority": "senior",
  "category": "data_ai",
  "department": "Data",
  "postedDate": "2026-11-04",
  "firstSeenDate": "2026-11-05",
  "salary": { "min": 80000, "max": 100000, "currency": "EUR", "period": "year" },
  "skills": ["python", "snowflake", "dbt", "airflow"],
  "visaSponsorship": "offered",
  "securityClearanceRequired": false,
  "jobUrl": "https://job-boards.greenhouse.io/acme/jobs/5470571008",
  "applyUrl": "https://job-boards.greenhouse.io/acme/jobs/5470571008",
  "careersPageUrl": "https://job-boards.greenhouse.io/acme",
  "source": "greenhouse",
  "verifiedLive": true,
  "checkedAt": "2026-11-05T17:59:14.051Z",
  "description": "About the role..."
}
```

### Tips for faster and cheaper runs

- Set **Posted within the last N days**. Reading one week of jobs is much faster than reading every date.
- Turn off **Include full job description** when you only need the structured fields.
- Put a title in double quotes for an exact phrase, such as `"product manager"`.
- For daily feeds, keep the same filters or set a **History name**, so **Only jobs not returned before** keeps its memory.

### Use Remote Jobs Scraper with the API and AI agents

Start a run and read the results with the Apify API client for Node.js:

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('atsfeed/remote-jobs-search').call({
  titleKeywords: ['data engineer'],
  locations: ['Germany'],
  maxResults: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Or for Python:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("atsfeed/remote-jobs-search").call(run_input={"titleKeywords": ["data engineer"], "maxResults": 100})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

AI agents in Claude, ChatGPT, Cursor or any MCP client can call this Actor as a tool through the Apify MCP server at `mcp.apify.com`. The **API** tab on this page has more examples.

### FAQ

#### Is it legal to scrape job postings from career sites?

This Actor reads public job listings from endpoints that the job board vendors publish for displaying jobs. It does not log in, solve CAPTCHAs or get around access controls, and it does not collect recruiter contact details. Postings belong to the employers who publish them, so follow the rules that apply to how you reuse them, and link back to the original job when you display it.

#### How fresh are the jobs?

The index is rebuilt every day, and each job is checked live at its source while your run is in progress.

#### Why did I get fewer jobs than I asked for?

Closed jobs and duplicates are skipped. Try fewer filters, a longer date window or broader keywords.

#### Can I get only new jobs every day?

Yes. Turn on **Only jobs not returned before** and schedule the Actor. Each run skips the jobs it already delivered to you.

#### Which job sites does it cover?

Public job boards on Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio and Breezy. It does not include LinkedIn, Indeed or other job boards.

### Coverage and accuracy

- **Index size, November 2026:** about 97,000 open remote jobs, about 10,000 of them naming no country.
- A job counts as remote when the employer marks it remote or its location says so. `countries` lists the countries a remote job names. An empty list means the posting names none, which can still mean one country in practice, so check the description.
- Coverage is limited to public job boards of the supported systems and is refreshed daily. It does not include LinkedIn, Indeed or other job boards, or systems not listed above. Run-time summary numbers are saved in the `SUMMARY` record of each run.
- Skills, seniority, category, salary found in text and visa wording come from fixed rules applied to the employer's own words. They are helpful but can be wrong, so check what matters. Visa and clearance values show what a posting says, not legal status.
- Some sources do not state a posting date. In that case the date this index first saw the job is used.
- Skills and visa wording are only available for jobs where the source shared a description when indexed. Filters on those fields skip jobs without them.

### Related Actors

- [Career Site Jobs API](https://apify.com/atsfeed/ats-job-search): open jobs from company career sites on eight applicant tracking systems, in one search.
- [Daily Jobs Feed](https://apify.com/atsfeed/daily-jobs-feed): every new job from company career sites in one scheduled run.
- [Salary Benchmarks](https://apify.com/atsfeed/job-salary-benchmarks): pay ranges for any job title and location.
- [Hiring Signals & Technographics](https://apify.com/atsfeed/hiring-signals-technographics): companies hiring for a role or naming a tool in their postings.
- Job search for a single source: [Greenhouse](https://apify.com/atsfeed/greenhouse-jobs-search), [Lever](https://apify.com/atsfeed/lever-jobs-search), [Ashby](https://apify.com/atsfeed/ashby-jobs-search), [Workable](https://apify.com/atsfeed/workable-jobs-search), [SmartRecruiters](https://apify.com/atsfeed/smartrecruiters-jobs-search).

### Questions

Found a wrong result, or want another source added? Open an issue on the **Issues** tab with an example.

# Actor input Schema

## `titleKeywords` (type: `array`):

A job matches if its title contains any entry. Words in an entry can be in any order: "data engineer" also finds "Engineer, Data". Put an entry in double quotes for an exact phrase. Leave empty for all titles.

## `excludeTitleKeywords` (type: `array`):

Skip jobs whose title contains any of these, for example "intern" or "manager".

## `locations` (type: `array`):

Any city, state, country or two-letter country code, in plain words. Common spellings work: Bangalore and Bengaluru, UK and United Kingdom. Leave empty for worldwide.

## `includeGlobalRemote` (type: `boolean`):

Applies when you set locations. Keeps remote jobs that do not name a country.

## `worldwideOnly` (type: `boolean`):

Keeps remote jobs whose posting names no country or region. Many of these still hire in one country in practice, so check the description.

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

1 returns jobs posted today (UTC), 7 returns the last week. Use 0 for any date. Scanning all dates takes longer.

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

The run stops after this many jobs. You pay per job returned, so this also caps your cost.

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

Company names, career board names or website domains, such as "Stripe" or "stripe.com".

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

Skip jobs from companies whose name contains any of these.

## `ats` (type: `array`):

Limit results to specific applicant tracking systems.

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

Detected from the job title.

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

Detected from the job title and department.

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

Jobs that do not state a type are left out when this is set.

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

Matches tools named in the job description, such as python, snowflake, salesforce or hubspot. Use lowercase. Works on jobs enriched from a full description, which is most but not all jobs.

## `salaryDisclosedOnly` (type: `boolean`):

Keep only jobs with a salary from the employer or found in the description.

## `minAnnualSalary` (type: `integer`):

Compares the top of the stated range, converted to yearly when pay is hourly or monthly. Applies only to jobs in the currency below.

## `salaryCurrency` (type: `string`):

Currency used by the minimum pay filter.

## `visaSponsorshipOnly` (type: `boolean`):

Based on wording in the description. Confirm with the employer.

## `excludeNoVisaSponsorship` (type: `boolean`):

Keeps jobs that say nothing about sponsorship.

## `excludeClearanceRequired` (type: `boolean`):

Skip jobs that mention a required security clearance.

## `includeDescription` (type: `boolean`):

Adds the description as plain text, read live from the source. Turn off for a faster run with only structured fields.

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

Adds the original HTML when the source provides it.

## `descriptionKeywords` (type: `array`):

Checked against each live description. You are charged only for jobs that pass. Slower than title keywords, so pair it with other filters.

## `excludeDescriptionKeywords` (type: `array`):

Skip jobs whose live description contains any of these.

## `verifyLive` (type: `boolean`):

Reads each job from its source before returning it. Closed jobs are skipped at no charge. Always on when descriptions are included.

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

Returns one job when a company lists the same title and location more than once.

## `onlyNewJobs` (type: `boolean`):

For scheduled runs. Remembers delivered jobs in a key-value store in your account and skips them next time. Changing any filter starts a new history, unless you set a history name below.

## `deltaKey` (type: `string`):

Optional name for the "only new jobs" history, so you can change filters and keep it. Example: "sales-jobs-feed".

## Actor input object example

```json
{
  "titleKeywords": [
    "software engineer"
  ],
  "includeGlobalRemote": true,
  "worldwideOnly": false,
  "postedWithinDays": 7,
  "maxResults": 20,
  "salaryDisclosedOnly": false,
  "salaryCurrency": "USD",
  "visaSponsorshipOnly": false,
  "excludeNoVisaSponsorship": false,
  "excludeClearanceRequired": false,
  "includeDescription": true,
  "includeDescriptionHtml": false,
  "verifyLive": true,
  "dedupe": true,
  "onlyNewJobs": false
}
```

# Actor output Schema

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

One item per open job, checked live at its source.

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

How many jobs matched, were returned, or were skipped because they had closed.

# 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 = {
    "titleKeywords": [
        "software engineer"
    ],
    "postedWithinDays": 7,
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("atsfeed/remote-jobs-search").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 = {
    "titleKeywords": ["software engineer"],
    "postedWithinDays": 7,
    "maxResults": 20,
}

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

```

## MCP server setup

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

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/qOIhG56wbWmn18Twt/builds/rSpb7sldfozIg3ZFW/openapi.json
