# Career Site Jobs: Greenhouse, Lever, Ashby & more (`liora-tools/ats-career-site-jobs`) Actor

Get every open job from company career sites powered by Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee through their official public job-board APIs. Normalized output, filters, salary where published, and 'only new jobs' monitoring. No proxies, no login.

- **URL**: https://apify.com/liora-tools/ats-career-site-jobs.md
- **Developed by:** [Liora Blyth](https://apify.com/liora-tools) (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

from $2.00 / 1,000 job saveds

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

## Career Site Jobs Scraper — Workday, Greenhouse, Lever, Ashby, Personio & more, with Salaries

Get **every open job from any company's career site** (now including **Workday** and **Personio**) in one clean, normalized dataset, straight from the
**official public job-board APIs** that these applicant-tracking systems (ATS) publish for embedding job listings.
No browser, no proxies, no login, and no CAPTCHA, so runs are fast, cheap and reliable.

### Quick start

1. Paste career-site URLs (or `greenhouse:stripe`-style slugs) into **Companies**.
2. Optionally add title keywords, locations or `remoteOnly`.
3. Click **Start**. Download the jobs as JSON, CSV, Excel, or pull them via the Apify API.
4. Schedule the run daily with `onlyNewJobs: true` to get only fresh postings (e.g. into Slack, Google Sheets or a webhook via Apify integrations).

### What you can do with it

- Track hiring at competitors or target accounts (sales signals, market research).
- Build niche job boards or newsletters (e.g. "remote AI engineering jobs").
- Get alerts for **new jobs only** on scheduled runs (built-in state, no duplicates).
- Feed job descriptions into LLMs or RAG pipelines (plain text or HTML).

### Supported ATS

| ATS | Example input |
|---|---|
| Greenhouse | `https://boards.greenhouse.io/stripe` or `greenhouse:stripe` |
| Lever | `https://jobs.lever.co/palantir` or `lever:palantir` |
| Ashby | `https://jobs.ashbyhq.com/openai` or `ashby:openai` |
| Workable | `https://apply.workable.com/huggingface` or `workable:huggingface` |
| SmartRecruiters | `https://jobs.smartrecruiters.com/BoschGroup` or `smartrecruiters:BoschGroup` |
| Recruitee | `https://bunq.recruitee.com` or `recruitee:bunq` |
| Personio | `https://acme.jobs.personio.de` or `personio:acme` |
| Workday | `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite` (full career-site URL) |

Workday career sites are read through the same public JSON endpoint the career site itself uses, only when the
site's robots.txt allows it, and at a polite pace. Title keywords are sent to Workday's own search, so large
Workday sites stay fast.

**Preset lists:** add `"presetLists": ["ai-companies"]` or `["big-tech-startups"]` to include ready-made,
verified boards (OpenAI, Anthropic, Databricks, Cohere, Scale AI, Perplexity, ElevenLabs / Stripe, Airbnb, Figma,
Discord, Dropbox, Reddit, Notion, Ramp, Linear, Palantir).

A **bare slug** (e.g. `notion`) is auto-detected by trying each ATS in turn.

### Input

```json
{
  "companies": ["https://boards.greenhouse.io/stripe", "lever:palantir", "ashby:openai", "notion"],
  "titleKeywords": ["engineer", "data"],
  "excludeTitleKeywords": ["intern"],
  "locations": ["remote", "london"],
  "remoteOnly": false,
  "postedWithinDays": 30,
  "includeDescription": true,
  "descriptionFormat": "text",
  "onlyNewJobs": false,
  "maxJobsPerCompany": 0
}
```

| Field | Meaning |
|---|---|
| `companies` (required) | Career-site URLs, `ats:slug`, or bare slugs |
| `titleKeywords` / `excludeTitleKeywords` | Case-insensitive title filters |
| `locations`, `departments` | Substring filters on location or department/team |
| `remoteOnly` | Keep only jobs flagged remote |
| `postedWithinDays` | Keep jobs published in the last N days (when the ATS exposes a date) |
| `includeDescription`, `descriptionFormat` | `text`, `html` or `both` |
| `onlyNewJobs`, `stateKey` | Output only jobs not seen in earlier runs with the same `stateKey` |
| `maxJobsPerCompany` | 0 = unlimited |
| `maxConcurrency` | Companies fetched in parallel (1–10) |
| `presetLists` | Ready-made company lists added to `companies` |
| `descriptionKeywords` | Match words in the title **or the full description** (e.g. `Python`, `Kubernetes`) |
| `workplaceTypes` | `remote`, `hybrid`, `onsite` |
| `employmentTypes` | Substring match on the ATS employment type (`Full`, `Part`, `Contract`, `Intern`) |
| `seniorityLevels` | `intern`, `junior`, `mid`, `senior`, `lead/manager`, `principal/staff`, `director+` (from the title) |
| `minSalary`, `onlyWithSalary` | Salary filters using the ATS salary field, Greenhouse pay ranges or a salary range found in the description (hourly/monthly converted to yearly; currency not converted) |
| `onlyVisaSponsorship` | Keep jobs whose description says visa sponsorship is offered |
| `includeApplicationQuestions` | Greenhouse application questions (labels and types only) and pay-transparency ranges |
| `maxItems` | Total cap across all companies |

### Output (one item per job)

```json
{
  "ats": "ashby", "companySlug": "openai", "company": "openai",
  "jobId": "240d459b-…", "title": "Research Engineer",
  "department": "Research", "team": "Research",
  "location": "San Francisco", "isRemote": false, "workplaceType": null,
  "employmentType": "FullTime", "publishedAt": "2025-04-05T00:03:20+00:00",
  "url": "https://jobs.ashbyhq.com/openai/240d459b-…",
  "applyUrl": "https://jobs.ashbyhq.com/openai/240d459b-…/application",
  "compensation": {"summary": "$250K – $445K • Offers Equity"},
  "salary": {"min": 250000, "max": 445000, "currency": "USD", "interval": "year", "source": "ats summary"},
  "seniority": "mid", "visaSponsorship": null,
  "descriptionText": "…", "isNew": null, "scrapedAt": "2026-10-21T09:34:09+00:00"
}
```

See `sample_output.json` for 18 real items. A `RUN_SUMMARY` record in the default key-value store lists
companies processed, failed inputs, and job counts.

### Pricing (pay per event)

| Event | Price |
|---|---|
| Job in the dataset (`job`) | **$0.002** ($2 per 1,000 jobs) |
| Actor start | $0.00005 (Apify default) |

- Failed companies and filtered-out jobs are free.
- Examples: 500 jobs ≈ $1.00; a daily new-jobs monitor that finds 20 new jobs/day ≈ $1.20/month.
- Set **Maximum cost per run** to cap your spend. The Actor stops cleanly when the cap is reached.

### Performance

Measured locally on 2026-10-21: 7 companies, 1,898 matching jobs (with full descriptions) in about 1 min 47 s.
18 jobs from 6 companies in about 30 s (large SmartRecruiters boards take longer because of paging).

### Privacy and legal notes

- Uses only the **public, unauthenticated job-board endpoints** the ATS vendors document for publishing jobs.
- No personal data is collected as fields. Recruiter or contact e-mails and phone numbers found in descriptions are
  **masked** (`[email removed]`, `[phone removed]`). Recruitee's `mailbox_email` field is dropped.
  Descriptions are the employer's own published text and may still mention a contact person's name.
- You are responsible for how you use the data (e.g. GDPR if you combine it with other data).

### FAQ

**A company isn't found.** Check the career-site URL; many companies use custom domains that embed one of these
ATSs. Look for `greenhouse.io`, `lever.co`, `ashbyhq.com` etc. in the apply link, and pass that slug.
**Workday?** Supported: pass the full `myworkdayjobs.com` career-site URL. Workday sites are skipped when their robots.txt disallows the endpoint.

**iCIMS / Taleo / SuccessFactors?** Not supported yet. Open an issue if you need them.

**Do I need proxies or an account?** No. All endpoints are public and the Actor runs on plain datacenter IPs.

**How fresh is the data?** Live: every run reads the ATS at run time.

**Can I get only new jobs?** Yes. `onlyNewJobs: true` with a fixed `stateKey` stores seen job ids in a named key-value store, so each scheduled run outputs only postings it has not seen before.

# Actor input Schema

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

One per line. Accepts a careers board URL (e.g. https://boards.greenhouse.io/stripe, https://jobs.lever.co/palantir, https://jobs.ashbyhq.com/openai, https://apply.workable.com/huggingface, https://jobs.smartrecruiters.com/BoschGroup, https://bunq.recruitee.com), an explicit 'ats:slug' (greenhouse:stripe), a Personio board (https://acme.jobs.personio.de), a Workday career site (https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite), or a bare slug (we try each ATS automatically).

## `presetLists` (type: `array`):

Add ready-made lists of verified public job boards to your own companies.

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

Case-insensitive. Leave empty for all jobs.

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

E.g. 'intern', 'senior'.

## `descriptionKeywords` (type: `array`):

Searches the full job description too (e.g. 'Python', 'Kubernetes'). Descriptions are loaded automatically.

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

Matched against the main and secondary locations, e.g. 'London', 'Germany', 'Remote'.

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

Matched against department and team names, e.g. 'Engineering', 'Sales'.

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

Keep only postings the ATS marks as remote, or whose location says 'Remote'.

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

Keep only remote, hybrid and/or on-site jobs (as reported by the ATS or stated in the location).

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

E.g. 'Full', 'Part', 'Contract', 'Intern'. Matched against the ATS employment type.

## `seniorityLevels` (type: `array`):

Detected from the job title.

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

Keeps jobs whose published salary (ATS field or salary range in the description) starts at or above this amount per year. Hourly and monthly pay are converted. Currency is not converted.

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

Only jobs with a published salary.

## `onlyVisaSponsorship` (type: `boolean`):

Rule-based check of the description.

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

Uses the publish date reported by the ATS (not available for every ATS).

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

Adds the full job description (PII such as e-mails/phones is masked).

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

Plain text is best for LLMs and spreadsheets.

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

Adds the application form questions (labels and types only) and Greenhouse pay-transparency ranges. One extra request per Greenhouse job.

## `onlyNewJobs` (type: `boolean`):

Turn on for scheduled monitoring: each run returns only postings that appeared since the last run with the same state key.

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

Use different keys for different watchlists.

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

0 = no limit.

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

Higher is faster; boards are fetched politely with one request stream each.

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

Stop after this many jobs across all companies (0 = no limit).

## Actor input object example

```json
{
  "companies": [
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/palantir",
    "ashby:openai"
  ],
  "presetLists": [],
  "titleKeywords": [],
  "excludeTitleKeywords": [],
  "descriptionKeywords": [],
  "locations": [],
  "departments": [],
  "remoteOnly": false,
  "workplaceTypes": [],
  "employmentTypes": [],
  "seniorityLevels": [],
  "onlyWithSalary": false,
  "onlyVisaSponsorship": false,
  "includeDescription": true,
  "descriptionFormat": "text",
  "includeApplicationQuestions": false,
  "onlyNewJobs": false,
  "stateKey": "default",
  "maxJobsPerCompany": 0,
  "maxConcurrency": 5,
  "maxItems": 0
}
```

# Actor output Schema

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

Job postings saved by this run (one dataset item each).

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "companies": [
        "https://boards.greenhouse.io/stripe",
        "https://jobs.lever.co/palantir",
        "ashby:openai"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("liora-tools/ats-career-site-jobs").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "companies": [
        "https://boards.greenhouse.io/stripe",
        "https://jobs.lever.co/palantir",
        "ashby:openai",
    ] }

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

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "companies": [
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/palantir",
    "ashby:openai"
  ]
}' |
apify call liora-tools/ats-career-site-jobs --silent --output-dataset

```

## MCP server setup

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

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/DgXURgrN6tV5hA8vT/builds/M95yEA1hTfMLIou1L/openapi.json
