# Greenhouse, Lever & Ashby Jobs Scraper — Salaries, No Login (`yugenox/ats-jobs-search`) Actor

Live job search across 12,000+ company career sites on Greenhouse, Lever and Ashby. Filter by keyword, location, remote, salary and posting date, or pull every open job from the companies you name. Salary ranges, full descriptions, apply links, daily new-jobs mode. No login.

- **URL**: https://apify.com/yugenox/ats-jobs-search.md
- **Developed by:** [Yugenox Corp](https://apify.com/yugenox) (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

$2.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.

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

## ATS Jobs Search: Greenhouse, Lever & Ashby jobs with salaries

Search open jobs **live** on the career sites of thousands of companies that hire through **Greenhouse, Lever and Ashby**. These are the platforms used by Stripe, Airbnb, OpenAI, Anthropic, Palantir, Notion, Figma and most fast-growing tech companies. You get one clean, identical record per job, whatever platform the company uses.

- **Name the companies** you care about and get every open job, or a filtered subset.
- **Search every company at once.** A built-in directory covers **12,000+ company job boards (about 300,000 open jobs)**. For example: "data analyst in Canada", "remote backend engineer", "internships in London".
- **Salary ranges** wherever the company publishes them, normalised to min / max / currency / period, with a minimum-salary filter.
- **Always fresh.** Every run reads the company's own job board at that moment. There is no cached database, so you never get jobs that closed last week.
- **Only-new mode for daily feeds.** Schedule it and get only jobs that are new or changed since the last run, plus free "closed" notices for jobs that disappeared.

No login, no cookies, nothing to configure. Paste company names and press Start.

### What you can do with it

- **Job seekers and career coaches:** a daily feed of new roles at your target companies, filtered by title, location, remote and minimum pay.
- **Recruiters and sourcers:** see who is hiring for what, where and at what pay, across hundreds of companies in one run.
- **Market and salary research:** compare published pay bands by role, company, city or country.
- **Job boards and aggregators:** feed thousands of company career pages into your site with full descriptions and apply links.
- **Sales intelligence:** hiring signals (new teams, new offices, new roles) for account research.

### Input examples

**Every engineering job at a few companies**

```json
{
  "companies": ["Stripe", "Airbnb", "https://jobs.lever.co/palantir", "openai"],
  "keywords": ["engineer"],
  "maxItems": 200
}
```

**Search every company: data and analytics roles in Canada paying at least 100k**

```json
{
  "searchAllCompanies": true,
  "keywords": ["data analyst", "analytics", "business intelligence"],
  "locations": ["Canada"],
  "minSalary": 100000,
  "salaryCurrency": "CAD"
}
```

**Daily feed of new remote product roles (schedule it once a day)**

```json
{
  "searchAllCompanies": true,
  "keywords": ["product manager", "product designer"],
  "workplaceTypes": ["remote"],
  "postedWithinDays": 7,
  "onlyNewOrChanged": true
}
```

### Input

| Field | What it does |
|---|---|
| **Companies** | Company names (`Stripe`), job board tokens (`anthropic`), job board links (`https://job-boards.greenhouse.io/stripe`, `https://jobs.lever.co/palantir`, `https://jobs.ashbyhq.com/openai`), or the company's own careers page if it embeds one of these boards. |
| **Job title keywords** | Match ANY of the entries. Words within one entry must all appear, in any order. Common endings count ("engineer" finds "Engineering Manager"). Put an entry in "double quotes" for an exact phrase. |
| **Locations** | Countries, states or provinces, cities, `Remote`, or `Remote Canada`. Countries and regions also match their cities, so "Canada" finds "Toronto, ON" and "California" finds "San Francisco, CA". |
| **Search every company** | Adds every job board in the built-in directory. When a location pins a country, only companies that hire there are searched. |
| **Job board platforms** | Limit to Greenhouse, Lever and/or Ashby. |
| **Filters** | Excluded title words, keyword match in the description, work arrangement (remote / hybrid / on-site), employment type, departments, posted within N days, minimum yearly salary (+ currency). |
| **Include full job descriptions** | Text + HTML description. Turn off for a faster, lighter list. |
| **Application form questions** | For Greenhouse jobs: the questions each application form asks. |
| **Max jobs / Max jobs per company** | Limits for the run. |
| **Only new or changed jobs** | Remembers previous results per search and returns only new or changed jobs. Jobs that were removed come back once as `changeType: "closed"`, free of charge. |

### Output

One record per job. Every field is present on every record (`null` when the company does not publish it):

```json
{
  "ats": "ashby",
  "company": "OpenAI",
  "companyToken": "openai",
  "jobId": "240d459b-696d-43eb-8497-fab3e56ecd9b",
  "title": "Research Engineer",
  "url": "https://jobs.ashbyhq.com/openai/240d459b-696d-43eb-8497-fab3e56ecd9b",
  "applyUrl": "https://jobs.ashbyhq.com/openai/240d459b-696d-43eb-8497-fab3e56ecd9b/application",
  "location": "San Francisco",
  "allLocations": ["San Francisco", "San Francisco, California, United States"],
  "countries": ["US"],
  "workplaceType": null,
  "isRemote": false,
  "employmentType": "full-time",
  "departments": ["Research"],
  "team": "Research",
  "offices": [],
  "postedAt": "2025-04-05T00:03:20.653Z",
  "updatedAt": null,
  "postedDaysAgo": 537,
  "applicationDeadline": null,
  "salaryMin": 250000,
  "salaryMax": 445000,
  "salaryCurrency": "USD",
  "salaryPeriod": "year",
  "salaryText": "$250K – $445K • Offers Equity",
  "salaryRanges": [{ "min": 250000, "max": 445000, "currency": "USD", "period": "year", "label": null }],
  "descriptionText": "By applying to this role, you will be considered for Research Engineer roles across all teams at OpenAI…",
  "descriptionHtml": "<p>By applying to this role…</p>",
  "language": null,
  "requisitionId": null,
  "internalJobId": null,
  "metadata": null,
  "companyBoardUrl": "https://jobs.ashbyhq.com/openai",
  "scrapedAt": "2026-09-24T07:19:35.566Z"
}
```

#### Fields

- **ats**: `greenhouse`, `lever` or `ashby`. **company**, **companyToken**: company name and its job board id. **companyBoardUrl**: the company's job board.
- **jobId**, **requisitionId**, **internalJobId**: the job's ids (the company's own requisition number when published).
- **title**, **url** (job page), **applyUrl**.
- **location**, **allLocations** (every listed location and office), **countries** (ISO codes detected from the locations, e.g. `["CA","US"]`), **workplaceType** (`remote` / `hybrid` / `onsite`), **isRemote**, **employmentType** (`full-time`, `part-time`, `contract`, `temporary`, `internship`).
- **departments**, **team**, **offices**.
- **postedAt** (first published), **updatedAt**, **postedDaysAgo**, **applicationDeadline**.
- **salaryMin**, **salaryMax**, **salaryCurrency**, **salaryPeriod** (`year`, `month`, `week`, `day`, `hour`, or null when the company does not say), **salaryText** (as published), **salaryRanges** (every published range, e.g. one per country or zone, with its label).
- **descriptionText**, **descriptionHtml**, **language**.
- **metadata**: extra custom fields some companies publish (e.g. "Location Type", "Employment Type").
- **questions**: application form questions, when requested (Greenhouse).
- **changeType**: `new`, `changed` or `closed` in only-new mode.

