# Greenhouse & Lever Job Scraper (`zilicon/ats-jobs-scraper`) Actor

Scrape open roles straight from companies' own career boards and get title, employer, location, department, workplace type, employment type, posting date and apply URL. Give it a list of company boards. No login, no account.

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

## Pricing

$5.00 / 1,000 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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### Scrape open roles straight from company career boards

Pull job openings from the **Greenhouse** and **Lever** feeds that sit behind a company's own "Careers" page - the source of truth, not an aggregator's copy of it. Give the actor a list of company boards and it returns every open role as clean, flat JSON.

Each record carries title, employer, location, department, workplace type, employment type, first-seen date and a direct apply URL. No login, no API key, no CAPTCHA.

**Get your first results in about 30 seconds:** press **Start** with the prefilled input. It returns 100 roles from the two example boards. Then swap in your own companies and add filters.

Boards are read in the order you list them and the run stops as soon as `maxResults` is reached, so a large employer at the top of the list can fill the whole result set on its own. Set **Max results per company** when you want even coverage across every company you are tracking.

Your **$5 of free Apify credit is worth roughly 1,000 job records** on this actor.

#### What you get per role

| Field | Description |
|---|---|
| `id` | Stable id, provider-prefixed - e.g. `greenhouse:stripe:7954688` |
| `provider` | `greenhouse` or `lever` |
| `company` | Employer display name |
| `companySlug` | The board token you supplied |
| `title` | Job title |
| `location` | Location as the employer wrote it |
| `department` | Department or team, exactly as the board records it. Greenhouse often prefixes an internal id - `1654 Account Executives (AI)` - so match on a substring rather than equality |
| `workplaceType` | `onsite`, `remote`, `hybrid` - Lever only, `null` on Greenhouse |
| `employmentType` | Commitment as the company words it, e.g. `Regular Full Time (Salary)` - Lever only |
| `tags` | Commitment and team labels, where the board publishes them |
| `salaryMin`, `salaryMax` | Reserved - neither feed publishes salary |
| `url`, `applyUrl` | The public posting and its apply page |
| `publishedAt` | ISO 8601 date the role was published or last updated |
| `teaser` | First 300 characters of the description, HTML stripped |

#### Sample record

```json
{
  "id": "greenhouse:stripe:7954688",
  "provider": "greenhouse",
  "company": "Stripe",
  "companySlug": "stripe",
  "title": "Account Executive, AI Sales (Grower)",
  "location": "San Francisco, CA",
  "department": "1654 Account Executives (AI)",
  "workplaceType": null,
  "employmentType": null,
  "tags": [],
  "salaryMin": null,
  "salaryMax": null,
  "url": "https://stripe.com/jobs/search?gh_jid=7954688",
  "applyUrl": "https://stripe.com/jobs/search?gh_jid=7954688",
  "publishedAt": "2026-07-27T11:17:30-04:00",
  "teaser": "Who we are About Stripe Stripe is a financial infrastructure platform for businesses. Millions of companies use Stripe to accept payments, grow their revenue, and accelerate new business opportunities..."
}
```

### Finding a company's board slug

Look at the company's careers URL and take the last path segment:

- `boards.greenhouse.io/stripe` becomes `greenhouse:stripe`
- `jobs.lever.co/leverdemo` becomes `lever:leverdemo`

Many companies host the board on their own domain but still run one of these two systems underneath - check the careers page's network requests, or try the company name as a slug. A slug that does not exist is reported in the run summary and skipped; it never sinks the run.

### Filters

| Input | What it does |
|---|---|
| `companies` | The boards to scrape, as `provider:slug`. Add as many as you like |
| `maxResults` | Stop after this many roles. Your cost control |
| `keywords` | Keep roles containing ALL of these words, e.g. `senior engineer` |
| `titleOnly` | Match those keywords against the job title alone |
| `excludeKeywords` | Drop roles containing ANY of these words, e.g. `intern manager` |
| `location` | Keep roles whose location contains this text |
| `remoteOnly` | Keep only remote roles |
| `department` | Keep only a matching department or team |
| `employmentType` | Keep only roles whose commitment contains this text |
| `postedWithinDays` | Keep only roles published or updated in the last N days |
| `maxPerCompany` | Cap how many roles any one company contributes |
| `proxyConfiguration` | Standard Apify proxy input. Datacenter proxies are fine here |

Neither Greenhouse nor Lever offers a server-side search on these public feeds - each endpoint returns that company's current openings in full. Every filter above is therefore applied to the roles after fetching, not sent as a live query. That costs you nothing extra: the request per company is the same either way, and filtering before results are written means you are only charged for the roles you asked for.

#### Example

```json
{
  "companies": ["greenhouse:stripe", "greenhouse:gitlab", "lever:spotify"],
  "keywords": "engineer",
  "excludeKeywords": "manager director",
  "remoteOnly": true,
  "maxPerCompany": 20,
  "maxResults": 100
}
```

