# ATS Jobs Scraper: Greenhouse, Lever, Workday & 8 more (`nice_dev/ats-jobs-scraper`) Actor

Scrape job listings from company career pages on 11 ATS (Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable…) in one schema: salary per year, skills, remote, new and closed jobs. Export to JSON, CSV or Excel.

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

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 is ATS Jobs Scraper?

**ATS Jobs Scraper** extracts **job postings from company career pages** hosted on **11 ATS** — Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Recruitee, Workable, Personio, BambooHR, Rippling and Teamtailor — into **one schema**: title, company, locations, **salary converted to a yearly amount**, remote / hybrid / on-site, seniority, years of experience, skills, full description and more. It works as a **Greenhouse, Lever, Ashby and Workday jobs API alternative**: run it on a schedule, call it from your code, or plug it into Make, Zapier or n8n.

Type **company names** (`stripe`, `ramp`, `spotify`) and the Actor finds which ATS hosts each one — or paste career page links, or tick **Search all companies in our directory** to search **17,463 companies** at once. Click **Start** and download the jobs in JSON, CSV or Excel. No login, nothing to set up.

### 📋 What data can you extract from career pages?

One item per job, 79 fields, the same whatever the ATS:

| Category                  | What you get                                                                                                                                                                 |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 🏷️ **Job**                | title, job link, apply link, an ID unique across every ATS and company, status (open, updated, taken down) — `Software Engineer, AI Connections (Developer Platform)`        |
| 🏢 **Company**            | name, career page, ATS, number of open jobs on the whole board, hiring entity, website, description — `Notion`, `137` open jobs                                               |
| 📍 **Location**           | main location and every other one, city, region, postal code, country and country code, map coordinates when published — `San Francisco, California`                        |
| 🏠 **Remote and contract** | remote / hybrid / on-site, fully remote or not, contract type (full-time, part-time, contract, internship…) normalized and as published — `hybrid`, `full-time`              |
| 🎓 **Profile asked**      | seniority (intern to executive), years of experience, highest degree, skills, visa sponsorship, security clearance — `10` years, `master`, `TypeScript`                      |
| 💰 **Salary**             | minimum and maximum, currency, period, **the same converted to a year**, where it was read, every pay range by location or tier, equity — `$272,000 – $304,000 per year`    |
| 🗂️ **Team**               | department, team, job function, industry, requisition ID, recruiter name, the company's own custom fields                                                                   |
| 🕒 **Dates**              | published, updated, "Posted 3 Days Ago" as shown, days since posted, application deadline — what the date filters read                                                     |
| 📝 **Text**               | full description as plain text and HTML, requirements, benefits, titled sections, posting language                                                                          |
| 📋 **Application form**   | the questions of the application form: label, type, required or not, choices (option)                                                                                      |
| ✉️ **Company contacts**   | public e-mails, phone numbers and social links found on the company's website (option)                                                                                      |
| 🔔 **Monitoring**         | first seen, last seen, taken down on, the keywords a job matched, what you typed that led to it                                                                             |

Every field, with an example, is listed in the **Output** section below.

Seniority, workplace type, contract type and language come from the ATS when it gives them; otherwise they are **detected from the job text**, like the years of experience, highest degree, skills, visa sponsorship and security clearance (empty when the text says nothing).

The description comes with the job list on Greenhouse, Lever, Ashby, Recruitee, Personio and Teamtailor. On Workday, SmartRecruiters, Workable, BambooHR and Rippling, tick **Extract job details** (paid option, off by default) to open each job page for the description and, depending on the ATS, the exact posting date, requirements, benefits or extra locations.

### ✅ Why use ATS Jobs Scraper?

- 🧩 **11 ATS, one schema**: Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Recruitee, Workable, Personio, BambooHR, Rippling and Teamtailor jobs land in the same columns — one dataset, one import.
- 🔎 **Type a name, not a URL**: `stripe` is enough — the Actor tries the ATS you allow and finds the career page. A domain (`stripe.com`), a forced ATS (`greenhouse:airbnb`) or any career page or job link work too. A Workday company is found by name only when it is in the directory; otherwise paste its career page link. A name found nowhere is listed, and the run goes on.
- 📚 **Jobs at companies you don't know yet**: a built-in directory of 17,463 company career pages (over 1 million open jobs when they were checked), searched with your keywords and filters.
- 💵 **Salaries you can compare**: hourly, daily, weekly and monthly pay converted to a year, every pay range kept, and where the amount was read.
- 🏭 **Big Workday boards in full**: Workday shows at most 2,000 jobs per search; past that, the Actor splits the board by country, then by job family, and saves each job once.
- 🎯 **The same filters on every ATS**: whole-word keywords and excluded words, places and countries, remote, contract, seniority, language, years of experience, skills, visa sponsorship, yearly salary, dates, company size.
- 🔔 **Monitoring built in**: tick **Only new jobs** and schedule the Actor: each run returns only the jobs never delivered before — and, if you want, the jobs **updated** and **taken down** since.
- 🔌 API, scheduling, integrations (Make, Zapier, n8n, Google Sheets…) and JSON / CSV / Excel export via the Apify platform.

### 🚀 How to scrape jobs from Greenhouse, Lever, Workday and other ATS

1. Create a free Apify account.
2. Open **ATS Jobs Scraper** and type company names in **Companies** (e.g. `stripe`), paste career page links into **Career page URLs**, or tick **Search all companies in our directory**.
3. Add a **Job keyword** (e.g. `engineer`) and the filters you need: location, remote, seniority, salary, dates…
4. Set how many job listings to save — **Max jobs** (100 by default, 0 = no limit) — then click **Start**.
5. Download the dataset in JSON, CSV, Excel or via API.

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

This Actor uses **pay per event** pricing: you pay for what it delivers, and the price of each event is in the **Pricing** tab. What is charged:

