# Career Site Jobs Feed: New Job Postings Monitor (`fecklesspleb/career-site-jobs-feed`) Actor

A feed of new job postings straight from company career sites: search a built-in directory of 692 boards or your own list, filter by time range, title, location, salary and visa sponsorship, and get only new jobs on each scheduled run. Expired-job tracking. $2 per 1,000 jobs.

- **URL**: https://apify.com/fecklesspleb/career-site-jobs-feed.md
- **Developed by:** [Scott Williams](https://apify.com/fecklesspleb) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 job postings

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 Feed: new job postings from company career sites, daily or hourly

Career Site Jobs Feed is a jobs feed and new-job-postings monitor: schedule it daily or hourly with **Only new jobs** on, and each run returns only the new job postings from company career sites on Greenhouse, Lever, Ashby, Workable, Recruitee and Teamtailor that you have not had before. It outputs every job in one JSON schema with title, company name, locations, workplace type, salary when published, visa sponsorship, status and a dedupe key, and **Report expired jobs** adds a free record when a posting disappears from its board. It costs **$0.002 per job posting ($2 per 1,000), with no start fee**.

Sample output: the first item from a local run of the prefilled example input (`{"maxItems": 4}`) on 2 November 2026, shortened to 15 of its 48 fields (`descriptionText` and the rest are in the full item):

```json
{
  "id": "bf2754d3-e29f-40a9-93b3-33589ff69e9e",
  "ats": "ashby",
  "companySlug": "legora",
  "companyName": "Legora",
  "title": "Legal Engineer - In-House",
  "department": "Legal Engineering",
  "location": "London",
  "country": "United Kingdom",
  "workplaceType": "onsite",
  "employmentType": "FULL_TIME",
  "postedAt": "2026-10-28T17:34:16.128000+00:00",
  "status": "active",
  "keySkills": [
    "Generative AI"
  ],
  "dedupeKey": "e94f9cd1ce161db1be20",
  "firstSeenAt": "2026-11-02T14:19:58.478858+00:00"
}
```

Career Site Jobs Feed reads the official public job-board APIs and feeds of **Greenhouse, Lever, Ashby, Workable, Recruitee and Teamtailor**, filters them by title, location, company, posting date, remote/hybrid, salary and visa sponsorship, and returns every job in the same schema, whichever ATS the company uses. It is an independent tool and is not affiliated with or endorsed by any of these ATS vendors.

No login, no third-party job board, no LinkedIn: every job comes from the employer's own board, is read at run time, and links to the employer's own application page.

### What can this career site scraper do?

- **Search a built-in directory** of 692 verified public Greenhouse, Ashby and Lever boards (mostly startups and tech companies). By default it reads the 100 largest; set `maxDirectoryCompanies` to `0` for all of them.
- **Watch your own list of companies** on any of the six supported platforms: paste a board URL, `ats:slug`, a bare company slug or name, or a careers page that embeds one of these boards.
- **Filter before you pay**: posted within the last hour, 24 hours, 7 days or 30 days; job title, location, description, department and company search with include and exclude lists; work arrangement; employment type; seniority; salary; visa sponsorship; maximum years of experience; staffing-agency exclusion.
- **Run it as a jobs feed**: on a schedule, **Only new jobs** returns only jobs you have not had before, and **Report expired jobs** adds a free record when a posting disappears from its board.
- **Normalise and enrich** every job: remote/hybrid/onsite, schema.org employment type, seniority from the title, annualised salary (plus a rough USD band), visa-sponsorship and years-of-experience hints, key skills, a cross-board `dedupeKey`, and an `isAgency` flag.

### Supported career sites (ATS platforms)

| ATS | Source the Actor reads | Example company entry |
|---|---|---|
| Greenhouse | Greenhouse Job Board API | `https://boards.greenhouse.io/airbnb` or `greenhouse:airbnb` |
| Lever | Lever Postings API | `https://jobs.lever.co/palantir` or `lever:palantir` |
| Ashby | Ashby public job posting API | `https://jobs.ashbyhq.com/ramp` or `ashby:ramp` |
| Workable | Workable widget API | `https://apply.workable.com/huggingface` |
| Recruitee | Recruitee Careers Site API (public XML offer feed as fallback) | `bunq.recruitee.com` |
| Teamtailor | Teamtailor jobs RSS | `proxima.teamtailor.com` |

Workable boards are supported but are not in the built-in directory, and Workable's API rate-limits hard: the Actor reads Workable at most once every 5 seconds. If Workable answers HTTP 429 (Cloudflare error 1015), the Actor stops requesting Workable for the rest of the run instead of retrying board after board, and writes one free `status: "warning"` record that lists the Workable boards it did not read.

Workday, SmartRecruiters and Personio entries are refused with a free `unresolved` record and no request to that site. iCIMS and SuccessFactors are not supported either. For Workday career sites, see the [Workday Jobs Scraper](https://apify.com/fecklesspleb/workday-jobs-scraper).

### Who uses a career-site jobs feed?

- **Job boards and aggregators** that want direct-from-employer postings every hour or every day.
- **Recruiters, sales and market-intelligence teams** tracking which companies are hiring for which roles.
- **Job seekers** who want an alert for new matching roles at the companies they care about.

### How it works

1. **Picks the boards**: your **Companies** list, the built-in directory, or both. Company-name and ATS filters are applied to the directory *before* any request, so a narrow search reads only a few boards.
2. **Reads each board once** from its public API or feed. robots.txt is checked for every host first, and requests to each host are spaced out (Lever's `Crawl-delay: 1` is honoured; Workable boards are read at most once every 5 seconds).
3. **Filters and enriches** each job: time range, title, location, description, department, work arrangement, employment type, seniority, salary, visa sponsorship and years of experience.
4. **Saves matching jobs** to the dataset and a per-board `RUN_SUMMARY` to the key-value store.

### How much does it cost to scrape career sites?

Pay per event, no start fee: **$0.002 per job posting saved ($2 per 1,000 jobs)**. Expired and unresolved records are free. Jobs dropped by a filter, by **Exclude recruiting agencies** or by **Remove duplicate jobs** are never saved, so they are never charged.

Examples (job counts from test runs on 2026-10-28; cost = jobs x $0.002):

- The whole directory for the last 24 hours: 186 jobs, **$0.37**.
- One large board read in full, Palantir on Lever (225 open jobs): **$0.45**.
- Empty input `{}` (the demo, see below): 4 jobs, **$0.008**.

`maxItems` (100 when left empty) and Apify's **Maximum cost per run** both stop a run.

### Input example

Engineering and data-science jobs posted in the last 24 hours, in the US or remote, paying at least $120,000:

```json
{
  "timeRange": "24h",
  "titleSearch": ["engineer*", "\"data scientist\""],
  "titleExclusionSearch": ["intern"],
  "locationSearch": ["\"united states\"", "remote"],
  "workArrangement": ["remote", "hybrid"],
  "minAnnualSalary": 120000,
  "salaryCurrency": "USD",
  "visaSponsorship": "not_no",
  "maxItems": 500
}
```

Search syntax (all `*Search` inputs): each list item is one alternative (OR); words inside an item must all appear as whole words; `engineer*` matches a prefix; `"product manager"` keeps a phrase together. `c++`, `.net` and `node.js` work as written.

A daily feed of new and closed jobs at particular companies:

```json
{
  "companies": ["https://boards.greenhouse.io/airbnb", "lever:palantir", "ashby:legora",
                "https://apply.workable.com/huggingface", "bunq.recruitee.com", "proxima.teamtailor.com"],
  "timeRange": "all",
  "onlyNewJobs": true,
  "includeExpired": true
}
```

### Output example

One record per job (trimmed; the full record has about 48 fields):

```json
{
  "status": "active",
  "uid": "lever:palantir:6ed76ce8-4156-4b60-b120-403538bd66cd",
  "ats": "lever",
  "companySlug": "palantir",
  "companyName": "Palantir Technologies",
  "title": "Administrative Business Partner",
  "team": "Administrative",
  "location": "Singapore, Singapore",
  "locations": ["Singapore, Singapore"],
  "country": "SG",
  "workArrangement": "hybrid",
  "workplaceTypeRaw": "hybrid",
  "employmentType": "FULL_TIME",
  "employmentTypeRaw": "Full-time",
  "seniority": null,
  "postedAt": "2026-08-11T17:38:11.368000+00:00",
  "url": "https://jobs.lever.co/palantir/6ed76ce8-4156-4b60-b120-403538bd66cd",
  "applyUrl": "https://jobs.lever.co/palantir/6ed76ce8-4156-4b60-b120-403538bd66cd/apply",
  "salaryAnnualMin": null,
  "salaryAnnualUsdMin": null,
  "visaSponsorship": null,
  "yearsExperienceMin": 3,
  "keySkills": ["Excel"],
  "isAgency": false,
  "dedupeKey": "4e08e342be634ffd5fca",
  "firstSeenAt": "2026-10-31T15:28:09.119138+00:00",
  "descriptionText": "A World-Changing Company\n\nPalantir builds the world's leading software for data-driven decisions ..."
}
```

A Greenhouse job with a published pay range also fills the salary fields, for example `"salaryMin": 212000, "salaryMax": 265000, "salaryCurrency": "USD", "salaryPeriod": "YEAR", "salarySource": "description", "salaryAnnualUsdMin": 212000, "salaryAnnualUsdMax": 265000, "requisitionId": "REQ52463"`.

#### Field notes

- `status`: `active` for a listed job. With **Report expired jobs** on, you also get `expired` records (uid, title, url, lastSeenAt, expiredDetectedAt) for jobs an earlier run returned that the board no longer lists. `unresolved` records explain an entry that didn't resolve to a board. Expired and unresolved records are free.
- `workArrangement` (`remote` / `hybrid` / `onsite`), `seniority` and `employmentType` (schema.org values) are normalised across ATSs; the ATS's own text stays in `workplaceTypeRaw` and `employmentTypeRaw`. Greenhouse has no standard field for these; they come from the company's own custom fields when it publishes one (e.g. `Workplace Type`, `Employment Type`, `Time Type`) and are null otherwise. `workArrangement` usually equals the normalised `workplaceType`; when the ATS gives no workplace type it is inferred from the title, location and remote flag, so the two can differ, and both are kept. `department` and `team` are what the ATS publishes: Lever often fills only `team`, so `department` can be null while `team` is set. The **Department or team** filter matches either field.
- `salaryAnnualMin` / `salaryAnnualMax` are annualised from the ATS's pay fields or from a pay range in the description (`salarySource` says which). Hourly pay is multiplied by 2,080, daily by 260, weekly by 52 and monthly by 12.
- `salaryAnnualUsdMin` / `salaryAnnualUsdMax` use a fixed table of rough exchange rates bundled with the Actor (set in October 2026, not live rates). Treat them as salary bands, not exact amounts. They are null when there is no salary, no pay period or an unlisted currency.
- `visaSponsorship` (`yes` / `no` / null) with `visaSponsorshipEvidence`, `yearsExperienceMin` / `yearsExperienceMax`, `keySkills` and `isAgency` are read from the description and company name with fixed patterns. They are hints, not statements by the employer, and can be wrong in both directions.
- `dedupeKey` matches the same role posted on several boards or locations. **Remove duplicate jobs** (`dedupeBy`) can drop such duplicates (`job`) or merge a company's same-title jobs into one record with all their `locations` (`companyTitle`) before they are saved.
- Contact details in descriptions (personal e-mail addresses, phone numbers, "Your recruiter: name" lines) are replaced with placeholders by default; company role mailboxes such as `jobs@` stay. Recruiter and hiring-manager fields are never output.
- **Invalid input fails at the start**: a negative number, a minimum salary above the maximum, an unknown `salaryCurrency` code or an unknown option value stops the run before any request, with a status message that lists every problem. Nothing is fetched or charged.
- **Every board failed or was blocked**: if no entry can be read (network or HTTP errors, boards not found, robots.txt, rate-limited hosts, or, on the Apify platform, private addresses), the run still succeeds and saves one free status row (`recordType: "status"`, `statusRow: true`, `status: "error"`, `reason: "allBoardsFailed"`). Its `message` starts with "Not charged: every board failed or was blocked" and gives the reasons; `boardsBlocked`, `boardsNetworkError`, `boardsNotFound` and `boardsSkipped` count them, and `failedBoards` lists the first 50 entries with their errors. Nothing is charged.

### Scheduling a jobs feed

Schedule the Actor hourly or daily with `timeRange` set a little wider than the interval and **Only new jobs** on. Each run then returns only jobs you haven't had yet, so you pay once per job. Add **Report expired jobs** to learn when postings close. State is kept in the named key-value store `career-site-jobs-feed-state`; use a different **State store name** for each independent feed. **Track first-seen dates** keeps `firstSeenAt` across runs without dropping jobs you already got.

### FAQ

**Can it read pages on private or internal addresses?** No. On the Apify platform a careers-page URL whose host resolves to a private, loopback or link-local address (also after a redirect) is not fetched and costs nothing. The entry gets a free `unresolved` row with `reason` `"not fetched: private, loopback and link-local addresses are not allowed"`.

**Which companies are covered?** The built-in directory holds 692 verified public boards (147 Greenhouse, 487 Ashby, 58 Lever), mostly startups and tech companies; about 11,600 jobs were live on them on 2026-10-28. Any public board on the six supported platforms can be added through **Companies** (up to 2,000 entries).

**What does an empty input do?** `{}`, the prefilled Console form and the example input (`{"maxItems": 4}`) run the same demo: it searches the 100 largest directory boards, jobs from the last 7 days, and stops at 4 jobs ($0.008), with a warning in the log and `demoMode: true` in `RUN_SUMMARY`. Leaving the other switches at their defaults does not change that. Demo jobs are real live jobs and are charged like any other. Any other `maxItems` (100 included), a `timeRange`, a `maxDirectoryCompanies` value or any search filter makes it a real run; with `maxItems` left empty, a real run stops at 100 jobs ($0.20).

**Is the posted date the original date?** It is the publish date the ATS reports (Greenhouse `first_published`, Lever `createdAt`, Ashby `publishedAt`, Workable `published_on`, Recruitee `published_at`, Teamtailor RSS `pubDate`). A company that re-posts a role gets a new date; `firstSeenAt` (with a state store) tells you when this Actor first saw it.

**Why are some jobs missing?** Jobs without a publish date are left out of time-range searches unless **Include undated jobs** is on. Unlisted Ashby jobs (shared by direct link only) are skipped. A host whose robots.txt disallows access or cannot be read is skipped and reported in `RUN_SUMMARY`.

**What happens when a site rate-limits the Actor?** If a site answers HTTP 429 (for example Workable's Cloudflare error 1015), or answers its robots.txt with 429, that host is skipped for the rest of the run instead of being retried board after board. You get one free `status: "warning"` record per skipped host (`recordType: "status"`, message starting "Not charged") listing the boards that were not read, and `RUN_SUMMARY` lists the host under `hostsSkipped`.

**How fast is it?** In a test on 2026-10-28, reading the whole directory took about 160 seconds with the default concurrency and about 150 MB of memory. Searches over fewer boards finish faster.

### Related job scrapers and free tools

- [ATS Jobs Scraper](https://apify.com/fecklesspleb/ats-jobs-scraper): jobs from the boards you list on nine ATSs, including Workday, in one schema.
- [Workday Jobs Scraper](https://apify.com/fecklesspleb/workday-jobs-scraper): jobs from Workday career sites, which this Actor does not read.
- Free, self-hosted scripts on GitHub: [ats-new-jobs-feed](https://github.com/fecklesspleb/ats-new-jobs-feed) (a daily Greenhouse, Lever and Ashby feed with GitHub Actions) and [workday-jobs-feed](https://github.com/fecklesspleb/workday-jobs-feed) (the same for Workday).

### Data source and attribution

Job data belongs to the employers who publish it through their ATS vendors' public job-board APIs and feeds (Greenhouse, Lever, Ashby, Workable, Recruitee, Teamtailor). This Actor is not affiliated with or endorsed by any of these companies. Use the data in line with each employer's and vendor's terms; several vendors' robots.txt files signal `ai-train=no`.

# Changelog

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

# Actor input Schema

## `timeRange` (type: `string`):

Only jobs whose ATS publish or update date falls in this window. Left empty, the last 7 days are used. Jobs without a date are left out unless 'Include undated jobs' is on.

## `titleSearch` (type: `array`):

Keep jobs whose title matches. Each list item is one alternative (OR). Words inside an item must all appear, as whole words. End a word with \* to match a prefix (engineer\* matches engineering). Put a phrase in "double quotes" to keep it together.

## `titleExclusionSearch` (type: `array`):

Drop jobs whose title matches any item. Same syntax as the title search.

## `locationSearch` (type: `array`):

Keep jobs whose location text matches (city, region or country as the company wrote it). 'remote' also matches jobs the ATS marks as remote. Each list item is one alternative (OR). Words inside an item must all appear, as whole words. End a word with \* to match a prefix (engineer\* matches engineering). Put a phrase in "double quotes" to keep it together.

## `locationExclusionSearch` (type: `array`):

Drop jobs whose location text matches any item.

## `descriptionSearch` (type: `array`):

Keep jobs whose description matches. Same syntax as the title search.

## `descriptionExclusionSearch` (type: `array`):

Drop jobs whose description matches any item.

## `organizationSearch` (type: `array`):

Keep only these companies. For the built-in directory this is applied to company names before any request, so a narrow search is fast and cheap.

## `organizationExclusionSearch` (type: `array`):

Leave these companies out (also applied to the directory before any request).

## `atsFilter` (type: `array`):

Read only these ATS platforms (directory and your own companies). Empty means all supported platforms.

## `workArrangement` (type: `array`):

Keep jobs with one of these arrangements (derived from the ATS field, location and title). Jobs with no detectable arrangement are left out when this is set.

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

Keep jobs whose normalised employment type is one of these. Jobs whose ATS gives no type are left out when this is set.

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

Keep jobs with one of these seniority levels (derived from the title). Jobs whose title shows no level are left out when this is set.

## `minAnnualSalary` (type: `integer`):

Keep only jobs that publish a salary whose annualised top (or bottom, if only one is given) is at least this. Jobs without a salary are left out when this is set.

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

With 'Minimum annual salary': also require this ISO currency code.

## `hasSalary` (type: `boolean`):

Return only jobs that state a salary, from the ATS's pay field or a range in the description (any currency or period). Jobs without one are dropped before they are output, so they are never charged.

## `minAnnualSalaryUsd` (type: `integer`):

Keep jobs whose annual salary in US dollars reaches this amount (the top of the range, or its only figure, is at least this). Salaries are annualised (hour x 2,080, day x 260, week x 52, month x 12) and converted with a fixed rate table bundled with the Actor (rough reference rates, see salaryAnnualUsdMin). Jobs whose salary cannot be converted (none given, no pay period, or an unlisted currency) are dropped unless 'Keep jobs without a salary' is on.

## `maxAnnualSalaryUsd` (type: `integer`):

Keep jobs whose annual USD salary starts at or below this amount (the bottom of the range, or its only figure). Same conversion and handling of jobs without a convertible salary as the minimum.

## `includeJobsWithoutSalary` (type: `boolean`):

With a minimum or maximum annual USD salary set, also keep jobs whose salary is missing or cannot be converted. Ignored when 'Only jobs with a salary' is on (jobs with no salary are dropped) and when no USD bound is set.

## `visaSponsorship` (type: `string`):

Filter on visaSponsorship, read from the description text (yes / no / not stated). Pattern-based, not a legal statement by the employer.

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

Drop jobs whose description asks for more years than this (e.g. 2 for early-career). Jobs that state no number are kept.

## `excludeAgencies` (type: `boolean`):

Leave out jobs that look like they were posted by a staffing or recruitment agency: the company name (e.g. Randstad, Hays, "… Staffing", "… Recruitment", "Personalberatung") or wording such as "on behalf of our client" or "für unseren Kunden suchen wir" in the description. It is a heuristic, so check the isAgency field before relying on it. Every job carries isAgency whether or not this is on; excluded jobs are never output or charged.

## `dedupeBy` (type: `string`):

Drop duplicates inside this run before they are output, so you never pay for them. <b>None</b>: every job is output (as before). <b>Same job</b>: a job with the same company, title and first location as one already output in this run is dropped (the dedupeKey field). <b>Same company and title (merge locations)</b>: jobs of one company with the same title are output as one record whose locations list holds all their locations, with duplicateCount and mergedUids; such records are output when the company's board has been read. Duplicates of jobs output by earlier runs are not affected (use Only new jobs for that).

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

Keep jobs whose department or team matches. Same syntax as the title search.

## `includeUndatedJobs` (type: `boolean`):

Keep jobs that carry no posted date when 'Posted within' is not 'Any time'.

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

Leave empty to search the built-in directory of public career boards. Or list your own: a board URL (https://boards.greenhouse.io/airbnb, https://jobs.lever.co/palantir, https://jobs.ashbyhq.com/ramp, https://apply.workable.com/huggingface, https://bunq.recruitee.com, https://proxima.teamtailor.com), 'ats:slug' such as 'greenhouse:airbnb', a bare slug or company name (each supported ATS is tried), or a careers page that embeds one of these boards. Workday, SmartRecruiters and Personio are not supported. Up to 2,000 entries.

## `searchDirectory` (type: `boolean`):

On by default when 'Companies' is empty; turn on to search the directory as well as your own list, or off to never use it. The directory holds about 690 verified public Greenhouse, Ashby and Lever boards (startups and tech companies), refreshed with each Actor version.

## `maxDirectoryCompanies` (type: `integer`):

Use only the N largest directory boards. Left empty: 100, which keeps a run to about 20 seconds. 0 means the whole directory (692 boards, about 3 minutes).

## `includeExpired` (type: `boolean`):

On scheduled runs, add a free record with status 'expired' for each job an earlier run returned that its board no longer lists. Only boards read completely in this run are checked. Uses the state store.

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

Return only jobs not returned by an earlier run with the same state store, so a schedule gives a clean feed and you pay only for new jobs.

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

Named key-value store for 'Only new jobs', 'Report expired jobs' and first-seen dates. Use a different name per independent feed.

## `trackFirstSeen` (type: `boolean`):

Keep firstSeenAt across runs without dropping jobs you already got.

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

Write the job description to the output. Descriptions are always read for the enrichment (visa, experience, skills).

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

Plain text, HTML, or both.

## `redactContacts` (type: `boolean`):

Replace e-mail addresses, phone numbers and 'Your recruiter: <name>' lines with placeholders. The Actor never outputs recruiter or hiring-manager fields.

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

Stop after this many paid jobs. Left empty: 100. 0 means no limit. The run also stops at your 'Maximum cost per run'. The form is prefilled with 4 for a cheap demo run (4 x $0.002 = $0.008); raise it for real runs. An empty input {} is the same demo: it stops at 4 jobs. Any value you set other than 4 (100 included) is a real run.

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

Stop after this many matching jobs per company. 0 means no limit. A capped board is not checked for expired jobs.

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

How many boards to read at once. Requests to each host are spaced regardless (robots.txt Crawl-delay is honoured).

## Actor input object example

```json
{
  "titleSearch": [
    "engineer*",
    "\"product manager\""
  ],
  "titleExclusionSearch": [
    "intern",
    "manager"
  ],
  "locationSearch": [
    "\"united states\"",
    "london",
    "remote"
  ],
  "descriptionSearch": [
    "python",
    "\"machine learning\""
  ],
  "descriptionExclusionSearch": [
    "\"security clearance\""
  ],
  "organizationSearch": [
    "stripe",
    "\"hugging face\""
  ],
  "salaryCurrency": "USD",
  "hasSalary": false,
  "includeJobsWithoutSalary": false,
  "visaSponsorship": "any",
  "excludeAgencies": false,
  "dedupeBy": "none",
  "includeUndatedJobs": false,
  "companies": [
    "https://boards.greenhouse.io/airbnb",
    "ashby:ramp",
    "lever:palantir"
  ],
  "includeExpired": false,
  "onlyNewJobs": false,
  "stateStoreName": "career-site-jobs-feed-state",
  "trackFirstSeen": false,
  "includeDescription": true,
  "descriptionFormat": "text",
  "redactContacts": true,
  "maxItems": 4,
  "maxJobsPerCompany": 0,
  "maxConcurrency": 5
}
```

# Actor output Schema

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

No description

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

No description

# 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 = {
    "maxItems": 4
};

// Run the Actor and wait for it to finish
const run = await client.actor("fecklesspleb/career-site-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 = { "maxItems": 4 }

# Run the Actor and wait for it to finish
run = client.actor("fecklesspleb/career-site-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 '{
  "maxItems": 4
}' |
apify call fecklesspleb/career-site-jobs-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fecklesspleb/career-site-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/iN8zvBnEUOQbj72uf/builds/OwOUJ4jHACwWsc4ze/openapi.json
