# Careers Page Job Scraper & New Job Alerts (6 ATS) (`patrykstudio/careers-job-feed`) Actor

Scrape open jobs from company careers pages on Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee. One normalized feed with salary, remote, location and department, plus new-job detection between runs. No login, no proxies.

- **URL**: https://apify.com/patrykstudio/careers-job-feed.md
- **Developed by:** [Heronpage Studio](https://apify.com/patrykstudio) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 50.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## 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 Job Scraper & New Job Alerts: Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee

**Get every open job from any company's careers page in one clean, normalized dataset, and get only the *new* jobs on every scheduled run.** Works with the six most popular applicant tracking systems (ATS): **Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee**. Paste careers-page URLs (or just company names), press Start, done.

- ✅ **6 ATS in one actor**: no need to juggle a separate Greenhouse scraper, Lever scraper and Ashby scraper
- 🔔 **New-job detection built in**: schedule it daily and get only postings that appeared since the last run (plus, optionally, jobs that closed)
- 💰 **Salary ranges** where the ATS publishes them (Ashby, Lever, Recruitee), plus **remote / hybrid / on-site**, location, department, employment type
- 🧭 **Auto-detects the ATS**: type `figma` or `notion` and the actor finds the right job board
- 🔎 **Filters**: title keywords, excluded keywords, location / country, department, remote only, posted within N days
- 🧾 **Pay only for what you get**: per company checked and per job returned, with no monthly rental
- 🔐 **No login, no cookies, no proxies.** It uses only the official public job-board APIs that the ATS vendors publish for careers pages.

### What can I use it for?

| Use case | How |
|---|---|
| **Job alerts for specific companies** | Add your dream employers, turn on *Only new jobs*, schedule daily, and connect email, Slack or Google Sheets via Apify integrations |
| **Recruiting & sales intelligence** | See who is hiring for what (e.g. "data engineer" in "Poland") and spot hiring surges as buying signals |
| **Job boards & niche aggregators** | Feed a remote-only / AI-only / EU-only job board with fresh, de-duplicated postings |
| **Market & salary research** | Pull thousands of postings with structured salary ranges, departments and locations |
| **Competitor monitoring** | Track which teams your competitors are growing and which roles they close |
| **AI agents & LLM pipelines** | Clean `descriptionText` per job, ready for embeddings or classification |

### How to use it

1. **Add companies.** Paste careers-page URLs, one per line:
   - `https://boards.greenhouse.io/stripe` or `https://job-boards.greenhouse.io/figma`
   - `https://jobs.lever.co/spotify` (EU Lever: `https://jobs.eu.lever.co/...`)
   - `https://jobs.ashbyhq.com/linear`
   - `https://apply.workable.com/huggingface`
   - `https://careers.smartrecruiters.com/BoschGroup`
   - `https://channable.recruitee.com`
   - or the short form `greenhouse:stripe`, `lever:spotify`, `ashby:linear`, `workable:huggingface`, `smartrecruiters:BoschGroup`, `recruitee:channable`
   - or just a company slug like `notion`. The actor tries all six ATSs, picks the board with the most jobs and remembers the result.
   - or the company's own careers page, like `https://www.notion.com/careers`. The actor scans the page for an embedded or linked Greenhouse, Lever, Ashby, Workable, SmartRecruiters or Recruitee board and uses it. Pages with no supported board are skipped (never a crashed run) and listed as `unsupported` in the `RUN_SUMMARY` record, with a hint for what to try instead.
   - Leave the list empty and the actor runs a small demo list (Stripe, Spotify, Linear, Channable) so you can see the output format.
2. **Optional filters**: title keywords, location keywords, remote only, and more.
3. **For alerts**: turn on **Only new jobs since last run**, give the watch-list a **Monitor ID**, and **schedule** the actor (Apify Console → Schedules). Turn off *Count jobs as new on the first run* if you want the first run to be a silent baseline.
4. **Export** as JSON, CSV, Excel or HTML, or push to Google Sheets, Slack, email, Zapier, Make or n8n via Apify integrations and webhooks.

### Input example

```json
{
  "companies": [
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/openai",
    "https://apply.workable.com/huggingface",
    "smartrecruiters:BoschGroup",
    "recruitee:channable",
    "notion"
  ],
  "onlyNewJobs": true,
  "monitorId": "my-dream-companies",
  "titleKeywords": ["engineer", "data"],
  "locationKeywords": ["Remote", "Poland", "Europe"],
  "includeDescription": true
}
```

### Output example

Each job is one dataset item with the same fields for every ATS:

```json
{
  "id": "ashby:ramp:34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "ats": "ashby",
  "companySlug": "ramp",
  "companyName": "Ramp",
  "jobId": "34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "title": "Security Engineer, Cloud",
  "department": "Engineering",
  "team": "Backend",
  "location": "New York, NY (HQ)",
  "locations": ["New York, NY (HQ)", "Remote (Canada)", "Remote (US)", "Miami, FL"],
  "country": "USA",
  "isRemote": true,
  "workplaceType": "hybrid",
  "employmentType": "FullTime",
  "salaryMin": 211400,
  "salaryMax": 290600,
  "salaryCurrency": "USD",
  "salaryPeriod": "year",
  "salaryText": "$211.4K – $290.6K • Offers Equity",
  "url": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application",
  "publishedAt": "2026-04-07T17:12:35.753000Z",
  "updatedAt": null,
  "descriptionHtml": "<h1><strong>About Ramp</strong></h1><p>…",
  "descriptionText": "ABOUT RAMP\n\nRamp is building the smart infrastructure for …",
  "isNew": true,
  "firstSeenAt": "2026-10-24T13:18:30Z",
  "status": "active",
  "scrapedAt": "2026-10-24T13:18:30Z"
}
```

With **Also output removed jobs** on, closed postings are returned as `{"status": "removed", "removedAt": "…", "firstSeenAt": "…"}`.

A run summary (boards checked, jobs found, new and removed per company, errors) is saved to the key-value store as `RUN_SUMMARY`.

#### Fields by ATS

| Field | Greenhouse | Lever | Ashby | Workable | SmartRecruiters | Recruitee |
|---|---|---|---|---|---|---|
| Title, URL, apply URL, published date | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Department / team | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Location(s), country | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Remote / workplace type | from location text | ✅ | ✅ | ✅ | ✅ | ✅ |
| Employment type | – | ✅ | ✅ | ✅ | ✅ | ✅ |
| Structured salary | – | when published | ✅ | – | – | when published |
| Full description | ✅ | ✅ | ✅ | ✅ | optional (1 extra request per job) | ✅ |

### How much does it cost?

Pay-per-event pricing means you only pay for results:

- **$0.002 per company board checked**
- **$0.001 per job in the output**: 1,000 jobs cost $1

Examples:

- Daily alerts for **50 companies**, ~10 new jobs a day: 50 × 30 × $0.002 + 300 × $0.001 ≈ **$3.30 / month**
- One-off export of **10,000 jobs** from 40 companies: 40 × $0.002 + 10,000 × $0.001 ≈ **$10.08**

Apify's free plan includes monthly credit, which is enough to try this actor on dozens of companies. You can cap spending per run with **Max cost per run**; the actor stops cleanly when the cap is reached.

### Is it legal? How does it get the data?

The actor calls only the **public, unauthenticated job-board APIs** that each ATS documents for companies to build their own careers pages: the Greenhouse Job Board API, Lever Postings API, Ashby Job Posting API, Workable careers API, SmartRecruiters Posting API (public postings only) and Recruitee Careers Site API. It does **not** log in, use cookies, bypass any protection, or touch candidate or personal data. Job postings are content the employers publish for everyone to read. Requests are throttled per ATS (for example one request per second to Lever, honoring its crawl-delay, and a slower pace for Workable) and back off automatically on HTTP 429.

You are responsible for using the data in line with applicable law and the terms of the sites you use it on. Do not use it to spam applicants or employers.

### Tips & limits

- **Finding the right URL**: open the company's careers page and click a job. The link usually reveals the ATS (`greenhouse.io`, `lever.co`, `ashbyhq.com`, `workable.com`, `smartrecruiters.com`, `recruitee.com`). Companies that host their own careers site on top of one of these ATSs can still be added with the `ats:slug` form.
- **Huge employers** (thousands of postings on SmartRecruiters): use **Max jobs per company** for quick samples. When the list is cut, removed-job detection is skipped for that company, so you never get false "removed" items.
- **Separate watch-lists** need separate **Monitor IDs**, so their "new since last run" memories don't mix.
- **Recruitee** has announced that from **10 February 2027** its careers API will require a token issued by each company. Recruitee boards may stop working for third parties from that date. Other ATSs are unaffected.
- Not supported (yet): Workday, Personio, Teamtailor, BambooHR, iCIMS. Open an issue if you need one. Entries on these are skipped with a clear note in the run's status message and `RUN_SUMMARY`; the rest of the list still runs.
- **Forgiving input**: a single text field of companies (one per line or comma-separated), keyword fields given as text, numbers given as strings, and `startUrls`-style `{ "url": ... }` objects are all accepted. Anything that had to be corrected is listed under `inputNotes` in `RUN_SUMMARY`.

### FAQ

**Can I get alerts by email or Slack?** Yes. Schedule the actor with *Only new jobs* on, then add an Apify integration (Slack, email, Google Sheets, Zapier, Make, n8n) or a webhook on "run succeeded".

**Why are some jobs listed twice with the same title?** Companies often post the same role separately per city or team. Each posting has its own `jobId` and URL.

**Can I use it via API or from an AI agent?** Yes. Call it via the Apify API, the Python or JavaScript client, or the Apify MCP server.

**Something broke?** Open an issue on the Issues tab with the company URL. Fixes are usually shipped within a few days.

# Actor input Schema

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

One entry per company. Paste the careers-page URL (e.g. https://boards.greenhouse.io/stripe, https://jobs.lever.co/spotify, https://jobs.ashbyhq.com/linear, https://apply.workable.com/huggingface, https://careers.smartrecruiters.com/BoschGroup, https://channable.recruitee.com) or use the short form ats:slug (greenhouse:stripe, lever:spotify, lever-eu:company, ashby:linear, workable:huggingface, smartrecruiters:BoschGroup, recruitee:channable). A bare slug like 'figma' is auto-detected across all six ATSs. You can also paste a company's own careers page (e.g. https://www.notion.com/careers): the Actor scans it for an embedded or linked board on one of the six ATSs and reports it as 'unsupported' in RUN_SUMMARY if none is found. If left empty, a small demo list is used.

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

Output only jobs that did not exist in the previous run with the same Monitor ID. Schedule the Actor (e.g. daily) to get a stream of fresh postings. Jobs are always tracked, so every item also carries isNew and firstSeenAt.

## `monitorId` (type: `string`):

Name of the 'memory' used for new-job detection. Use a different ID for each independent watch-list / schedule so they don't interfere. Letters, digits, dash, dot, underscore.

## `treatFirstRunAsNew` (type: `boolean`):

When a company is checked for the first time, mark all its jobs as new (on) or just record them as a baseline (off). Turn off for alerting so the first run doesn't flood you.

## `emitRemovedJobs` (type: `boolean`):

Add an item with status 'removed' for each job that disappeared since the last run.

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

Case-insensitive. Example: engineer, data, product manager. Empty = all titles.

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

Case-insensitive. Example: intern, senior director.

## `locationKeywords` (type: `array`):

Matched against location, all locations and country code. Example: Berlin, Poland, PL, Remote, EMEA.

## `departmentKeywords` (type: `array`):

Example: Engineering, Sales.

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

Keep only jobs flagged remote by the ATS (or with 'Remote' in the location).

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

0 = no limit.

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

Adds descriptionHtml and descriptionText. Turn off for smaller, faster output.

## `fetchSmartRecruitersDescriptions` (type: `boolean`):

SmartRecruiters needs one extra request per job for the description. Only done for jobs that pass filters (and only new ones when 'Only new jobs' is on).

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

0 = unlimited. Useful for very large employers. When the limit cuts the list, removed-job detection is skipped for that company.

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

Requests are throttled per ATS host regardless of this value.

## Actor input object example

```json
{
  "companies": [
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/linear",
    "https://apply.workable.com/huggingface",
    "recruitee:channable",
    "figma"
  ],
  "onlyNewJobs": false,
  "monitorId": "default",
  "treatFirstRunAsNew": true,
  "emitRemovedJobs": false,
  "remoteOnly": false,
  "postedWithinDays": 0,
  "includeDescription": true,
  "fetchSmartRecruitersDescriptions": false,
  "maxJobsPerCompany": 0,
  "maxConcurrency": 6
}
```

# Actor output Schema

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

All job records from this run (new jobs only when onlyNewJobs is on).

## `runSummary` (type: `string`):

Per-company counts of open, new and removed jobs.

# 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/spotify",
        "https://jobs.ashbyhq.com/linear",
        "https://apply.workable.com/huggingface",
        "recruitee:channable",
        "figma"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("patrykstudio/careers-job-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/stripe",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/linear",
        "https://apply.workable.com/huggingface",
        "recruitee:channable",
        "figma",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("patrykstudio/careers-job-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/stripe",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/linear",
    "https://apply.workable.com/huggingface",
    "recruitee:channable",
    "figma"
  ]
}' |
apify call patrykstudio/careers-job-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,patrykstudio/careers-job-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/nu04Ptqw4geMFhR1i/builds/Vd4nJtBT3IkKrfyQ2/openapi.json