- each **job** saved in the dataset — a job saved again because it changed (**Also report updated jobs**) counts as a job;
- each **job page opened** with **Extract job details**, on top of the job — only on Workday, SmartRecruiters, Workable, BambooHR and Rippling, and only when the page was really read;
- each job delivered **with its application questions** (**Application form questions**), on top of the job — a job without questions pays nothing more;
- each **company summary** written (**Hiring summary per company**);
- each **company with at least one e-mail found** (**Company contact e-mails**), once per company — phone numbers and social links alone are free;
- each **job taken down** reported (**Report jobs taken down**), instead of the price of a job;
- a small fee per run start, and a small fee for each job that one of your filters checks and drops (`filter-check`, or `detail-filter-check` when the filter needed the job page).

A job already delivered, with **Only new jobs**, is neither saved nor charged. Platform usage is included in the price.

### ⚙️ Input

```json
{
    "companies": ["stripe", "ramp", "spotify"],
    "query": "engineer",
    "workplaceTypes": ["remote", "hybrid"],
    "maxItems": 200
}
```

Search the whole directory: data engineers in the US, paid at least $150,000 a year, posted in the last 7 days:

```json
{
    "searchAllCompanies": true,
    "maxCompanies": 2000,
    "atsPlatforms": ["greenhouse", "ashby", "lever"],
    "searchQueries": ["data engineer", "analytics engineer"],
    "countries": ["US"],
    "minSalary": 150000,
    "salaryCurrency": "USD",
    "postedAfter": "7 days",
    "maxItems": 500
}
```

Or with career page links, as a daily monitor of new, updated and taken-down jobs:

```json
{
    "startUrls": [
        { "url": "https://job-boards.greenhouse.io/airbnb" },
        { "url": "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite" }
    ],
    "maxItems": 0,
    "onlyNew": true,
    "includeUpdatedJobs": true,
    "includeClosedJobs": true,
    "stateKey": "airbnb-nvidia"
}
```

