# Careers Page Jobs Scraper: Greenhouse, Lever, Workday & Ashby (`cleanrowdata/careers-jobs-feed`) Actor

Scrape every open job from any company careers page on Greenhouse, Lever, Ashby, Workday, SmartRecruiters or Workable. Paste URLs or names, ATS auto-detected. Full descriptions, salary, and a new/closed jobs feed for hiring signals. Live data, no login, $2 per 1,000 jobs.

- **URL**: https://apify.com/cleanrowdata/careers-jobs-feed.md
- **Developed by:** [Clean Row Data](https://apify.com/cleanrowdata) (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 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/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

## Careers Page Jobs Scraper: Greenhouse, Lever, Workday, Ashby, SmartRecruiters & Workable jobs API

**Scrape every open job from any company's careers page, with full descriptions and salary, in one clean schema.** Paste careers URLs, ATS board links or just company names; the Actor **auto-detects the applicant tracking system (ATS)** and reads the company's official public job feed live: **Greenhouse, Lever, Ashby, Workday, SmartRecruiters and Workable**. Schedule it with **Changes only** and you get just the **new and closed jobs** since the last run, a ready-made **hiring-signal feed** for recruiting and sales.

- ✅ **6 ATS platforms in one Actor**: no need to run a separate Greenhouse scraper, Lever scraper and Workday scraper
- ✅ **ATS auto-detection** from any careers URL, `ats:token`, or a plain company name
- ✅ **Full job descriptions** (plain text and HTML), department, team, locations, remote flag, employment type, posted date, apply URL
- ✅ **Salary**: structured pay ranges (Lever, Ashby) plus pay-transparency ranges extracted from descriptions (Workday, Greenhouse, SmartRecruiters...)
- ✅ **New / closed jobs feed**: `status` = `new` / `active` / `closed`, plus `first_seen`, `last_seen` and `closed_at`
- ✅ **Workday done right**: gets past Workday's 2,000-result cap and fills `department` from Workday's Job Category
- ✅ **Live data**: every run reads the boards at that moment. Official public job-board feeds, no login, no proxies, no browser
- ✅ **$2 per 1,000 jobs** + $0.002 per company checked

### Quick start (first run in seconds)

1. Click **Start**. The prefilled input checks **Airbnb (Greenhouse), Spotify (Lever) and Linear (Ashby)** and returns up to **25 jobs per company** (about 75 rows, usually in under 10 seconds, about $0.16).
2. Replace the companies with your own: careers URLs (`https://boards.greenhouse.io/stripe`), Workday URLs (`https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`) or names (`notion`).
3. Set **Max jobs per company** to 0 for every job, add keyword/location filters, and export to CSV, Excel, JSON or Google Sheets, or use the API.

### Use cases and ready-to-paste inputs

#### 1. Sales teams: hiring signals on your target accounts

"Company X just opened 12 data-engineering roles" is a buying signal. Track your account list and get only the new roles every day.

```json
{
  "companies": ["https://boards.greenhouse.io/stripe", "https://jobs.ashbyhq.com/ramp", "notion"],
  "keywords": ["data", "security", "revenue operations"],
  "changesOnly": true,
  "feedKey": "my-target-accounts"
}
```

#### 2. Recruiting and staffing agencies: watch client and target companies

Get alerted the moment target accounts open roles that fit your candidates, with the full description to match on skills.

```json
{
  "companies": ["https://jobs.lever.co/spotify", "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"],
  "keywords": ["engineer"],
  "locations": ["United States", "Remote"],
  "postedSince": "7 days"
}
```

#### 3. Job boards and aggregators: a niche board that stays fresh

Daily changes-only run over your company list: insert `new` rows, delete `closed` rows.

```json
{
  "companies": ["https://jobs.ashbyhq.com/linear", "https://apply.workable.com/huggingface", "https://jobs.smartrecruiters.com/ServiceNow"],
  "remoteOnly": true,
  "changesOnly": true
}
```

#### 4. Labor-market, HR and compensation research

Department mix, location mix, remote share and published salary ranges across a set of employers.

```json
{
  "companies": ["airbnb", "https://jobs.lever.co/palantir", "https://boards.greenhouse.io/figma"],
  "includeDescriptionHtml": false,
  "trackState": false
}
```

#### 5. AI agents and RAG

Clean, consistent JSON with plain-text descriptions, ready for LLMs. Works through the Apify MCP server.

### Sample output

Real rows from October 2026 runs (descriptions omitted here; every row also has `description_text` and `description_html`). Download the full example dataset from the prefilled input (76 jobs from Airbnb, Spotify and Linear): [CSV](https://api.apify.com/v2/datasets/AUfNqhoeRd7Zji44y/items?format=csv) · [JSON](https://api.apify.com/v2/datasets/AUfNqhoeRd7Zji44y/items?format=json) · [Excel](https://api.apify.com/v2/datasets/AUfNqhoeRd7Zji44y/items?format=xlsx).

| Company | ATS | Title | Department | Location | Remote | Salary | Posted |
|---|---|---|---|---|---|---|---|
| Airbnb | Greenhouse | Senior Partnership Manager | Partnerships | United States | yes | $157,000—$185,000 USD | 2026-10-16 |
| Airbnb | Greenhouse | Staff Data Engineer, Tech Foundations | Engineering & Technology | San Francisco, CA | yes | | 2026-10-16 |
| Spotify | Lever | Senior Machine Learning Engineer, Personalization | Engineering | New York, NY | yes | 184,049–262,928 USD, plus equity | 2026-10-14 |
| Linear | Ashby | Senior / Staff Security Engineer | Product | North America | yes | | 2026-10-15 |
| Nvidia | Workday | Sales Operations Analyst | Sales | US, CA, Santa Clara | no | 92,000 USD - 143,750 USD | 2026-10-16 |
| Stripe | Greenhouse | Solutions Engineer, AI Build Team | 1650 AI GTM Strategy & Solutions | US-SF, US-NYC, US-Remote | yes | | 2026-10-16 |

#### Each row as JSON

```json
{
  "company": "Airbnb",
  "ats": "greenhouse",
  "board_token": "airbnb",
  "job_id": "8282351",
  "requisition_id": "ONE",
  "title": "Senior Partnership Manager",
  "department": "Partnerships",
  "team": null,
  "location": "United States",
  "locations": ["United States"],
  "country": null,
  "remote": true,
  "workplace_type": "remote",
  "employment_type": "FULL_TIME",
  "employment_type_raw": null,
  "posted_at": "2026-10-16T19:59:45Z",
  "updated_at": "2026-10-16T19:59:45Z",
  "apply_url": "https://careers.airbnb.com/positions/8282351?gh_jid=8282351",
  "job_url": "https://careers.airbnb.com/positions/8282351?gh_jid=8282351",
  "salary_min": 157000,
  "salary_max": 185000,
  "salary_currency": "USD",
  "salary_period": "YEAR",
  "salary_text": "$157,000—$185,000 USD",
  "salary_source": "description",
  "description_text": "Airbnb was born in 2007 when two hosts welcomed three guests ...",
  "description_html": "<div class=\"content-intro\"><p>Airbnb was born in 2007 ...",
  "status": "new",
  "first_seen": "2026-10-17T04:00:33Z",
  "last_seen": "2026-10-17T04:00:33Z",
  "closed_at": null,
  "input": "https://boards.greenhouse.io/airbnb",
  "scraped_at": "2026-10-17T04:00:33Z"
}
```

Every row has the same columns whatever the source system, so you can export to CSV, Excel, JSON or Google Sheets, or pull it through the API. The dataset has three ready-made views: **Overview**, **Changes (new / closed)** and **Salary**. Each run also writes a `RUN_SUMMARY` record. It lists, per company, the detected ATS, how many jobs are on the board, the emitted/new/closed counts and any error.

Notes on fields:

- `employment_type` is normalized to `FULL_TIME`, `PART_TIME`, `CONTRACT`, `INTERNSHIP`, `TEMPORARY` or `OTHER`. The original value is kept in `employment_type_raw`.
- `salary_source` is `ats` when the system provides structured pay. It's `description` when the range was extracted from a pay-transparency statement in the job text.
- All dates are ISO 8601 in UTC.

### Supported systems and what to paste

| System | Example input | How it's fetched |
|---|---|---|
| Greenhouse | `https://boards.greenhouse.io/stripe`, `https://job-boards.greenhouse.io/figma`, `greenhouse:airbnb` | Official Job Board API (`boards-api.greenhouse.io`) |
| Lever | `https://jobs.lever.co/spotify`, `jobs.eu.lever.co/...`, `lever:palantir` | Official Postings API (`api.lever.co/v0/postings`) |
| Ashby | `https://jobs.ashbyhq.com/ramp`, `ashby:notion` | Official public Job Posting API (with compensation) |
| Workday | `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite` | Public careers-site JSON (the same feed the careers page uses) |
| SmartRecruiters | `https://jobs.smartrecruiters.com/ServiceNow`, `smartrecruiters:BoschGroup` | Official public Posting API |
| Workable | `https://apply.workable.com/huggingface`, `workable:skroutz` | Public jobs widget API |

You can also paste:

- a **plain company name or slug** such as `stripe`. We probe Greenhouse, Lever, Ashby, Workable and SmartRecruiters and pick the board with jobs.
- a **company's own careers page** such as `https://www.example.com/careers`. We look for an embedded or linked ATS board.
- a **display name** such as `Acme Corp | https://jobs.lever.co/acme`, to set the `company` column.

Workday always needs the full `myworkdayjobs.com` URL, because tenant and site names can't be guessed.

**Filters** are optional and combine with AND. Each list matches *any* of its values, case-insensitive and on whole words, so `intern` doesn't match `internal`.

- `keywords` / `excludeKeywords` match the job title. Turn on `keywordsInDescription` to also search descriptions.
- `locations` match any of the job's locations or its country. `Remote` also matches jobs flagged remote.
- `departments` match the department or team. For Workday this is the Job Category.
- `postedSince` takes a date (`2026-10-01`) or a relative period (`24 hours`, `7 days`, `2 weeks`).

### Changes-only mode (daily new/closed feed)

Turn on **Changes only** and schedule the Actor (for example daily). Each run emits:

- `status: "new"` for jobs that weren't on the board at the previous run of this feed
- `status: "closed"` for jobs that disappeared since the previous run, with `closed_at` set

Jobs that are still open aren't emitted again, so you don't pay for them.

History is stored per company as a small record in a **named key-value store** in your Apify account (default `careers-jobs-feed-state`). Use a different **State store name** or **Feed key** for each independent feed, for example one per client or per filter set.

How state behaves:

- **First run:** the first run for a company emits all current jobs as `new`. Turn off `firstRunEmitsAll` to record a silent baseline instead.
- **Failed fetches:** if a company can't be fetched in a run, its state isn't touched, so nothing is falsely reported as closed.
- **Filters:** only jobs that match your filters are tracked. If you change the filters, previously excluded jobs are re-evaluated.
- **Full mode:** without Changes only, every run returns all matching jobs, still with `status`, `first_seen` and `last_seen`. Turn off **Track state** for one-off exports.

### How it compares

| | **Careers Page Jobs Scraper (this Actor)** | [Fresh Jobs API](https://apify.com/cleanrowdata/fresh-jobs-index) (our jobs index) | LinkedIn / Indeed job scrapers | Single-ATS scrapers |
|---|---|---|---|---|
| Best for | Companies you already know | Discovering jobs across 17,000+ companies by title/location | Job-board search | One ATS only |
| Source | Employer's own ATS, read live | Employer's own ATS, index refreshed hourly (Workday daily) | Job board listings, reposts | One ATS |
| ATS platforms | 6, auto-detected | 9 | n/a | 1 |
| Full descriptions | ✅ | ❌ not yet | ✅ | usually ✅ |
| Salary | ✅ structured + extracted from text | ✅ when structured | varies | varies |
| New / closed jobs | ✅ per-company diff | ✅ time windows + closed in last 7 days | partial | rarely |
| Login / proxies | none | none | often | none |
| Price | $2 / 1,000 jobs + $0.002 per company | $2.50 / 1,000 jobs | varies | varies |

Don't know which companies to watch yet? Search by title and location across 1.17M jobs with the [Fresh Jobs API](https://apify.com/cleanrowdata/fresh-jobs-index), then track the companies you find here.

### Pricing (pay per event)

| Event | Price |
|---|---|
| Job row in the dataset (new, active or closed) | **$0.002** (= **$2 per 1,000 jobs**) |
| Company checked (per company per run; boards with more than 1,000 open jobs count once per 1,000 jobs on the board) | **$0.002** |
| Actor start (Apify's standard start event) | $0.00005 |

Examples:

- **First run with the prefilled input:** 3 companies × 25 jobs = 75 jobs, which costs $0.15 + $0.006 = **about $0.16**.
- **One-off export:** 50 companies × 200 jobs = 10,000 jobs, which costs $20.00 + $0.10 = **$20.10**.
- **Daily changes-only feed:** 200 companies with about 150 new/closed jobs a day, which costs $0.40 + $0.30 = **about $0.70 a day**.

You never pay for jobs filtered out by your filters. Set **Max jobs per run** or the run's maximum cost to stay within budget. The Actor stops cleanly when the limit is reached.

### Tips for fast, cheap runs

- Use **Changes only** for scheduled feeds.
- For big **Workday** and **SmartRecruiters** employers, descriptions need one request per job. Turn off **Include job descriptions** if you only need titles, locations and links. Changes-only mode already fetches descriptions just for new jobs.
- Use the **Max jobs per company** and **Posted since** filters for quick samples.

### FAQ

**Is this legal? Do you scrape behind logins?**
No logins, no captcha or block bypassing, no proxies. The Actor only reads the public job-board feeds that companies publish so their jobs can be found and syndicated. Most of these are official, documented APIs: Greenhouse Job Board API, Lever Postings API, Ashby Job Posting API and SmartRecruiters Posting API. Workday and Workable data comes from the same public JSON their careers pages load. We don't collect recruiter names or contact details. See *Responsible use* below.

**How fresh is the data?**
Live: every run reads the boards at that moment.

**Is it a LinkedIn jobs alternative?**
For the companies you track, yes: companies publish on their own ATS first, the data is cleaner (no reposts or promoted listings) and the apply link goes straight to the employer. It won't find jobs that exist only on LinkedIn.

**How do I find the right careers URL?**
Open any job on the company's careers site: the address usually contains `greenhouse.io`, `lever.co`, `ashbyhq.com`, `myworkdayjobs.com`, `smartrecruiters.com` or `workable.com`. Paste that link. Or just paste the company name and let the Actor probe.

**Why did a company return "not found"?**
The board token or URL doesn't exist on that system, or the company moved to another ATS. Paste the URL of a job on their careers site. `RUN_SUMMARY` shows what was detected for each input.

**One company failed. Did the run fail?**
No. Each company is isolated. A bad URL, a typo or a site outage never stops the run: the company is retried with exponential backoff and, if it still fails, it's reported in the **Run summary** (the `RUN_SUMMARY` record, linked from the run's Output tab) with `status` = `not_found` or `error` and a readable `error` message, while the others continue.

- `error` (timeouts, HTTP 5xx, Workday maintenance windows): not charged, history untouched, just run it again later.
- `not_found` (the board doesn't exist, or the URL isn't a supported careers page): counts as one *company checked* event, because the lookup was done.

**Workday says 2,000 jobs. Do I get them all?**
Yes, in nearly all cases. Workday's search stops at 2,000 results, so the Actor automatically splits the search by Workday's own facets (job category, location and so on) and de-duplicates. In the rare case a board still can't be fully listed, a warning is logged and closed-job detection is paused for that board, so you get no false "closed" rows.

**Can I get jobs from companies on other systems (iCIMS, Taleo, SuccessFactors, Teamtailor, Recruitee, Personio...)?**
Not in this Actor yet. Recruitee, Personio and Rippling jobs are searchable in the [Fresh Jobs API](https://apify.com/cleanrowdata/fresh-jobs-index). Tell us in the Issues tab which systems you need.

**Can I use it from code, Make, Zapier, n8n, Clay or an AI agent?**
Yes. Use the Apify API, any Apify integration or the Apify MCP server. Input and output are fully described by schemas.

### Limits

- **Supported systems:** Greenhouse, Lever, Ashby, Workday, SmartRecruiters and Workable. Other systems (iCIMS, Taleo, SuccessFactors, Teamtailor, Recruitee, Personio...) return `not_found`.
- **Workday** needs the full `*.myworkdayjobs.com` careers URL. Workday sites have weekly maintenance windows (often on weekends); during one, the company is reported as `error` (not charged) and its history is kept.
- **Speed:** Greenhouse, Lever, Ashby and Workable return all jobs in one or a few requests (seconds per company). Workday and SmartRecruiters need one extra request per job for the description, so a 2,500-job Workday board takes about 5-12 minutes with descriptions (Workday rate-limits busy tenants and the Actor slows down to match), or 1-2 minutes with **Include job descriptions** turned off. Example: 24 companies / 11,400 jobs including four big Workday employers took 13 minutes and about $0.08 of platform usage at 512 MB. Keep the default run timeout (1 hour) or higher for big lists; if the timeout gets close, the Actor stops cleanly and saves its state.
- **SmartRecruiters** answers an unknown company id with an empty list, so a misspelled id shows as `ok` with 0 jobs and a `note` in the run summary.
- **Plain company names** are matched by probing the slug on Greenhouse, Lever, Ashby, Workable and SmartRecruiters. Short or generic names can hit a different company's board, so use the careers URL when it matters.
- **Workday `posted_at`** is approximate in list data ("Posted 3 Days Ago") and replaced by the exact start date when the description is fetched. Workday doesn't expose structured salary; it's taken from the description text when present.
- **Salary extraction from text** is conservative: if there's no clear range with a currency, salary fields stay empty.
- Data is what the employer publishes on its job board at run time; nothing is inferred or enriched from other sources.

### Responsible use

This Actor is meant for job discovery, labor-market research and hiring-signal use cases, using job postings that companies publish publicly to attract applicants.

- Respect each employer's and each platform's terms. Don't use the data to spam applicants or recruiters, or to misrepresent jobs.
- If you republish jobs, link back to the original `apply_url` and remove closed jobs promptly. The `closed` status makes that easy.
- The Actor is deliberately gentle. It sends at most 4 parallel requests per host (5 per Workday tenant), automatically lowers that limit for a site that answers HTTP 429, backs off on 5xx and honors `Retry-After`. Keep schedules reasonable: daily is plenty for most feeds.
- No personal data is collected: the output has no recruiter or hiring-manager names, emails or phone numbers.

### Related Actors

- [Job Postings API: 1M+ Fresh Jobs](https://apify.com/cleanrowdata/fresh-jobs-index): search 1.17M jobs from 17,000+ career sites by title, location and time window, refreshed hourly.
- [Hiring Signals API: Companies Hiring Now](https://apify.com/cleanrowdata/hiring-signals-api): one row per hiring company with new jobs by function and seniority, for sales and recruiting lead lists.
- [Remote Jobs API: Remote Jobs by Region](https://apify.com/cleanrowdata/remote-jobs-api): remote-only jobs filtered by where you can work from (US, Canada, Europe, LATAM, anywhere), with function, seniority and salary filters.

### Support

Found a board that doesn't work, or need another ATS? Open an issue on the Actor's **Issues** tab with the careers URL. We usually respond within 24 hours.

*Built by CleanRow Data (Trade Boss Pro LLC).*

# Changelog

This Actor's version history is a separate document: https://apify.com/cleanrowdata/careers-jobs-feed/changelog.md

# Actor input Schema

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

One company per line. Accepted forms:<br>• ATS board URL: <code>https://boards.greenhouse.io/stripe</code>, <code>https://jobs.lever.co/spotify</code>, <code>https://jobs.ashbyhq.com/ramp</code>, <code>https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite</code>, <code>https://jobs.smartrecruiters.com/ServiceNow</code>, <code>https://apply.workable.com/huggingface</code><br>• Explicit token: <code>greenhouse:airbnb</code>, <code>lever:palantir</code>, <code>ashby:notion</code>, <code>smartrecruiters:BoschGroup</code>, <code>workable:skroutz</code><br>• Plain name/slug: <code>stripe</code> (we probe Greenhouse, Lever, Ashby, Workable and SmartRecruiters)<br>• A company's own careers page, e.g. <code>https://www.example.com/careers</code> (we look for an embedded ATS)<br>Optional display name: <code>Acme Corp | https://jobs.lever.co/acme</code>. Workday always needs the full myworkdayjobs.com URL.

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

Keep jobs whose title contains ANY of these words or phrases (case-insensitive, whole-word: 'intern' does not match 'internal'). Leave empty for all jobs.

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

Search the job description as well as the title. Slower for Workday and SmartRecruiters (descriptions need one request per job).

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

Drop jobs whose title contains any of these, e.g. 'Senior', 'Manager', 'Intern'.

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

Keep jobs where any location contains one of these, e.g. 'New York', 'London', 'Germany', 'US'. Use 'Remote' to also match jobs flagged remote.

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

Keep only jobs the ATS marks as remote (or whose location says Remote / Anywhere).

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

Keep jobs whose department or team contains any of these, e.g. 'Engineering', 'Sales'. For Workday the 'Job Category' is used as department.

## `postedSince` (type: `string`):

Only jobs posted on/after this date. Absolute (<code>2026-10-01</code>) or relative (<code>24 hours</code>, <code>7 days</code>, <code>2 weeks</code>, <code>1 month</code>). Jobs without a posted date are kept.

## `changesOnly` (type: `boolean`):

Emit only jobs that are NEW since the previous run of this feed, plus jobs that were CLOSED (disappeared). Ideal for daily schedules: you pay only for changes. State is kept in the named key-value store below.

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

Add one row with status 'closed' for every job that disappeared from a board since the last run.

## `firstRunEmitsAll` (type: `boolean`):

In 'changes only' mode, the first run for a company has no history: emit all current jobs as 'new' (on) or just record a silent baseline and emit nothing (off).

## `trackState` (type: `boolean`):

Keep history between runs even in full mode. Turn off for one-off exports (status will be 'active', no closed rows). Always on in 'changes only' mode.

## `stateStoreName` (type: `string`):

Named key-value store in your account that keeps history between runs. Use a different name (or Feed key) per independent feed.

## `feedKey` (type: `string`):

Optional prefix so several feeds with different filters can share one state store without interfering, e.g. 'eng-us-daily'.

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

Fetch full description text + HTML. Turn off for a much faster/lighter run on Workday and SmartRecruiters (no per-job requests).

## `includeDescriptionHtml` (type: `boolean`):

Keep the original HTML next to the plain text. Turn off for smaller datasets.

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

Stop after this many emitted jobs per company (newest first). 0 = no limit.

## `maxJobs` (type: `integer`):

Hard cap on dataset rows for the whole run (cost control). 0 = no limit.

## `maxCompaniesInParallel` (type: `integer`):

How many companies are processed at the same time.

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

Global cap on simultaneous HTTP requests (per-host limits always apply: max 4 per host, 5 per Workday tenant, automatically reduced when a site rate-limits). Lower it to be gentler.

## Actor input object example

```json
{
  "companies": [
    "https://boards.greenhouse.io/airbnb",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/linear"
  ],
  "keywordsInDescription": false,
  "remoteOnly": false,
  "changesOnly": false,
  "emitClosed": true,
  "firstRunEmitsAll": true,
  "trackState": true,
  "stateStoreName": "careers-jobs-feed-state",
  "includeDescription": true,
  "includeDescriptionHtml": true,
  "maxJobsPerCompany": 25,
  "maxJobs": 0,
  "maxCompaniesInParallel": 4,
  "maxConcurrency": 20
}
```

# Actor output Schema

## `jobs` (type: `string`):

All job rows in one normalized schema across Greenhouse, Lever, Ashby, Workday, SmartRecruiters and Workable.

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

JSON with the detected ATS, jobs on board, emitted/new/closed counts and any error for each input company.

# 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/airbnb",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/linear"
    ],
    "maxJobsPerCompany": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("cleanrowdata/careers-jobs-feed").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/airbnb",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/linear",
    ],
    "maxJobsPerCompany": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("cleanrowdata/careers-jobs-feed").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/airbnb",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/linear"
  ],
  "maxJobsPerCompany": 25
}' |
apify call cleanrowdata/careers-jobs-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cleanrowdata/careers-jobs-feed"
        }
    }
}
```

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/OiyV6V1YuEEDl3RXh/builds/v82cuajsx7cKQJHYg/openapi.json
