# Greenhouse, Lever & Ashby Jobs Scraper (`govdata-tools-us/ats-jobs-monitor`) Actor

Scrape and monitor job postings from Greenhouse, Lever and Ashby job boards via their official public APIs. Filter by keyword, location, remote, department and date. Salary, apply URL and description. First 25 results per run free.

- **URL**: https://apify.com/govdata-tools-us/ats-jobs-monitor.md
- **Developed by:** [GovData Tools](https://apify.com/govdata-tools-us) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.50 / 1,000 job records

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 (ATS Jobs Monitor)

> **First 25 results of every run are free.** You pay only for jobs beyond the first 25 in a run.

**Scrape and monitor job postings from any company that hires through Greenhouse, Lever or Ashby. One normalized dataset, many companies.** Give it a list of companies (e.g. `greenhouse:stripe`, `https://jobs.lever.co/palantir`, `https://jobs.ashbyhq.com/linear`). It returns every open role with title, department, team, location, remote flag, employment type, salary range (when the company publishes it), post date, apply link and, optionally, the full job description.

It reads only the **official, public job board APIs** that Greenhouse, Lever and Ashby provide so companies can show jobs on their own careers sites. No login, no cookies, no proxies, no browser automation, so runs are fast, cheap and reliable.

### What can you do with this ATS job scraper?

- **Recruiting & sourcing.** Track new openings at target companies every day and see which teams are hiring.
- **Sales lead generation.** Hiring signals are buying signals. A company hiring "Data Engineer" or "RevOps Manager" may need your product. Feed new postings into your CRM or Slack.
- **Job aggregators & niche job boards.** Build a remote-only, region-specific or role-specific board from hundreds of company boards with one normalized schema.
- **Market & competitive research.** Measure hiring velocity, department mix, locations and published salary ranges across competitors or a whole industry.
- **Job seekers.** Get a daily list of new roles at your dream companies that match your keywords.

### Features

- ✅ **3 major ATS platforms**: Greenhouse, Lever and Ashby. Mix them freely in a single run.
- ✅ **Paste URLs or slugs.** The platform is auto-detected from board URLs (`boards.greenhouse.io/…`, `job-boards.greenhouse.io/…`, `jobs.lever.co/…`, `jobs.eu.lever.co/…`, `jobs.ashbyhq.com/…`).
- ✅ **Filters**: title keywords (include/exclude), location, remote-only, department/team, and posted since (`1 day`, `7 days`, `24 hours`, `2026-10-01`).
- ✅ **Monitoring mode** (`onlyNew`). Remembers jobs it has already returned and outputs only new ones. Schedule it daily and get just the fresh postings.
- ✅ **Salary data** from Ashby and Lever when the employer publishes it (min, max, currency, interval, summary).
- ✅ **Deduplicated and fault tolerant.** A wrong slug or an unavailable board is logged as a warning and skipped. The rest of the run continues.
- ✅ **Budget aware.** Stops automatically when your maximum charge per run is reached.

### Input

| Field | Description |
|---|---|
| `companies` (required) | List of `platform:slug` entries or board URLs. |
| `keywords` | Keep jobs whose title contains any of these words (case-insensitive). |
| `excludeKeywords` | Drop jobs whose title contains any of these. |
| `locations` | Keep jobs whose location (or any secondary location) contains any of these. |
| `remoteOnly` | Keep only remote jobs. |
| `departments` | Keep jobs whose department or team contains any of these. |
| `postedSince` | `1 day`, `7 days`, `48 hours` or `YYYY-MM-DD`. Empty means no date filter. |
| `onlyNew` / `stateStoreName` | Monitoring mode. Output only jobs not seen in previous runs. |
| `includeDescription` | Add the full plain-text description. |
| `maxItems` | Maximum number of jobs to return (default 1000). |

#### Example: new engineering jobs from the last day (daily monitor)

```json
{
  "companies": ["greenhouse:stripe", "greenhouse:airbnb", "lever:palantir", "ashby:linear", "ashby:notion"],
  "keywords": ["engineer", "developer"],
  "postedSince": "1 day",
  "onlyNew": true,
  "maxItems": 500
}
```

#### Example: remote sales roles in the US, using board URLs

```json
{
  "companies": ["https://boards.greenhouse.io/airbnb", "https://jobs.lever.co/palantir", "https://jobs.ashbyhq.com/openai"],
  "departments": ["sales", "go to market"],
  "locations": ["United States", "US"],
  "remoteOnly": true,
  "includeDescription": true
}
```

**How to find a company's slug:** open their careers page and click a job. If the URL looks like `boards.greenhouse.io/<slug>`, `jobs.lever.co/<slug>` or `jobs.ashbyhq.com/<slug>`, paste it as is. Some companies host their careers page on their own domain. For those, look for `gh_jid=` (Greenhouse), `lever.co` or `ashbyhq.com` links in the apply button.

### Output

One record per job:

```json
{
  "source": "ashby",
  "company": "ashby",
  "companyName": "ashby",
  "jobId": "7458d4e9-da2e-47bd-98cb-adfda43d42b2",
  "title": "Engineering Manager - EU",
  "department": "Engineering",
  "team": "EMEA Engineering",
  "location": "Remote - European Union",
  "allLocations": ["Remote - European Union", "Spain", "Italy", "Germany"],
  "remote": true,
  "workplaceType": "Remote",
  "employmentType": "FullTime",
  "compensation": {"min": 150000, "max": 250000, "currency": "EUR", "interval": "1 YEAR", "summary": "€150K – €250K • Offers Equity • Offers Bonus"},
  "postedAt": "2024-03-04T14:29:08.532000Z",
  "updatedAt": null,
  "applyUrl": "https://jobs.ashbyhq.com/ashby/7458d4e9-da2e-47bd-98cb-adfda43d42b2/application",
  "jobUrl": "https://jobs.ashbyhq.com/ashby/7458d4e9-da2e-47bd-98cb-adfda43d42b2",
  "descriptionText": "Hi 👋 I'm Colin, Director of Engineering, Europe. …",
  "id": "ashby:ashby:7458d4e9-da2e-47bd-98cb-adfda43d42b2",
  "scrapedAt": "2026-10-28T17:00:00Z"
}
```

`id` is a stable unique key (`source:company:jobId`), so you can use it for dedupe and upserts in your own database. A run summary with per-company counts and any errors is saved to the key-value store record `OUTPUT`.

You can download the results as JSON, CSV, Excel or HTML, or send them anywhere with Apify integrations (Google Sheets, Slack, Zapier, Make, webhooks, API).

### Pricing

**Pay per result: $1.50 per 1,000 jobs** ($0.0015 per job record). There's no start fee and no monthly subscription. **The first 25 results of every run are free** (no charge events for them). You pay only for the jobs returned after your filters are applied. Set a maximum charge per run and the Actor stops when it is reached. Use filters and `onlyNew` to pay only for the jobs you actually want.

### FAQ

**Is this legal? Does it bypass anything?**
It only uses the official public job board endpoints that Greenhouse (`boards-api.greenhouse.io`), Lever (`api.lever.co/v0/postings`) and Ashby (`api.ashbyhq.com/posting-api`) publish so job listings can be embedded on careers sites. No authentication, scraping evasion or private data is involved. The data is the same as what anyone sees on the public careers page.

**Why are some fields empty?**
Each ATS exposes different data. Greenhouse's public API has no salary or employment-type fields. Lever has no "updated" date. Salary is included only when the employer chooses to publish it.

**How does "Posted since" work?**
It uses Greenhouse's *first published* date, Lever's *created* date and Ashby's *published* date. If a job has no post date, the updated date is used.

**How do I get only new jobs every day?**
Turn on `onlyNew` and schedule the Actor (for example, daily). Use a different `stateStoreName` for each separate monitor.

**A company returns an error.**
The slug is probably wrong or the company moved to another ATS. Check the run log or the `OUTPUT` record. The other companies are still processed.

**Can you add Workday, SmartRecruiters, Workable…?**
Open an issue on the Actor's Issues tab and tell us which platforms you need.

# Actor input Schema

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

One per line: 'platform:slug' (greenhouse:stripe, lever:palantir, ashby:linear) or a job board URL (https://boards.greenhouse.io/airbnb, https://jobs.lever.co/palantir, https://jobs.ashbyhq.com/notion). Platform is auto-detected from URLs.

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

Keep jobs whose title contains ANY of these (case-insensitive). Empty = all.

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

Drop jobs whose title contains any of these (e.g. 'intern', 'senior').

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

Keep jobs whose location contains ANY of these (e.g. 'New York', 'London', 'United States').

## `remoteOnly` (type: `boolean`):

Keep only jobs marked or labeled remote.

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

Keep jobs whose department or team contains ANY of these (e.g. 'Engineering', 'Sales').

## `postedSince` (type: `string`):

Only jobs posted (or, if no post date, updated) on/after this. '1 day', '7 days', '24 hours' or 'YYYY-MM-DD'. Empty = no date filter. Note: Lever exposes creation date only; Greenhouse 'first published'.

## `onlyNew` (type: `boolean`):

Remember job IDs across runs (named key-value store) and output only jobs not seen before. Ideal for scheduled daily runs.

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

Named key-value store used by 'Only new'. Use different names for separate monitors.

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

Add the full plain-text job description (larger output).

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

Stop after this many jobs (across all companies). You are charged per job returned.

## Actor input object example

```json
{
  "companies": [
    "greenhouse:stripe",
    "lever:palantir",
    "ashby:linear"
  ],
  "keywords": [],
  "remoteOnly": false,
  "onlyNew": false,
  "stateStoreName": "ats-jobs-seen",
  "includeDescription": false,
  "maxItems": 1000
}
```

# Actor output Schema

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

All matched job postings from the default dataset.

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

Per-company counts and 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 = {
    "companies": [
        "greenhouse:stripe",
        "lever:palantir",
        "ashby:linear"
    ],
    "keywords": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("govdata-tools-us/ats-jobs-monitor").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 = {
    "companies": [
        "greenhouse:stripe",
        "lever:palantir",
        "ashby:linear",
    ],
    "keywords": [],
}

# Run the Actor and wait for it to finish
run = client.actor("govdata-tools-us/ats-jobs-monitor").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 '{
  "companies": [
    "greenhouse:stripe",
    "lever:palantir",
    "ashby:linear"
  ],
  "keywords": []
}' |
apify call govdata-tools-us/ats-jobs-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,govdata-tools-us/ats-jobs-monitor"
        }
    }
}
```

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/gn6LPlRi091BgR5Dp/builds/39hHMNochjkGoXmlz/openapi.json