| Field | Notes |
| --- | --- |
| `companies` | Company names (`stripe`, `ramp`), website domains (`stripe.com`) or a forced ATS with its prefix (`greenhouse:airbnb`, `ashby:notion`, `workday:nvidia.wd5/NVIDIAExternalCareerSite`). A career page link works here too, with or without https:// (`jobs.lever.co/spotify`); a name with a colon that is no ATS prefix (`Re:Work`) is read as a name. Each name is looked for on the ATS ticked in **ATS platforms**; a Workday company is found by name only when it is in the built-in directory, otherwise give its career page link (here or in **Career page URLs**). A name found nowhere is listed in the FAILED_REQUESTS record of the run and the run goes on. Max 5,000. |
| `startUrls` | Career pages or job pages of the 11 ATS: `https://job-boards.greenhouse.io/airbnb`, `https://jobs.lever.co/spotify`, `https://jobs.ashbyhq.com/ramp`, `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`, `https://apply.workable.com/huggingface`. A job link reads the whole board of its company. Workday needs the full link (company and site): it is the way to read a Workday company that is not in the directory. Max 5,000. |
| `searchAllCompanies`, `maxCompanies` | Also read the companies of the built-in directory (17,463 career pages checked on 21-22 October 2026), the largest boards first, restricted by `atsPlatforms`, `includeCompanies` and `excludeCompanies`. `maxCompanies` = how many (500 by default, 0 = the whole directory). |
| `atsPlatforms` | `greenhouse`, `lever`, `ashby`, `workday`, `smartrecruiters`, `recruitee`, `workable`, `personio`, `bamboohr`, `rippling`, `teamtailor`: the ATS a company name is looked for on, and the ATS of the directory companies. Empty = all eleven. |
| `query`, `searchQueries`, `searchInDescription` | Keep the jobs whose title, department or team contains the word or phrase (`engineer`, `data scientist`; whole words, case and accents ignored). `searchQueries` adds more keywords: a job matching any of them is kept, once (up to 100 in `searchQueries`, plus `query`). `searchInDescription` reads the description too; on Workday, SmartRecruiters, Workable, BambooHR and Rippling it turns `extractDetails` on. Empty = all jobs. |
| `excludeKeywords` | Drop the jobs whose title contains one of these whole words (`intern`, `sales`); the description too with `searchInDescription`. |
| `location`, `locations` | Keep the jobs with a location containing this text (`London`, `Germany`, `Remote`; case and accents ignored); `locations` adds more places (up to 100, plus `location`), a job matching any of them is kept. |
| `countries` | ISO codes (`US`, `GB`, `DE`) or English names (`Germany`): a job with several locations is kept when one of them matches; a job whose country cannot be read is dropped. |
| `excludeLocations` | Drop the jobs whose every location contains one of these words (`India`). On Workday, SmartRecruiters, Workable, BambooHR and Rippling, a job whose list entry shows no location is checked on its job page (one more request, charged as a filter check only if the job is dropped). |
| `workplaceTypes`, `remoteOnly` | `remote`, `hybrid`, `onsite`: from the ATS when it says it, otherwise from the location and title. `remoteOnly` adds `remote` to `workplaceTypes`: alone, it keeps the remote jobs only; with `hybrid` ticked too, it keeps both. |
| `employmentTypes` | `full-time`, `part-time`, `contract`, `temporary`, `internship`, `apprenticeship`, `volunteer`: from the ATS when it gives it, otherwise from the title. A job whose type is found neither on its ATS nor in its title is dropped once this list is set. |
| `seniority` | `intern`, `junior`, `mid`, `senior`, `lead`, `manager`, `director`, `executive`: from the ATS level when there is one, otherwise from the title. A job with no level is dropped once this list is set. |
| `departments` | Keep the jobs whose department, team or job function contains one of these words (`Engineering`, `Sales`). Workday gives no department: its jobs are dropped once this list is set. |
| `skills` | Keep the jobs that name at least one of these skills in the title or description (`Python`, `Salesforce`, `Kubernetes`; whole words). |
| `languages` | Language of the posting, ISO codes (`en`, `de`, `fr`): from the ATS when it gives it, otherwise detected from the description. |
| `maxYearsExperience` | `3` keeps the jobs that ask 3 years of experience or less; a job that writes no number is kept. On Workday, SmartRecruiters, Workable, BambooHR and Rippling, whose job list has no description, the job page of each job is read for it (one more request, charged as a filter check only if the job is dropped). `0` = no limit. |
| `visaSponsorshipOnly` | Keep only the jobs that say they sponsor visas. |
| `salaryCurrency`, `minSalary`, `maxSalary`, `keepJobsWithoutSalary`, `onlyWithSalary` | Yearly salary bounds in this currency (`USD` by default, `EUR`, `GBP`…), hourly to monthly pay converted to a year first: `minSalary` reads the top of the range, `maxSalary` the bottom. A job in another currency or without a salary is dropped; `keepJobsWithoutSalary` keeps the jobs without a salary. `onlyWithSalary` keeps only the jobs that show a salary. |
| `minOpenJobs` | `50` keeps the companies with at least 50 open jobs on their board, counted before your filters. `0` = all companies. |
| `includeCompanies`, `excludeCompanies` | Keep, or drop, the jobs of the companies whose name or slug contains one of these words (`Stripe`) — dropping staffing agencies is a common use. |
| `postedAfter`, `postedBefore` | Publication date range: `2026-09-01` (the whole day is included) or a period before now (`7 days`, `24 hours`, `2 weeks`). Reads `publishedAt`; a job without a date is dropped. |
| `updatedAfter` | Jobs updated on their ATS since this date or period (`3 days`), read on `updatedAt`, else on `publishedAt`. |
| `extractDetails` | Paid option, off by default. Opens each job page on Workday, SmartRecruiters, Workable, BambooHR and Rippling, whose job list has no description: description, exact posting date, requirements, benefits or extra locations, depending on the ATS. Greenhouse, Lever, Ashby, Recruitee, Personio and Teamtailor always give the full description. |
| `includeApplicationQuestions` | Paid option, off by default. Greenhouse, Ashby, Recruitee, Rippling and BambooHR: the questions of the application form (label, type, required, choices), plus the pay ranges Greenhouse publishes. Charged per job that has questions. |
| `descriptionFormat`, `descriptionMaxLength` | `both` (default), `text`, `html` or `none`: which description columns to save (`description`, `descriptionHtml`). `descriptionMaxLength` cuts the plain text to that many characters (0 = the full text, up to 32,000 characters); `descriptionHtml` is kept up to 200,000 characters. |
| `includeCompanySummary` | Paid option, off by default. One summary per company with jobs in the results, counted on the jobs this run delivered (after your filters, `maxItems` and `onlyNew`); only its count of open jobs is the whole board, before your filters. Jobs by department, country, workplace type, seniority and contract type, share of remote jobs, jobs posted in the last 7 and 30 days, new and taken down since the last run, salary range. Saved in the COMPANY_SUMMARIES record of the key-value store (linked in the Output tab). If the jobs reach the maximum cost set for the run, some summaries can be left out: the log says how many. |
| `enrichEmails` | Paid option, off by default. For each company whose website is known (the domain typed in Companies, Ashby's company profile, or the careers page linked by Greenhouse or Recruitee), reads its contact and about pages: public e-mails, phone numbers, social links. Charged once per company with at least one e-mail found; phone numbers and social links alone are free. |
| `maxItems`, `maxItemsPerQuery` | Jobs saved for the whole run (`0` = no limit), and the cap of each company board, so that one big employer cannot use up the whole budget (`0` = none). |
| `onlyNew`, `stateKey`, `resetState` | Monitoring: only the jobs never delivered under this memory key (`fintech-engineers`); `resetState` forgets the memory. |
| `includeUpdatedJobs`, `includeClosedJobs` | With `onlyNew`: also save again a job already delivered whose content changed (status updated, charged as a job), and report once each job taken down from its board (status closed, paid option, charged per job taken down). Up to 32 records of 4,000 followed jobs each: see Known limitations. |
| Advanced | `proxyConfiguration` (none by default: add one if your runs are rate-limited), `maxConcurrency`, `maxRequestsPerMinute`, `minRequestIntervalMs`, `maxRequestRetries`, `debugLog`. |

### 📦 Output

One real job (Notion, on Ashby), shortened: some columns are left out (most of them empty for this job) and the description is cut.

```json
{
    "id": "1fc309c8-da20-4ff2-84c7-8b863ece2b0a",
    "globalId": "ashby:notion:1fc309c8-da20-4ff2-84c7-8b863ece2b0a",
    "url": "https://jobs.ashbyhq.com/notion/1fc309c8-da20-4ff2-84c7-8b863ece2b0a",
    "applyUrl": "https://jobs.ashbyhq.com/notion/1fc309c8-da20-4ff2-84c7-8b863ece2b0a/application",
    "status": "open",
    "ats": "ashby",
    "companySlug": "notion",
    "companyName": "Notion",
    "companyOpenJobs": 137,
    "boardUrl": "https://jobs.ashbyhq.com/notion",
    "title": "Software Engineer, AI Connections (Developer Platform)",
    "department": "Engineering",
    "departments": ["Engineering"],
    "team": "Engineering",
    "location": "San Francisco, California",
    "locations": ["San Francisco, California", "New York, New York"],
    "city": "San Francisco",
    "region": "California",
    "country": "United States",
    "countryCode": "US",
    "countryCodes": ["US"],
    "workplaceType": "hybrid",
    "isRemote": false,
    "employmentType": "full-time",
    "employmentTypeRaw": "FullTime",
    "minYearsExperience": 10,
    "maxYearsExperience": 10,
    "educationLevel": "master",
    "skills": ["TypeScript", "LLM"],
    "salaryMin": 272000,
    "salaryMax": 304000,
    "salaryCurrency": "USD",
    "salaryPeriod": "year",
    "salaryMinYearly": 272000,
    "salaryMaxYearly": 304000,
    "salaryText": "$272,000 – $304,000 per year",
    "salarySource": "description",
    "salaryRanges": [{ "title": null, "min": 272000, "max": 304000, "currency": "USD", "period": "year" }],
    "publishedAt": "2026-08-24T14:44:49.699Z",
    "postedDaysAgo": 58,
    "language": "en",
    "description": "WHO WE ARE\n\nNotion is the collaborative AI workspace where teams and agents think together https://www.youtube.com/watch?v=vkpYpWfEK5s. We're building one place where your knowledge, projects, meetings, and AI tools live side by side, so work is faster, clearer, and less fragmented. …",
    "descriptionHtml": "<h1>Who We Are</h1><p style=\"min-height:1.5em\">Notion is the collaborative AI workspace where teams and agents …",
    "sections": [],
    "customFields": {},
    "applicationQuestions": [],
    "companyEmails": [],
    "companyPhones": [],
    "companySocialLinks": [],
    "matchedKeywords": [],
    "sourceInput": "ashby:notion",
    "scrapedAt": "2026-10-21T22:58:00.128Z"
}
```

You can download the dataset in various formats such as JSON, HTML, CSV or Excel. The Output tab also has a **salaries** view.

#### All 79 fields

| Fields | What you get |
| --- | --- |
| `id`, `globalId` | the job's ID on its ATS, and `ats:companySlug:id` — unique across every ATS and company, the key to merge runs: `ashby:notion:1fc309c8-…` |
| `url`, `applyUrl` | the job page and the application form |
| `status` | `open`, `updated` (delivered before and changed since) or `closed` (taken down from its board) |
| `ats`, `companySlug`, `boardUrl`, `sourceApiUrl` | `ashby`, `notion`, `https://jobs.ashbyhq.com/notion`, and the address the job was read from |
| `companyName`, `hiringOrganization`, `companyOpenJobs` | **Company**: `Notion`, the hiring entity when named apart (Personio; Workday with **Extract job details**), `137` open jobs on the whole board, before your filters |
| `companyWebsite`, `companyDomain`, `companyLogoUrl`, `companyDescription` | website and domain (the domain you typed, Ashby's company profile with **Company contact e-mails**, or the careers page linked by Greenhouse or Recruitee), logo (not filled yet: always empty), about-the-company text (SmartRecruiters and Rippling, with **Extract job details**) |
| `title` | `Software Engineer, AI Connections (Developer Platform)` |
| `department`, `departments`, `team`, `jobFunction`, `industry` | **Team**: `Engineering`, every department (parent first), team, job function or category, industry (SmartRecruiters) |
| `location`, `locations`, `city`, `region`, `postalCode` | **Location**: `San Francisco, California`, every location of the job, `San Francisco`, `California`, postal code |
| `country`, `countryCode`, `countryCodes`, `latitude`, `longitude` | `United States`, `US`, the codes of every location, coordinates (SmartRecruiters) |
| `workplaceType`, `isRemote` | `remote`, `hybrid` or `onsite`; `true` when the job can be done fully remote |
| `employmentType`, `employmentTypeRaw` | `full-time`, `part-time`, `contract`, `temporary`, `internship`, `apprenticeship` or `volunteer`; as published: `FullTime` |
| `seniority`, `experienceLevelRaw` | `intern`, `junior`, `mid`, `senior`, `lead`, `manager`, `director` or `executive`; the level as published |
| `minYearsExperience`, `maxYearsExperience`, `educationLevel` | **Profile asked**: `10`, `10` (`3-5 years` gives 3 and 5), `master` (`high-school`, `bachelor`, `master` or `phd`) |
| `skills` | `["TypeScript", "LLM"]`, from a fixed list of common skills |
| `visaSponsorship`, `securityClearance` | `true`, `false`, or `null` when the job says nothing |
| `recruiterName` | the recruiter who published the job (SmartRecruiters) |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod` | **Salary**: `272000`, `304000`, `USD`, `year` (or `month`, `week`, `day`, `hour`) |
| `salaryMinYearly`, `salaryMaxYearly` | converted to a year (hour × 2,080, day × 260, week × 52, month × 12): `$33.65 - $38.70 per hour` gives `69992` and `80496` |
| `salaryText`, `salarySource`, `salaryRanges`, `offersEquity` | `$272,000 – $304,000 per year`; `ats`, `pay-transparency` or `description`; every pay range (by location or tier); equity (Ashby) |
| `publishedAt`, `updatedAt`, `postedOnText`, `postedDaysAgo` | **Dates**: `2026-08-24T14:44:49.699Z` (the day alone, `2026-09-21`, when the ATS gives no time: Workable, BambooHR, Workday), last update (Greenhouse and Recruitee), `Posted 30+ Days Ago` (Workday), `58` |
| `applicationDeadline`, `requisitionId`, `internalJobId` | last day to apply, as written by the job (`2026-11-30`; Greenhouse and Recruitee), the company's reference of the opening, its internal ID |
| `language` | `en` |
| `description`, `descriptionHtml` | **Text**: the full description, plain text and HTML (HTML up to 200,000 characters) |
| `requirements`, `benefits`, `sections` | requirements and benefits when the ATS publishes them apart, the titled sections of the description |
| `customFields` | the fields the company added on its ATS, name → value |
| `applicationQuestions` | with **Application form questions**: label, type, required, choices |
| `companyEmails`, `companyPhones`, `companySocialLinks` | with **Company contact e-mails**: public e-mails, phone numbers, LinkedIn, X, Facebook… pages |
| `matchedKeywords`, `sourceInput` | the keywords the job matched; the company or link you typed (`directory` for the directory) |
| `firstSeenAt`, `lastSeenAt`, `closedAt` | with **Only new jobs**: first delivered, last run that found it, taken down at |
| `scrapedAt` | ISO timestamp of the extraction |

### 💡 Tips

#### Search the whole directory

Tick **Search all companies in our directory** to read the career pages of 17,463 companies checked on 21-22 October 2026 (about 1,009,000 open jobs between them when they were checked), the largest boards first, up to **Max companies from the directory** (500 by default, 0 = all). Narrow them down with **ATS platforms**, **Only these companies** and **Exclude companies**, then keep the jobs you want with keywords and filters.

| ATS | Companies | Open jobs when checked |
| --- | --- | --- |
| Workable | 3,684 | 65,934 |
| Greenhouse | 3,548 | 145,226 |
| BambooHR | 2,556 | 18,496 |
| Workday | 1,962 | 498,730 |
| Ashby | 1,783 | 42,813 |
| Personio | 1,619 | 15,302 |
| Teamtailor | 634 | 7,784 |
| SmartRecruiters | 611 | 185,711 |
| Rippling | 400 | 5,239 |
| Recruitee | 372 | 8,006 |
| Lever | 294 | 15,690 |

#### How to get more results

Set `maxItems` to `0`, leave `maxItemsPerQuery` at `0`, and use broad keywords. Big Workday boards are read past 2,000 jobs, nothing to set. With `searchInDescription`, a keyword written only in the description is found too.

#### How to reduce costs

The price is per job, so the levers are `maxItems`, `maxItemsPerQuery`, the filters (a job a filter drops costs only the small filter fee) and `onlyNew` for recurring runs (you never pay twice for the same job, unless it changed and you ticked `includeUpdatedJobs`). Leave the paid options off unless you need them: Greenhouse, Lever, Ashby, Recruitee, Personio and Teamtailor already give the full description.

#### Several keywords and places in one run

Fill `searchQueries` and / or `locations`, up to 100 each (plus the single `query` and `location`): a job is kept when it matches any keyword and any place, and is saved — and charged — once, with the keywords it matched in `matchedKeywords`. The single `query` and `location` fields still work and are added to the lists. Set `maxItemsPerQuery` to give every company board its own cap: without it, the first big boards can use up the whole `maxItems` budget.

#### Monitoring: new, updated and taken-down jobs

Tick **Only new jobs** (`onlyNew`) and schedule the Actor. The first run returns everything; each later run skips the jobs already delivered: they are not saved and not charged. The memory lives in a named key-value store of your account (`ats-jobs-scraper-seen`, up to 150,000 listings per key) and is only updated with jobs that really reached the dataset, so a failed run never hides anything. Give each schedule its own `stateKey` (two schedules sharing a key would hide each other's jobs), and tick `resetState` once to start over.

Add **Also report updated jobs** to get a job again when its title, locations, salary, description or dates changed (`status` = `updated`), and **Report jobs taken down** to get, once, each delivered job that is no longer on its company board (`status` = `closed`, with `closedAt`). Tick them from the first run of the schedule: jobs are followed from a run that has one of them ticked. A board is judged only when the run read it in full: a board that failed, was cut by a cap, was searched for a keyword on the ATS itself, or is a Workday board of 2,000 jobs or more reports no job taken down. Up to 4,000 jobs are followed in each of 32 records (a company board always in the same one): past that, the next jobs of a full record are not reported as updated or taken down.

#### Salary filters

`minSalary` and `maxSalary` compare the yearly amount (hour × 2,080, day × 260, week × 52, month × 12) in `salaryCurrency` (USD by default). There is no currency conversion: a job paid in another currency is dropped, and so is a job without a salary unless you tick `keepJobsWithoutSalary`. The salary comes from the ATS's pay fields, from the pay ranges Greenhouse publishes (with `includeApplicationQuestions`), or from an amount written in the description — `salarySource` tells which.

#### Filter by publication date

`postedAfter` and `postedBefore` take a date (`2026-09-01`, the whole day is included) or a period before now (`7 days`, `2 weeks`, `24 hours`). They read `publishedAt`; on Workday without **Extract job details**, that is the day computed from "Posted 3 Days Ago" ("30+ Days Ago" counts as 30 days) — unless one of your date bounds is more than 30 days ago: then the page of each "30+ Days Ago" job is opened to read its exact date (one more request per such job, not charged as **Extract job details**). A job without a date is dropped as soon as a date bound is set. `updatedAfter` reads `updatedAt`, or `publishedAt` when the ATS gives no update date. Filtered-out jobs are not saved and do not count in `maxItems`.

### 🔌 Integrations and API

Call the Actor via the Apify API, the JavaScript or Python clients, or connect it with integrations and webhooks (Make, Zapier, n8n, Google Sheets, Slack, Airtable…). The dataset can be fetched as JSON or CSV from any tool.

### 🤖 Use with AI agents (MCP)

AI agents and assistants (any MCP client) can find and run this Actor through the [Apify MCP server](https://mcp.apify.com), billed to their Apify account like any run. It returns one item per job posting. Actor id: `nice_dev/ats-jobs-scraper`; MCP server with this Actor only: `https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/ats-jobs-scraper`.

Smallest input, for a cheap first call:

```json
{
    "companies": ["stripe"],
    "maxItems": 10
}
```

Key output fields: `title`, `companyName`, `url`, `location`, `workplaceType`, `salaryMinYearly`, `publishedAt`, `description`.

Cost: pay per event — see the pricing section above and the **Pricing** tab. Cap each call with `maxItems` and, through the API, with the run option `maxTotalChargeUsd`.

### ❓ FAQ

#### Is it legal to scrape job postings from career pages?

The Actor only reads the job postings that companies publish on their public career pages for anyone to see. It logs in to nothing and solves no captcha. Results can contain personal data — the name of a recruiter (SmartRecruiters) and, with **Company contact e-mails**, the public e-mails and phone numbers of a company — which is protected by GDPR: do not store it without a legitimate reason. You are responsible for using the data in compliance with the Terms of Use of each career site and ATS and with applicable law. This Actor is not affiliated with Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Recruitee, Workable, Personio, BambooHR, Rippling, Teamtailor or the companies whose jobs it reads.

#### Does it need a login or a proxy?

No login, and no proxy by default. A request a site turns away is retried after a pause of 5 seconds, doubled at each retry up to 150 seconds. If your runs are rate-limited (many companies, frequent schedules), add a proxy in **Proxy configuration**: a refused request is then retried at once on a new proxy session, up to 10 times on top of the retries.

#### Is the data safe to open in Excel or to show on a web page?

Titles and descriptions are the companies' own words, copied as they are. A text can begin with `-`, `+`, `=` or `@`: Excel and Google Sheets may read such a cell of a CSV file as a formula or as a number. The Actor leaves the text as it is, so that the JSON and the API give the real value: when you open a CSV, import these columns as text. `descriptionHtml` is the HTML the ATS publishes, left as it is by the Actor (only cut past 200,000 characters): sanitize it before showing it on a web page, and escape every other field like any text written by a stranger.

#### Known limitations

- **Workday** shows at most 2,000 jobs per search: past that, the Actor splits the board by country, then by job family. If the pieces cannot cover the whole board, the log says that some jobs may be missing. On such a board, a run capped at 20 jobs or fewer without filters gets the first jobs of the career page; with a higher cap or filters, the jobs come from the pieces in no fixed order.
- **Workable** limits each IP to a few hundred requests a day. If a Workable board is still refused, the run goes on with the other boards and its log tells you to add a proxy or to run again the next day.
- With a single keyword, Workday, SmartRecruiters and Workable boards are searched for it on the ATS itself, and `companyOpenJobs` is then empty for them. Set `minOpenJobs` and the whole board is read so that it can be counted.
- **Workday** companies are found by name only when they are in the built-in directory: for another one, give its career page link.
- **Updated and taken-down jobs** are followed in 32 records of up to 4,000 jobs each, a company board always in the same record. Once a record is full, the next jobs put in it are not followed: they are never reported as updated or taken down, and the log warns once.
- `descriptionMaxLength` = 0 gives the full text up to 32,000 characters: a longer description is cut there.
- Fields detected from the job text are empty when the text does not say it: a job that names no degree has no `educationLevel`.
- `onlyNew` remembers job IDs: a job that changed comes back only with `includeUpdatedJobs`.
- Two runs sharing the same `stateKey` at the same time may both return the same new job.

**A run that reaches its timeout** stops itself about 45 seconds before it: no new page is asked, what it read is saved and, with **Only new jobs**, remembered, and the run ends *Succeeded* with "Stopped before the run's timeout". Resurrect it to go on from there, or give the next run a longer timeout (Run options).

**A run the platform stops without warning** (out of memory)

- Resurrect it: it goes on from where it stood at most a minute before the stop. What it had read since is read again, and the jobs already saved are skipped: none is delivered or charged twice, and `maxItems` still counts them.
- With `onlyNew`, the memory is saved after each write (at most once every 2 seconds): resurrect the stopped run and the jobs it had saved meanwhile join the memory; leave it stopped for good, and the next run may return the jobs of its last 2 seconds once more.

#### Something doesn't work?

The last line of the log counts the jobs saved and the requests that failed after every retry. Those requests, and the company names found on no ATS, are listed with the reason in the `FAILED_REQUESTS` record of the run's key-value store. A run that saved nothing and had failed requests fails, and its last message gives the cause.

If an ATS changes its job pages, you are told instead of paying for blank rows. If the first 20 listings read all lack their title, or their publication date on the nine ATS whose job list shows it (all but BambooHR and Rippling), the run saves nothing more, stops and fails, and its last message names the missing field: at most those first jobs are charged. A job that `postedAfter` / `postedBefore` drops because it has no date at all counts among those 20. A run of fewer jobs (a scheduled **Only new jobs** run that finds a few new ones, a small **Max jobs**) is checked at its end, from 5 listings: its jobs are already saved, and the run fails with the missing field instead of ending green.

### 🛟 Support

Open an issue in the **Issues** tab with a link to your run: the run log and the `FAILED_REQUESTS` record of the key-value store show exactly which companies or URLs failed and why.

# Actor input Schema

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

Company names, ATS slugs or website domains, one per line (e.g. `stripe`, `ramp`, `spotify`, `notion.so`). The Actor finds which ATS hosts each company (one quick check per ATS, see **ATS platforms**). Force the ATS with a prefix: `greenhouse:airbnb`, `lever:spotify`, `ashby:ramp`, `smartrecruiters:BoschGroup`, `workday:nvidia.wd5/NVIDIAExternalCareerSite`. A career page link works here too, with or without https://. A Workday company is found by name only when it is in our directory: otherwise give its career page link. Max 5 000.

## `startUrls` (type: `array`):

Career pages or job pages of any supported ATS, e.g. `https://job-boards.greenhouse.io/airbnb`, `https://jobs.lever.co/spotify`, `https://jobs.ashbyhq.com/ramp`, `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`, `https://jobs.smartrecruiters.com/BoschGroup`, `https://bunq.recruitee.com`, `https://apply.workable.com/huggingface`. A job URL returns the whole company board. Workday needs the full URL (tenant + site): the way to read a Workday company that is not in our directory. Max 5 000.

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

Also read the companies of our built-in directory (thousands of career sites found on the public web, filtered by **ATS platforms**, **Only these companies** and **Exclude companies**) and keep the jobs that match your keywords and filters. Use it to find jobs without knowing which companies hire. Capped by **Max companies from the directory**.

## `maxCompanies` (type: `integer`):

With **Search all companies**: how many directory companies to read, the largest boards first. 0 = the whole directory.

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

Only use these ATS: to detect the ATS of a company name, and to pick directory companies. Empty = all eleven.

## `query` (type: `string`):

Keep only the jobs whose title (or department / team) contains this word or phrase, e.g. `engineer`, `data scientist` (case and accents ignored). Tick **Search in description too** to also match the description. Empty = all jobs.

## `searchQueries` (type: `array`):

Several keywords in one run: a job is kept when it matches ANY of them (and **Job keyword**). Up to 100 here, plus **Job keyword**. Each job is saved once, with the keywords it matched in `matchedKeywords`.

## `searchInDescription` (type: `boolean`):

Match the keywords against the job description as well as the title. Needs the description: free for Greenhouse, Lever, Ashby, Recruitee, Personio and Teamtailor; for the other ATS it turns **Extract job details** on.

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

Keep only the jobs whose location (any of their locations) contains this text, e.g. `London`, `Germany`, `Remote` (case and accents ignored). Empty = everywhere.

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

Several locations: a job is kept when it matches ANY of them (and **Location**). Up to 100 here, plus **Location**.

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

Maximum number of jobs to save for the whole run (after deduplication and filters). 0 = no limit.

## `maxItemsPerQuery` (type: `integer`):

Cap for EACH company board, so that one big employer cannot use up the whole **Max jobs** budget. 0 = no per-company cap.

## `extractDetails` (type: `boolean`):

Open each job page (1 extra request per job) on the ATS whose job list has no description: Workday (description, exact posting date, country code, extra locations), SmartRecruiters (description, qualifications), Workable (description, requirements, benefits), BambooHR and Rippling. Greenhouse, Lever, Ashby, Recruitee, Personio and Teamtailor always come with the full description. Charged as a job with details (see Pricing).

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

Greenhouse, Ashby, Recruitee, Rippling and BambooHR: add the questions of the application form (label, type, required, choices) in `applicationQuestions`, plus the Greenhouse pay ranges. 1 extra request per Greenhouse, Ashby, Rippling or BambooHR job; charged per job that has questions (see Pricing).

## `descriptionFormat` (type: `string`):

Which description fields to save: plain text (`description`), the HTML of the ATS (`descriptionHtml`), both, or none (lighter dataset).

## `descriptionMaxLength` (type: `integer`):

Cut the plain-text `description` to this many characters (ending with `…`); `descriptionHtml` is not cut by this setting, only past 200 000 characters. 0 = the full text, up to 32 000 characters.

## `includeCompanySummary` (type: `boolean`):

Also write one summary per company with jobs in the results, counted on the jobs this run delivered (after the filters, Max jobs and Only new jobs; only the open jobs of the whole board are counted before the filters): open jobs, jobs per department, country, workplace type, seniority and contract type, share of remote jobs, jobs posted in the last 7 / 30 days, new and closed since the last run (with **Only new jobs**), salary range. Saved in the key-value store record `COMPANY_SUMMARIES` (linked in the Output tab). Charged per company summary written (see Pricing). If the maximum cost of the run is reached by the jobs, some summaries can be left out; the end message says how many.

## `enrichEmails` (type: `boolean`):

For each company whose website is known (the domain you typed in **Companies**, Ashby's company profile, or the company's own careers page linked by Greenhouse / Recruitee), read its contact / about pages and add the public e-mail addresses (`companyEmails`), phone numbers (`companyPhones`) and social links such as LinkedIn (`companySocialLinks`) found there. Charged once per company with at least one e-mail found (see Pricing); phone numbers and social links alone are free.

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

Keep only remote, hybrid and / or on-site jobs, read from the ATS field when there is one, otherwise from the location and title (`workplaceType`). Empty = all.

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

Adds Remote to **Workplace type**: alone, it keeps the remote jobs only; with Hybrid or On-site ticked there too, it keeps those as well.

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

Keep only these contract types (normalized from the ATS value, otherwise read in the title, see `employmentType`). Jobs whose type is found neither on their ATS nor in their title are dropped when this list is not empty. Empty = all.

## `seniority` (type: `array`):

Keep only the jobs of these levels, from the ATS experience level when there is one, otherwise from the job title (see `seniority`). Jobs with no level are dropped when this list is not empty. Empty = all.

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

Keep only the jobs whose department, team or job function contains one of these words, e.g. `Engineering`, `Sales` (case ignored). Workday gives no department: its jobs are dropped once this list is set. Empty = all.

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

Keep only the jobs located in these countries: ISO codes (`US`, `GB`, `DE`) or English names. A job with several locations is kept when one of them matches. Jobs whose country cannot be read are dropped when this list is not empty.

## `excludeLocations` (type: `array`):

Drop the jobs whose every location contains one of these words (case and accents ignored). On Workday, SmartRecruiters, Workable, BambooHR and Rippling, a job whose list entry shows no location is checked on its job page (1 extra request; charged as a filter check only if the job is dropped).

## `includeCompanies` (type: `array`):

Keep only the jobs of companies whose name or slug contains one of these words (case ignored). Most useful with **Search all companies**.

## `excludeCompanies` (type: `array`):

Drop the jobs of companies whose name or slug contains one of these words (e.g. staffing agencies).

## `skills` (type: `array`):

Keep only the jobs that name at least one of these skills in the title or description (e.g. `Python`, `Salesforce`, `Kubernetes`; case ignored, whole words). Read from `skills` and the description.

## `languages` (type: `array`):

Keep only the jobs written in these languages, ISO 639-1 codes (`en`, `de`, `fr`…): from the ATS field when there is one, otherwise detected from the description (`language`). Empty = all.

## `maxYearsExperience` (type: `integer`):

Keep only the jobs that ask at most this many years of experience (`minYearsExperience`, read from the description); jobs that write no number are kept. On Workday, SmartRecruiters, Workable, BambooHR and Rippling, whose job list has no description, the job page of each job is read for it (1 extra request; charged as a filter check only if the job is dropped). 0 = no limit.

## `minOpenJobs` (type: `integer`):

Keep only the jobs of companies that have at least this many open jobs on their board (`companyOpenJobs`, counted before your filters). 0 = all companies.

## `visaSponsorshipOnly` (type: `boolean`):

Keep only the jobs that say they sponsor visas (`visaSponsorship` = true).

## `onlyWithSalary` (type: `boolean`):

Keep only the jobs that show a salary: the pay range of the ATS, or an amount written in the description.

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

Keep only the jobs whose yearly salary (top of the range, hourly / monthly pay converted to a year) reaches this amount in **Salary currency**. Jobs in another currency, or without a salary, are dropped. 0 = no minimum.

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

Currency of **Minimum yearly salary**, ISO code (`USD`, `EUR`, `GBP`…).

## `maxSalary` (type: `integer`):

Keep only the jobs whose yearly salary (bottom of the range, converted to a year) is at most this amount in **Salary currency**. Jobs in another currency, or without a salary, are dropped (unless **Keep jobs without a salary**). 0 = no maximum.

## `keepJobsWithoutSalary` (type: `boolean`):

With **Minimum yearly salary**: also keep the jobs that publish no salary (only the jobs whose published salary is too low, or in another currency, are dropped).

## `postedAfter` (type: `string`):

Only jobs published on or after this date: `2026-09-01`, or a period before now such as `7 days`, `24 hours`, `2 weeks`. The date read is `publishedAt` (Workday without details: the day shown as `Posted N Days Ago`; `30+ Days Ago` counts as 30 days, unless a date bound is more than 30 days ago: then the page of each such job is opened for its exact date, 1 extra request per job, not charged as **Extract job details**). Jobs without a date are dropped.

## `postedBefore` (type: `string`):

Only jobs published on or before this date (the whole day is included), or older than a period such as `30 days`.

## `updatedAfter` (type: `string`):

Only jobs updated on their ATS on or after this date, or within a period such as `3 days` (`updatedAt`; jobs whose ATS gives no update date are compared on `publishedAt`).

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

Drop the jobs whose title contains one of these whole words (case and accents ignored), e.g. `intern`, `sales`; the description is checked too with **Search in description too**.

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

Skip the jobs that a previous run (same **Memory key**) already delivered: they are not saved and not charged. First run = everything is new.

## `includeClosedJobs` (type: `boolean`):

With **Only new jobs**: also save, once, each job delivered by a previous run (same **Memory key**, with this box ticked) that is no longer on its company board, with `status` = `closed` and `closedAt`. Charged as a closed job, not as a job. Nothing is reported for a company board the run could not read in full.

## `includeUpdatedJobs` (type: `boolean`):

With **Only new jobs**: also save again a job already delivered when its content changed since (title, locations, salary, description, dates...), with `status` = `updated`. Charged as a job.

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

Name of the memory used by **Only new jobs**. Give each schedule / task its own key (e.g. `fintech-engineers`) so that they do not share their memory. Letters, digits, `-` and `_`.

## `resetState` (type: `boolean`):

Forget everything remembered under this **Memory key** before the run: this run returns (and charges) every job again. Untick it afterwards.

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

Optional. Leave empty: the Actor reads the public job APIs directly. Add a proxy if your runs are rate-limited.

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

Maximum number of requests processed in parallel (all ATS together).

## `maxRequestsPerMinute` (type: `integer`):

Most requests in any 60 seconds, all ATS counted. Lever is always kept at 1 request per second at most. Lower it if the log shows HTTP 429.

## `minRequestIntervalMs` (type: `integer`):

Smallest gap between two requests, in milliseconds. 0 = no gap.

## `maxRequestRetries` (type: `integer`):

Retries per request before it is marked as failed.

## `debugLog` (type: `boolean`):

Include debug messages in the run log.

## Actor input object example

```json
{
  "companies": [
    "stripe",
    "ramp",
    "spotify"
  ],
  "startUrls": [],
  "searchAllCompanies": false,
  "maxCompanies": 500,
  "atsPlatforms": [],
  "searchQueries": [],
  "searchInDescription": false,
  "locations": [],
  "maxItems": 100,
  "maxItemsPerQuery": 0,
  "extractDetails": false,
  "includeApplicationQuestions": false,
  "descriptionFormat": "both",
  "descriptionMaxLength": 0,
  "includeCompanySummary": false,
  "enrichEmails": false,
  "workplaceTypes": [],
  "remoteOnly": false,
  "employmentTypes": [],
  "seniority": [],
  "departments": [],
  "countries": [],
  "excludeLocations": [],
  "includeCompanies": [],
  "excludeCompanies": [],
  "skills": [],
  "languages": [],
  "maxYearsExperience": 0,
  "minOpenJobs": 0,
  "visaSponsorshipOnly": false,
  "onlyWithSalary": false,
  "minSalary": 0,
  "salaryCurrency": "USD",
  "maxSalary": 0,
  "keepJobsWithoutSalary": false,
  "excludeKeywords": [],
  "onlyNew": false,
  "includeClosedJobs": false,
  "includeUpdatedJobs": false,
  "stateKey": "default",
  "resetState": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "maxConcurrency": 10,
  "maxRequestsPerMinute": 600,
  "minRequestIntervalMs": 0,
  "maxRequestRetries": 5,
  "debugLog": false
}
```

# Actor output Schema

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

No description

## `companySummaries` (type: `string`):

One summary per company read (open jobs, departments, locations, salary ranges), filled when includeCompanySummary is on.

# 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": [
        "stripe",
        "ramp",
        "spotify"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

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

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

```

## MCP server setup

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