### What it costs

Pricing is **pay-per-event** on Apify's built-in per-result event: you pay per role returned and nothing at all for a run that finds no matches. There is **no per-run start fee**, so watching twenty companies in twenty small runs costs the same as one big one.

A worked example: Stripe's board carries about 550 open roles. Pulling all of them costs roughly **$2.75**. Monitoring ten mid-size companies for engineering roles only, at around 300 matches a day, is about **$1.50 a day**.

### Typical uses

- **Recruiting and talent intelligence** - track exactly who a target company is hiring, by team and location.
- **Job boards and aggregators** - source listings from the system of record instead of re-scraping another aggregator.
- **Competitive and market research** - headcount direction, which teams are growing, which locations are opening.
- **Sales prospecting** - hiring signals are budget signals, and the department tells you which budget.

### Your feedback

If a provider is missing, a field is wrong, or you need something these boards publish that this actor does not yet return, please open an issue on the **Issues** tab. Requests get read and acted on, and a short review helps other people find the actor.

### Disclaimer

This is an **unofficial** scraper. It is not affiliated with, endorsed by, or sponsored by Greenhouse Software, Inc. or Lever, Inc. It reads only data that those boards publish publicly, with no login and no access to private accounts.

#### Personal data in the output

Results may contain personal data (for example a named contact on a job posting). Personal data is protected by regulations such as the GDPR in the EU and the CCPA in California. You should not scrape or process personal data unless you have a legitimate reason to do so; if you are unsure whether your reason is legitimate, consult your lawyers.

# Actor input Schema

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

The company career boards to scrape, each as "provider:slug". Provider is greenhouse or lever; the slug is the board token in the company's careers URL - boards.greenhouse.io/STRIPE becomes "greenhouse:stripe", jobs.lever.co/LEVERDEMO becomes "lever:leverdemo". Add as many companies as you like; one bad slug is reported and skipped, it does not sink the run.

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

Stop after this many roles. Your cost control - 500 results costs about $2.50. Set 0 for no cap.

## `keywords` (type: `string`):

Keep only roles containing ALL of these words, e.g. 'senior engineer'. Matched against the title, company, department, tags and description unless 'Match title only' is on. Leave blank to return every open role.

## `titleOnly` (type: `boolean`):

Match the keywords against the job title alone. Use this when a word like 'python' appears in the body of every posting and you only want roles actually named for it.

## `excludeKeywords` (type: `string`):

Drop any role containing ANY of these words, e.g. 'intern manager director'. Applied to the whole record. Useful for stripping seniority levels you do not want.

## `location` (type: `string`):

Keep only roles whose location contains ALL of these words, e.g. 'London', 'New York', 'Germany'. Word order does not matter, so 'york new' also matches 'New York'. Leave blank for all locations.

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

Keep only remote roles. Uses the ATS remote flag where the provider publishes one (Lever) and the location text otherwise (Greenhouse).

## `department` (type: `string`):

Keep only roles whose department contains ALL of these words, e.g. 'Engineering', 'Sales', 'Design'. Matched as substrings, so 'eng' matches 'Engineering'. Note that Greenhouse often prefixes an internal id ('1654 Account Executives (AI)'), so match on a word rather than the full name.

## `employmentType` (type: `string`):

Keep only roles whose commitment contains this text, e.g. 'full time', 'contract', 'intern'. Each company writes its own wording - real values include 'Regular Full Time (Salary)', 'Contract - Remote' and 'Hourly' - so this matches as a substring rather than an exact list. Published by Lever boards only; Greenhouse does not expose it, so Greenhouse roles are excluded whenever this filter is set.

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

Keep only roles published or updated in the last N days, e.g. 14 for the last fortnight. Roles with no usable date are kept rather than silently dropped. Leave 0 for no date limit.

## `maxPerCompany` (type: `integer`):

Cap how many roles come from any single company, so one big employer cannot fill your whole result set. Leave 0 for no per-company cap.

## `proxyConfiguration` (type: `object`):

Proxy configuration. Datacenter proxies are fine for these boards.

## Actor input object example

```json
{
  "companies": [
    "greenhouse:stripe",
    "lever:leverdemo"
  ],
  "maxResults": 100,
  "titleOnly": false,
  "remoteOnly": false,
  "postedWithinDays": 0,
  "maxPerCompany": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Every job returned by the run, as rows in the default dataset.

# 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:leverdemo"
    ]
};

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

# Run the Actor and wait for it to finish
run = client.actor("zilicon/ats-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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:leverdemo"
  ]
}' |
apify call zilicon/ats-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=zilicon/ats-jobs-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/1DODw0VL9Sqq6wSwt/builds/1qmdk22jBlvfeW5o2/openapi.json
