# Greenhouse, Lever & Ashby Jobs Scraper – Remote & Country (`fluyeporlaweb/ats-jobs-scraper`) Actor

Scrape public job postings from Greenhouse, Lever & Ashby career sites. Filter by keyword, country (ISO) and true remote. Salaries, no login, clean JSON.

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

## Pricing

from $1.00 / 1,000 job postings

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

## Greenhouse, Lever & Ashby Jobs Scraper – Remote & Country

**Greenhouse, Lever & Ashby jobs scraper** that pulls every public job posting from company career sites into clean, unified JSON. Filter by **title keywords**, **country** (ISO code or name) and **true remote** (hybrid is *not* counted as remote). Salaries are included when the ATS publishes them. No login, no cookies, no proxies: only the official public job-board APIs.

### What does it do?

- Takes lists of company board names for **Greenhouse** (`boards.greenhouse.io/<token>`), **Lever** (`jobs.lever.co/<slug>`) and **Ashby** (`jobs.ashbyhq.com/<name>`).
- Downloads all published jobs from each board in a single request.
- Normalizes them to **one schema** across the three ATS, including `country` / `countries` (ISO 3166-1 alpha-2), `workplaceType`, `isRemote` and `salary`.
- Applies your filters and saves the result to the dataset (JSON, CSV, Excel or API).

### Use cases

- **Job boards and niche aggregators**: feed a remote-only or country-specific job board from hundreds of startups.
- **Recruiting and sourcing**: track new openings at target companies every day.
- **Sales intelligence and hiring signals**: companies hiring for "Data Engineer" or "Security" are buying tools; turn openings into leads at the company level.
- **Market and salary research**: compare roles, locations and published salary ranges.
- **Job alerts and AI agents**: schedule the Actor and send new jobs to Slack, email or your LLM pipeline.

### Input

| Field | Type | Description |
|---|---|---|
| `greenhouse` | string\[] | Greenhouse board tokens, e.g. `stripe`, `gitlab`, `airbnb` |
| `lever` | string\[] | Lever company slugs, e.g. `spotify`, `palantir` |
| `ashby` | string\[] | Ashby board names, e.g. `ramp`, `notion`, `openai` |
| `keywords` | string\[] | Keep jobs whose title contains any keyword |
| `remote` | `any` / `true` / `false` | Remote only, exclude remote, or don't care |
| `countries` | string\[] | ISO codes or names: `US`, `GB`, `Germany`… |
| `maxJobsPerCompany` | integer | 0 = no limit |
| `includeDescription` | boolean | Adds plain-text `descriptionText` |

Example input (real):

```json
{
    "greenhouse": [
        "gitlab"
    ],
    "lever": [
        "spotify"
    ],
    "ashby": [
        "ramp"
    ],
    "keywords": [
        "engineer"
    ],
    "remote": "true",
    "countries": [
        "US",
        "Germany"
    ],
    "maxJobsPerCompany": 2,
    "includeDescription": false
}
```

### Output

One item per job. Real output for the input above (first 2 of 5 items, run on 26 Oct 2026):

```json
[
  {
    "source": "greenhouse",
    "company": "GitLab",
    "companyToken": "gitlab",
    "jobId": "8771512002",
    "title": "Backend Engineer, Knowledge Graph (Rust)",
    "location": "Remote, Canada; Remote, United States",
    "country": "US",
    "countries": [
      "US",
      "CA"
    ],
    "department": "Data Engineering",
    "team": null,
    "employmentType": null,
    "workplaceType": "remote",
    "isRemote": true,
    "postedAt": "2026-10-23T18:47:07-04:00",
    "updatedAt": "2026-10-23T18:47:07-04:00",
    "url": "https://job-boards.greenhouse.io/gitlab/jobs/8771512002",
    "applyUrl": "https://job-boards.greenhouse.io/gitlab/jobs/8771512002",
    "salary": null,
    "scrapedAt": "2026-10-26T11:06:59.910830+00:00"
  },
  {
    "source": "ashby",
    "company": "ramp",
    "companyToken": "ramp",
    "jobId": "d1183b00-6590-4fe4-a585-28d84e578fe3",
    "title": "Software Engineer, Security, Stablecoin",
    "location": "New York, NY (HQ)",
    "country": "US",
    "countries": [
      "US"
    ],
    "department": "Engineering",
    "team": "Backend",
    "employmentType": "FullTime",
    "workplaceType": "remote",
    "isRemote": true,
    "postedAt": "2026-05-13T20:28:09.574+00:00",
    "updatedAt": null,
    "url": "https://jobs.ashbyhq.com/ramp/d1183b00-6590-4fe4-a585-28d84e578fe3",
    "applyUrl": "https://jobs.ashbyhq.com/ramp/d1183b00-6590-4fe4-a585-28d84e578fe3/application",
    "salary": "$189K - $330K",
    "scrapedAt": "2026-10-26T11:06:59.668344+00:00"
  }
]
```

Key fields:

- `country`: primary ISO country. When you filter by country and a job lists several, the **country you asked for comes first**.
- `countries`: every country detected for the job.
- `workplaceType`: always lowercase `remote`, `hybrid`, `onsite` or `null`, the same across all three ATS.
- `isRemote`: `true` only for fully remote jobs.

In Apify Console the dataset has three views: **Jobs** (key fields), **Remote & location** and **All fields**. The full field list with examples is in the dataset schema.

### How accurate are the country and remote filters?