The Output tab has two ready-made views: **Jobs** (overview) and **Salaries**.

### FAQ

**Which companies are covered?**
Any company whose careers site runs on Greenhouse, Lever or Ashby. The built-in directory lists 12,000+ of them and is refreshed regularly. A company missing from the directory still works: paste its job board link or careers page, or just its name, and the actor checks all three platforms live.

**How fresh is the data?**
Live. Every run reads each company's job board at that moment, so closed jobs never show up and new jobs appear as soon as the company posts them.

**How do salaries work?**
Many companies publish pay ranges, and some US states and Canadian provinces require them. You get the headline range in `salaryMin`/`salaryMax`/`salaryCurrency`/`salaryPeriod` and every published range in `salaryRanges`. The minimum-salary filter compares yearly amounts, so hourly and monthly ranges are converted. Jobs without a published range are left out when that filter is set.

**How long does a run take?**
A handful of companies takes seconds. Searching every company takes a few minutes; limiting it to a country or a platform makes it faster.

**Why did a company return 0 jobs?**
It may have no open roles matching your filters, or it may have moved to a different job platform. The run log shows each company's result, and companies that could not be found are listed in the final status.

**Can I get only jobs I have not seen before?**
Yes. Turn on **Only new or changed jobs** and schedule the actor. Each distinct search keeps its own memory, so you are only charged for new or changed jobs. Removed jobs are reported once as `closed`, free.

**Do I need a proxy?**
The default Apify datacenter proxy works well and is the cheapest option. You can also switch the proxy off.

**What happens when a job board is down or the run hits its time limit?**
The run still finishes successfully with everything it could collect, and the status message says what happened ("Partial — stopped before the run's time limit", "Greenhouse did not respond this run", "Not found: …"). A platform that keeps failing is paused and retried a few times, then skipped for the rest of the run instead of burning your timeout. Whole boards that are too large for the run's memory are delivered from lighter calls (raise the memory for full descriptions). You are charged only for jobs that were actually saved to the dataset — never for errors, retries, duplicates, unchanged jobs or "closed" notices.

**I pasted an input from another job scraper. Will it work?**
Mostly, yes. Common spellings are accepted as aliases: `maxResults` / `limit` for `maxItems`, `keyword` / `query` for `keywords`, `company` / `startUrls` for `companies`, `location` for `locations`, `remote: true` for `workplaceTypes: ["remote"]`, `onlyNew` for `onlyNewOrChanged`. An input the actor cannot use ends with 0 jobs, no charge, and a message telling you what to add.

