# ATS Jobs Monitor: Greenhouse, Lever, Ashby & more (`thesamirux/ats-jobs-monitor`) Actor

Get every open job from Greenhouse, Lever, Ashby, SmartRecruiters, Recruitee and Workable boards in one format. Paste names or URLs, the ATS is detected automatically. Schedule it to get only new or closed jobs.

- **URL**: https://apify.com/thesamirux/ats-jobs-monitor.md
- **Developed by:** [Mateo Cao](https://apify.com/thesamirux) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 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

### What does ATS Jobs Monitor do?

**ATS Jobs Monitor** collects every open job from company career boards hosted on **[Greenhouse](https://www.greenhouse.com), [Lever](https://www.lever.co), [Ashby](https://www.ashbyhq.com), [SmartRecruiters](https://www.smartrecruiters.com), [Recruitee](https://recruitee.com) and [Workable](https://www.workable.com)**, and returns them in **one normalized format**. It works as a **job postings API** for any company that uses one of these applicant tracking systems: paste company names or careers page URLs and the Actor **detects the ATS automatically**.

Run it on a **schedule** and it becomes a **hiring monitor**: it remembers what it saw last time and outputs only the **new jobs** and, optionally, the jobs that were **closed**.

It reads the official public job board APIs the companies themselves publish. No login, no cookies, no proxies, no browser, so runs are fast and cheap.

### Why use ATS Jobs Monitor?

- 🎯 **Sales and lead generation**: hiring is a buying signal. Track target accounts and react when they open roles in your space.
- 🧑‍💼 **Recruiting and job boards**: aggregate fresh postings from hundreds of employers into one feed.
- 📈 **Market and competitor research**: see which teams competitors grow or freeze, and where they hire.
- 💸 **Salary benchmarks**: structured pay ranges where the ATS publishes them (Lever, Ashby, Recruitee).
- 🤖 **AI agents**: callable as a tool through the Apify API and MCP server, with clean JSON output.

Features:

- **6 ATS in one Actor**, the same output columns for all of them.
- **Auto-detection**: give a company name, a board URL or the company's own careers page.
- **Monitoring mode** with per-watchlist state (`monitorId`): new jobs only, plus closed jobs.
- **Filters**: title keywords (include and exclude), location, department, remote only, posted within N days.
- **Fair billing**: companies that cannot be found or read are never charged.
- Everything the Apify platform adds: scheduling, API access, webhooks, integrations with Google Sheets, Slack, Zapier and Make.

### What data can ATS Jobs Monitor extract?

| Field | Description |
|---|---|
| `title` | Job title |
| `companyName` / `companySlug` | Company and its board identifier |
| `ats` | greenhouse, lever, ashby, smartrecruiters, recruitee or workable |
| `department` / `team` | Department and team or function |
| `location` / `locations` / `country` | Primary location, all locations, country |
| `workplaceType` / `isRemote` | remote, hybrid or onsite |
| `employmentType` | full_time, part_time, contract, internship, temporary |
| `postedAt` / `updatedAt` | Publish and update dates (ISO 8601, UTC) when available |
| `salaryMin` / `salaryMax` / `salaryCurrency` / `salaryInterval` | Published pay range |
| `url` / `applyUrl` | Job page and application link |
| `status` / `isNew` / `firstSeenAt` / `closedAt` | Monitoring fields |
| `descriptionText` / `descriptionHtml` | Full description (optional) |

### How to scrape Greenhouse, Lever and Ashby jobs

1. Click **Try for free**.
2. In **Companies**, add one company per line: a board URL like `https://boards.greenhouse.io/stripe`, a careers page like `https://www.example.com/careers`, an explicit pair like `lever:palantir`, or just a name like `Notion`.
3. Optionally set filters, for example title keywords `data, analytics` and location `remote`.
4. Click **Start** and download the results as JSON, CSV, Excel or HTML, or read them through the API.

#### How to monitor new job postings every day

1. Set **Output mode** to **New jobs only** and turn on **Report closed jobs** if you want them.
2. Give the watchlist a **Monitor ID**, for example `fintech-latam`.
3. Save the task and add a daily **Schedule**. Connect a Slack, email or Google Sheets integration to get each day's new jobs delivered.

The first run outputs all current jobs (or none, if you enable **Skip existing jobs on the first run**); every later run outputs only what changed.

### How much does it cost to scrape job postings?

The Actor uses **pay-per-event** pricing, and platform usage is included:

- **$0.90 per 1,000 job postings** delivered.
- **$0.002 per company** board fetched successfully. Companies that are not found or fail are free.

Examples:

- One-off export of 20 companies with 1,500 open jobs: 20 × $0.002 + 1,500 × $0.0009 ≈ **$1.39**.
- Daily monitor of 50 companies, new jobs only, about 40 new jobs a day: (50 × $0.002 + 40 × $0.0009) × 30 ≈ **$4.08 per month**.

Apify's free plan includes monthly credit, enough to try the Actor on real companies.

### Input

See the **Input** tab for every option. Input lines are interpreted like this:

- **Board URL** (`jobs.lever.co/…`, `boards.greenhouse.io/…`, `jobs.ashbyhq.com/…`, `apply.workable.com/…`, `*.recruitee.com`, `jobs.smartrecruiters.com/…`): used directly.
- **Careers page URL** of the company's own site: the page is scanned for an embedded ATS board.
- **`ats:slug`**: forces one ATS. Use `lever-eu:slug` for Lever's EU instance (also detected automatically).
- **Plain name**: every ATS is probed with slugs derived from the name, and the board with the most open jobs wins. Use the **ATS for plain company names** option to restrict probing to one ATS.

### Output

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel. Example items:

```json
[
  {
    "id": "greenhouse:examplecorp:4012345008",
    "status": "active",
    "isNew": true,
    "ats": "greenhouse",
    "companyName": "Example Corp",
    "title": "Senior Data Engineer",
    "department": "Engineering",
    "location": "Remote - Americas",
    "workplaceType": "remote",
    "employmentType": null,
    "url": "https://boards.greenhouse.io/examplecorp/jobs/4012345008",
    "postedAt": "2026-10-01T14:30:00Z",
    "salaryMin": null,
    "firstSeenAt": "2026-10-18T06:00:00Z"
  },
  {
    "id": "lever:examplecorp:5ac21346-8e0c-4494-8e7a-3eb92ff77902",
    "status": "active",
    "isNew": false,
    "ats": "lever",
    "title": "Backend Engineer (Go)",
    "team": "Payments",
    "location": "London",
    "locations": ["London", "Remote - UK"],
    "workplaceType": "hybrid",
    "employmentType": "full_time",
    "salaryMin": 80000,
    "salaryMax": 100000,
    "salaryCurrency": "GBP",
    "salaryInterval": "year"
  }
]
```

A **SUMMARY** record in the run's key-value store lists every input company with its status (`ok`, `not_found`, `error`, `duplicate`, `skipped`), the detected ATS and slug, and the counts of jobs found, new and closed.

### Tips

- Prefer board URLs or `ats:slug` pairs over plain names: they skip probing, so runs are faster.
- Leave **Include job descriptions** off unless you need them; items are much smaller without them.
- Use separate **Monitor IDs** for unrelated watchlists so their new and closed jobs don't mix.
- Filters only change the output. New and closed tracking always covers the whole board, so you can change filters at any time.

### FAQ

#### Which applicant tracking systems are supported?

Greenhouse, Lever (global and EU), Ashby, SmartRecruiters, Recruitee and Workable. Workday, iCIMS and Taleo are not supported yet.

#### Why was a company not found?

The company may use an unsupported ATS, or its board slug differs from its name. Paste the URL of its careers page or of one of its job posts instead; the SUMMARY record shows what was tried.

#### Can I use it through the API or from an AI agent?

Yes. Every Actor on Apify has a REST API (see the **API** tab) and can be called as a tool from the Apify MCP server.

#### Is it legal to collect job postings?

The Actor reads job board APIs that companies publish for the purpose of distributing their job ads. Our Actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our Actors, when used for ethical purposes by Apify users, are safe. However, you should be aware that your results could contain personal data, for example a recruiter's name inside a job description. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

#### I found a bug or need another ATS

Open an issue in the **Issues** tab with the company or board URL. Requests for new ATS with a public job board API are welcome.

# Actor input Schema

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

One company per line. Accepts a job board URL (boards.greenhouse.io/stripe, jobs.lever.co/palantir, jobs.ashbyhq.com/openai...), a company careers page URL (the ATS embedded in the page is detected), an explicit pair such as lever:palantir or lever-eu:company, or just a company name (every supported ATS is probed).

## `ats` (type: `string`):

Which ATS to query for entries that are plain company names. Auto probes all of them and keeps the board with the most open jobs. URLs and ats:slug pairs always use their own ATS.

## `mode` (type: `string`):

All: every open job, each flagged with isNew. New only: just the jobs that appeared since the previous run of this monitor, ideal for a daily schedule.

## `emitClosed` (type: `boolean`):

Also output jobs that were open in the previous run and are no longer listed (status "closed"). A useful hiring-freeze signal.

## `skipExistingOnFirstRun` (type: `boolean`):

In New only mode, the first run of a monitor normally outputs every open job. Enable this to only record a baseline on the first run and output nothing until new jobs appear.

## `monitorId` (type: `string`):

Name of the saved state. Use a different ID for each independent watchlist so their new and closed jobs are tracked separately.

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

Keep only jobs whose title contains at least one of these keywords (case-insensitive). Leave empty to keep all.

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

Drop jobs whose title contains any of these keywords, for example senior or intern.

## `locationKeywords` (type: `array`):

Keep only jobs whose location, country code or workplace type contains one of these keywords, for example Berlin, US or remote.

## `departmentKeywords` (type: `array`):

Keep only jobs whose department or team contains one of these keywords, for example engineering.

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

Keep only jobs marked as remote by the ATS (or with remote in the location, for Greenhouse).

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

Keep only jobs published in the last N days. 0 disables the filter. Jobs whose ATS does not expose a publish date are kept.

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

Add the full description as plain text and HTML. Makes items much larger and needs one extra request per job on SmartRecruiters.

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

Cap on active jobs output per company in one run. 0 means no limit.

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

Maximum number of parallel requests to the ATS APIs.

## Actor input object example

```json
{
  "companies": [
    "https://boards.greenhouse.io/stripe",
    "lever:palantir",
    "Notion"
  ],
  "ats": "auto",
  "mode": "all",
  "emitClosed": false,
  "skipExistingOnFirstRun": false,
  "monitorId": "default",
  "titleKeywords": [],
  "excludeTitleKeywords": [],
  "locationKeywords": [],
  "departmentKeywords": [],
  "remoteOnly": false,
  "postedWithinDays": 0,
  "includeDescription": false,
  "maxJobsPerCompany": 0,
  "maxConcurrency": 10
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset with one item per job posting (active, new or closed)

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

Per-company status, detected ATS and counts of new and closed jobs

# 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": [
        "https://boards.greenhouse.io/stripe",
        "jobs.lever.co/palantir",
        "https://jobs.ashbyhq.com/openai"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("thesamirux/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": [
        "https://boards.greenhouse.io/stripe",
        "jobs.lever.co/palantir",
        "https://jobs.ashbyhq.com/openai",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("thesamirux/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": [
    "https://boards.greenhouse.io/stripe",
    "jobs.lever.co/palantir",
    "https://jobs.ashbyhq.com/openai"
  ]
}' |
apify call thesamirux/ats-jobs-monitor --silent --output-dataset

```

## MCP server setup

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