Greenhouse only gives free-text locations ("SF, SEA, CHI, NYC, remote", "Remote - Ontario, Canada", "Hybrid"). The Actor parses them with a location parser that handles:

- ISO codes and country names;
- 100+ tech-hub cities;
- US states and Canadian provinces;
- remote patterns ("Remote - US", "Anywhere", "Distributed").

It also reads the board's `offices` and custom `metadata` fields (for example "Workplace Type"). On a hand-labeled sample of 56 real Greenhouse jobs from 8 companies, the previous version returned no country for Greenhouse jobs and its country filter matched only 55% of the true countries (recall). The new parser assigns the correct primary country to 56 of 56 jobs, with 100% precision and 98% recall. Remote accuracy went from 89% to 100%. On a second check with 30 jobs from 6 other companies, the parser was also correct every time; one of those cases is ambiguous. For Ashby, we use `workplaceType` because Ashby's own `isRemote` flag is also true for hybrid roles.

### FAQ

**Do I need an account or API key for Greenhouse, Lever or Ashby?**
No. The Actor uses each ATS's public job-board API, which serves only published jobs and needs no authentication.

**How do I find a company's board name?**
Open its careers page and look at the job URL: `boards.greenhouse.io/**stripe**`, `jobs.lever.co/**spotify**`, `jobs.ashbyhq.com/**ramp**`.

**Is "remote" really remote?**
Yes. `isRemote` is true only for fully remote roles. Hybrid roles get `workplaceType: "hybrid"` and `isRemote: false`.

**Can I filter by region like EMEA or LATAM?**
Region names are matched as text in the location (e.g. "Remote - EMEA"). Country codes are matched against the parsed countries.

**Does it include salaries?**
Yes, when the company publishes them:

- Ashby: compensation summary.
- Lever: `salaryRange`.
- Greenhouse: usually inside the description, so turn on `includeDescription`.

**How fast is it?**
In a local test, 18 companies (about 3,000 jobs) took around 20 seconds. Each board is a single API request.

**Is it polite to the ATS servers?**
Yes. Each board is fetched once per run, with retries and backoff on errors. Ashby requests are spaced at least 1 second apart, as its robots.txt asks (`Crawl-delay: 1`), even when you raise `maxConcurrency`.

**What permissions does the Actor need?**
Limited permissions only. It reads public URLs and writes to its own default dataset and key-value store. It never touches other data in your Apify account.

**What if a company doesn't exist or moved ATS?**
That board is skipped and the error is listed in the `RUN_SUMMARY` key-value record. The run doesn't fail.

**Is it legal?**
It reads only data that the ATS vendors publish openly for job seekers. Lever's docs state published postings "may be scraped by third parties". No personal data is collected. You are responsible for how you use the data, for example GDPR if you contact people.

**Can I schedule it?**
Yes. Use Apify Schedules plus integrations (webhooks, Slack, Google Sheets, Make, Zapier, n8n).

**Can AI agents use it?** Yes. Call it through the Apify API, or from Claude, Cursor or any MCP client via the Apify MCP server.

### Not affiliated

This Actor is not affiliated with, or endorsed by, Greenhouse Software, Lever or Ashby. We use the names only to describe compatibility.

# Actor input Schema

## `greenhouse` (type: `array`):

Board token from boards.greenhouse.io/<token> or job-boards.greenhouse.io/<token>. Example: stripe

## `lever` (type: `array`):

Slug from jobs.lever.co/<slug>. Example: spotify

## `ashby` (type: `array`):

Name from jobs.ashbyhq.com/<name>. Example: ramp

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

Keep only jobs whose title contains at least one keyword (case-insensitive). Empty = all jobs.

## `remote` (type: `string`):

"Remote only" keeps fully remote jobs (hybrid is NOT remote). "Exclude remote" drops them.

## `countries` (type: `array`):

ISO codes or country names, e.g. US, GB, Germany. Matched against parsed job locations. Unknown values (e.g. EMEA) fall back to text match.

## `maxJobsPerCompany` (type: `integer`):

Stop after N matching jobs per company. 0 = no limit.

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

Add the plain-text job description (descriptionText) to each item.

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

Parallel requests to the ATS APIs. Keep it low to be polite.

## Actor input object example

```json
{
  "greenhouse": [
    "stripe"
  ],
  "lever": [
    "spotify"
  ],
  "ashby": [
    "ramp"
  ],
  "keywords": [],
  "remote": "any",
  "countries": [],
  "maxJobsPerCompany": 0,
  "includeDescription": false,
  "maxConcurrency": 5
}
```

# Actor output Schema

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

Job postings in the default dataset (overview view)

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

Item count and per-board errors

# 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 = {
    "greenhouse": [
        "stripe"
    ],
    "lever": [
        "spotify"
    ],
    "ashby": [
        "ramp"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fluyeporlaweb/ats-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 = {
    "greenhouse": ["stripe"],
    "lever": ["spotify"],
    "ashby": ["ramp"],
}

# Run the Actor and wait for it to finish
run = client.actor("fluyeporlaweb/ats-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 '{
  "greenhouse": [
    "stripe"
  ],
  "lever": [
    "spotify"
  ],
  "ashby": [
    "ramp"
  ]
}' |
apify call fluyeporlaweb/ats-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fluyeporlaweb/ats-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/GiFEBDVvVR5spPRZf/builds/GivyTRjIzHQ1MKjTM/openapi.json