**Is it legal to scrape Greenhouse, Lever and Ashby job boards?**
This actor reads only public job postings: the same listings anyone can see on a company's careers page without logging in, served by the public job-board feeds that Greenhouse, Lever and Ashby provide so companies can show their jobs on their own websites. Job postings are business information, but a description can occasionally name a recruiter or include a contact email that the company chose to publish. If you store or reuse that kind of personal data, you are responsible for following the privacy laws that apply to you (such as GDPR, PIPEDA or CCPA) and the terms of the sites involved. If you are unsure whether your use case is allowed, check with a lawyer. More background: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

**Does it access any private data?**
No. It never logs in, uses no accounts, cookies or API keys, and only reads jobs that companies have published on their public job boards. It cannot see candidates, applications, internal or unpublished jobs, or anything else inside a company's hiring system.

# Actor input Schema

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

Company names (e.g. Stripe, Airbnb, OpenAI, Palantir), job board tokens (anthropic), job board links (https://job-boards.greenhouse.io/stripe, https://jobs.lever.co/palantir, https://jobs.ashbyhq.com/openai) or a company's own careers page that embeds one of those boards. Names are matched against a built-in directory of thousands of companies; unknown names are checked live. Leave empty and add keywords to search every company in the directory.

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

A job matches if its title contains ANY of these. Words inside one entry must all appear, in any order ("data analyst" also finds "Analyst, Data Platform"); common word endings count ("engineer" finds "Engineering Manager"). Put an entry in double quotes for an exact phrase. Leave empty for every job.

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

Countries, states/provinces or cities, e.g. Canada, Ontario, Toronto, United States, California, London, Remote, "Remote Canada". A job matches if it is in ANY of them. Countries and provinces/states also match their cities (Canada finds "Toronto, ON").

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

Maximum number of jobs saved in this run. Leave empty for no limit.

## `searchAllCompanies` (type: `boolean`):

Search all Greenhouse, Lever and Ashby job boards in the built-in directory (thousands of companies), live, on top of any companies listed above. Best combined with keywords and/or locations. A full sweep takes several minutes.

## `atsPlatforms` (type: `array`):

Which platforms to search when searching every company (and when matching company names). Default: all three.

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

Skip jobs whose title matches any of these, e.g. senior, manager, intern.

## `keywordsInDescription` (type: `boolean`):

Match keywords against the full description too (e.g. skills like SQL or Kubernetes), not only the title.

## `workplaceTypes` (type: `array`):

Only remote, hybrid or on-site jobs. Jobs that do not state an arrangement count as hybrid/on-site unless their location says remote.

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

Full-time, part-time, contract, temporary or internship. Jobs without a stated type are judged by their title (e.g. "Intern").

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

Only jobs in these departments or teams, e.g. Engineering, Data, Sales, Finance.

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

Only jobs first published in the last N days.

## `minSalary` (type: `integer`):

Only jobs that publish a pay range reaching at least this much per year (hourly/monthly ranges are converted). Jobs without a published range are left out when this is set.

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

Optional 3-letter currency for the minimum salary, e.g. USD, CAD, GBP, EUR. Empty = any currency.

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

Adds the description as text and HTML (and departments/offices for Greenhouse). Turn off for a faster, lighter list of titles, locations, salaries and links.

## `includeApplicationQuestions` (type: `boolean`):

Adds the questions each Greenhouse job's application form asks (label, required, type, options). Costs one extra request per job.

## `maxItemsPerCompany` (type: `integer`):

Cap per company, so one big employer does not use up the whole run.

## `onlyNewOrChanged` (type: `boolean`):

Remembers the jobs this search returned before and saves only new ones and ones whose title, location or pay changed (marked in changeType). Jobs that disappeared are reported once as changeType "closed" at no charge. Schedule the actor daily for a new-jobs feed.

## `stateKey` (type: `string`):

Optional. By default each distinct search keeps its own memory automatically; set a name to share or separate memories explicitly.

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

Requests in flight at once. Empty = 16, or 24 when searching every company.

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

Apify's datacenter proxy works well and is the cheapest. You can also switch the proxy off.

## Actor input object example

```json
{
  "companies": [
    "anthropic",
    "stripe"
  ],
  "keywords": [
    "engineer"
  ],
  "maxItems": 50,
  "searchAllCompanies": false,
  "keywordsInDescription": false,
  "includeDescription": true,
  "includeApplicationQuestions": false,
  "maxItemsPerCompany": 25,
  "onlyNewOrChanged": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Every row this run saved, as JSON.

## `resultsCsv` (type: `string`):

The same rows as CSV, ready for a spreadsheet.

## `resultsTable` (type: `string`):

The same rows narrowed to the key columns (the "overview" view).

# 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": [
        "anthropic",
        "stripe"
    ],
    "keywords": [
        "engineer"
    ],
    "maxItems": 50,
    "maxItemsPerCompany": 25,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yugenox/ats-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 = {
    "companies": [
        "anthropic",
        "stripe",
    ],
    "keywords": ["engineer"],
    "maxItems": 50,
    "maxItemsPerCompany": 25,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("yugenox/ats-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 '{
  "companies": [
    "anthropic",
    "stripe"
  ],
  "keywords": [
    "engineer"
  ],
  "maxItems": 50,
  "maxItemsPerCompany": 25,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call yugenox/ats-jobs-search --silent --output-dataset

```

## MCP server setup

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