# Career Page Jobs Scraper — Any Company, 13 ATS Auto-Detected (`fabrikit/career-page-jobs-scraper`) Actor

Scrape jobs from any company's careers page. Give a name, domain or URL: the Actor detects Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Teamtailor, Personio, Breezy, BambooHR, Pinpoint, Rippling or JazzHR and returns all open jobs in one schema. From US$0.36 per 1,000 jobs.

- **URL**: https://apify.com/fabrikit/career-page-jobs-scraper.md
- **Developed by:** [Fabrikit](https://apify.com/fabrikit) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.36 / 1,000 job scrapeds

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 Page Jobs Scraper — Any Company, 13 ATS Auto-Detected

**Career Page Jobs Scraper extracts job postings from any company's careers page.** Paste company names, websites or careers URLs and the Actor works out which applicant tracking system (ATS) sits behind the page — Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Teamtailor, Personio, Breezy HR, BambooHR, Pinpoint, Rippling or JazzHR — reads the board through its public, unauthenticated endpoint and saves every open position in one flat schema: title, locations, remote flag, department, employment type, salary when the company publishes it, job and apply URLs, dates and, on request, the full description. One summary record per company tells you which ATS it uses, where it was detected and how many jobs are open.

No browser, no API key, no login. You pay per job saved and per company resolved.

It grows out of our [ATS Jobs Scraper](https://apify.com/fabrikit/ats-jobs-api) (Greenhouse, Lever, Ashby and SmartRecruiters by board slug) and adds nine more ATS plus the company-to-ATS detection, so you no longer need to know where a company hosts its jobs.

### What data does it return?

Job records (`recordType: "job"`):

| Field | Example | Notes |
|---|---|---|
| `company`, `companyName`, `ats` | `ramp`, `Ramp`, `ashby` | board slug, display name, ATS id |
| `sourceId`, `title` | `29b679a8-…`, `Solutions Consultant, Enterprise` | the ATS's own posting id |
| `location`, `allLocations` | `New York, NY (HQ)`, `["New York, NY (HQ)", "Remote (US)", "Miami, FL"]` | primary and every listed location |
| `remote`, `workplaceType` | `true`, `hybrid` | `remote` / `hybrid` / `onsite` when the ATS says so, else inferred from the location text |
| `department`, `team`, `employmentType`, `seniority` | `Sales`, `Solutions Consulting`, `FullTime`, `Entry level` | as labelled by the company |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryInterval`, `salaryText` | `null`, `null`, `null`, `null`, `$195K – $298K • Offers Equity` | numbers when the ATS structures them (Lever, Recruitee, Pinpoint), text otherwise (Ashby, Breezy, BambooHR) |
| `url`, `applyUrl` | `https://jobs.ashbyhq.com/ramp/29b6…`, `…/application` | |
| `publishedAt`, `updatedAt`, `expiresAt` | `2026-09-03T21:55:28.736Z` | ISO 8601, when the ATS exposes them |
| `description` | plain text | only with `includeDescription`; e-mail addresses and phone numbers removed |
| `input`, `scrapedAt` | `ashby:ramp` | the input line that produced the record |

Company records (`recordType: "company"`): `input`, `company`, `companyName`, `ats`, `atsLabel`, `boardUrl`, `careersUrl` (the page where the ATS was detected), `detectedVia` (`input`, `url`, `careers-page` or `name-probe`), `jobsOpen`, `boardComplete`, `jobsMatched`, `jobsSaved`.

### Use cases

- **Job feeds for a list of target companies** — hundreds of companies in one run, one schema, no per-ATS code; schedule it daily and diff against the previous dataset.
- **Recruiting-tech intelligence** — switch on `companiesOnly` to learn which ATS each company uses and how many roles it has open (sales signal for HR-tech vendors, agencies and investors).
- **Hiring signals for sales and research** — open headcount by department and location, remote policies, posted salaries.
- **Job boards and aggregators** — fill a niche board (remote, a region, an industry) straight from the source instead of from scraped aggregators.
- **AI agents and RAG** — full descriptions as plain text with ISO dates and numeric salary fields, ready for an LLM pipeline.

### How to use it

Add one company per line in **Companies**, in whichever form you have:

| You have | Write | What happens |
|---|---|---|
| the ATS and slug | `greenhouse:stripe`, `ashby:ramp`, `recruitee:bunq`, `teamtailor:antonsport`, `bamboohr:nycballet` | read directly (fastest, 1 request) |
| an ATS link | `https://jobs.lever.co/spotify`, `https://acme.recruitee.com`, `https://acme.jobs.personio.de` | the slug is taken from the URL |
| a website or careers page | `ramp.com`, `https://www.pinpointhq.com/`, `https://acme.com/careers` | the page and up to two careers links are scanned for ATS links and embeds; if nothing is found the brand name is probed as a board slug |
| just the name | `rippling`, `Anton Sport` | the name is probed as a slug on the 13 ATS (cheap requests, most common ATS first), then `<name>.com` is tried |

Then set **Maximum jobs** (exact, across all companies), optionally **Maximum jobs per company**, **Remote jobs only**, **Include job description** and **Company records only**, and run. Export JSON, CSV or Excel, or read the dataset through the API.

#### Input example: the default run

```json
{
  "companies": ["ashby:ramp", "recruitee:bunq", "https://www.pinpointhq.com/", "teamtailor.com"],
  "maxItems": 30,
  "maxJobsPerCompany": 8
}
```

#### Input example: remote jobs with descriptions from a watch list

```json
{
  "companies": ["stripe.com", "https://ramp.com/careers", "lever:spotify", "personio:personio", "Anton Sport"],
  "remoteOnly": true,
  "includeDescription": true,
  "maxItems": 500
}
```

#### Input example: which ATS do these companies use?

```json
{
  "companies": ["bunq", "rippling", "nycballet.bamboohr.com", "https://www.pinpointhq.com/"],
  "companiesOnly": true
}
```

### Output example

A job and the summary record of its company from a local run on 20 October 2026:

```json
{
  "recordType": "job",
  "input": "ashby:ramp",
  "company": "ramp",
  "companyName": "ramp",
  "ats": "ashby",
  "sourceId": "29b679a8-9990-48c1-b91e-001c566ced27",
  "title": "Solutions Consultant, Enterprise",
  "location": "New York, NY (HQ)",
  "allLocations": ["New York, NY (HQ)", "San Francisco, CA", "Remote (US)", "Miami, FL"],
  "remote": true,
  "workplaceType": "hybrid",
  "department": "Sales",
  "team": "Solutions Consulting",
  "employmentType": "FullTime",
  "seniority": null,
  "salaryMin": null,
  "salaryMax": null,
  "salaryCurrency": null,
  "salaryInterval": null,
  "salaryText": "$195K – $298K • Offers Equity • Offers Commission • Multiple Ranges",
  "url": "https://jobs.ashbyhq.com/ramp/29b679a8-9990-48c1-b91e-001c566ced27",
  "applyUrl": "https://jobs.ashbyhq.com/ramp/29b679a8-9990-48c1-b91e-001c566ced27/application",
  "publishedAt": "2026-09-03T21:55:28.736Z",
  "updatedAt": null,
  "expiresAt": null,
  "description": null,
  "scrapedAt": "2026-10-20T09:36:31.879Z"
}
```

```json
{
  "recordType": "company",
  "input": "ashby:ramp",
  "company": "ramp",
  "companyName": "ramp",
  "ats": "ashby",
  "atsLabel": "Ashby",
  "boardUrl": "https://jobs.ashbyhq.com/ramp",
  "careersUrl": null,
  "detectedVia": "input",
  "jobsOpen": 167,
  "boardComplete": true,
  "jobsMatched": 167,
  "jobsSaved": 30,
  "scrapedAt": "2026-10-20T09:36:31.879Z"
}
```

A `SUMMARY` record in the key-value store lists every company with its ATS and counts, the inputs that could not be resolved and why, the number of requests and the proxy rung used.

### Pricing

Pay per event, compute and proxy included:

- **US$0.36 per 1,000 jobs** saved (US$0.00036 each) — `job-result`
- **US$2.00 per 1,000 companies** resolved (US$0.002 each) — `company-resolved`, charged once per company whose board was read; companies that cannot be resolved cost nothing

Examples: 1,000 jobs from 20 companies = US$0.36 + US$0.04 = US$0.40; 100 companies with all their jobs (say 5,000) = US$1.80 + US$0.20 = US$2.00; an ATS lookup of 1,000 companies with `companiesOnly` = US$2.00. Duplicates are never charged and a maximum cost per run set in Apify stops the Actor cleanly at that limit.

### How it compares

- **Single-ATS scrapers** (Greenhouse-only, Lever-only, Workable-only…) need you to know the ATS and the board slug for every company. Here you can start from a name or a domain, and one run can mix all 13 systems in one schema.
- **Other career-page and ATS job scrapers in Apify Store** charge roughly US$3 to US$45 per 1,000 jobs. This Actor is priced at US$0.36 per 1,000 jobs plus US$2 per 1,000 companies, which keeps a 100-company daily feed around two dollars.
- **Job aggregators** (LinkedIn, Indeed, Glassdoor) list what employers choose to syndicate, often days late and without the structured fields. Reading the company's own board gives you every posting the day it goes live, with the ATS's own ids for de-duplication.
- **Limits that come from the sources:** SmartRecruiters and Breezy HR do not publish descriptions; Rippling, BambooHR and JazzHR need one extra request per job for them; Teamtailor and Pinpoint boards are read from a single feed; Workday, iCIMS, SuccessFactors, Taleo and other enterprise systems are not covered. Companies whose careers page only loads jobs through private scripts cannot be detected from the page — pass the ATS link or `ats:slug` instead.

### Integrations

Run it from the Apify API or the JavaScript and Python clients, schedule it in Apify Console and push the dataset to Google Sheets, Airtable, n8n, Make, Zapier or any webhook. AI agents (Claude, ChatGPT, Cursor and other MCP clients) can call it through the Apify MCP server, for example "list the open engineering roles at Ramp and bunq".

### FAQ

**Is it legal to scrape career pages?** The Actor reads public job advertisements through the same unauthenticated endpoints the companies' own careers pages use. Job postings describe companies and roles, not people; recruiter e-mail addresses and phone numbers are removed from descriptions, and no candidate or applicant data is touched. This Actor is not affiliated with any ATS vendor and this is not legal advice.

**Do I need a proxy?** No. ATS endpoints answer datacenter IPs. Company websites — read only to find the ATS — sometimes sit behind Cloudflare or DataDome; after repeated blocks the Actor switches to Apify residential proxies automatically. You can also force residential proxies in `proxyConfiguration`.

**A company was not resolved. Why?** It uses an ATS that is not supported (Workday, iCIMS, SuccessFactors, Taleo, custom sites), its careers page does not link to the board, or the name is not the board slug. `SUMMARY.unresolved` gives the reason; passing the board URL or `ats:slug` always works for the 13 supported systems.

**Which ATS are detected?** Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Teamtailor (including career sites on the company's own domain), Personio, Breezy HR, BambooHR, Pinpoint, Rippling and JazzHR. Each one was verified against live boards on 20 October 2026.

**How are remote jobs detected?** From the ATS's own flag or workplace type where it exists (Lever, Ashby, SmartRecruiters, Recruitee, Workable, Teamtailor, Pinpoint, BambooHR, Breezy), otherwise from the word "remote" in the location. Jobs without any signal have `remote: null` and are skipped by `remoteOnly`.

**How many requests does a name cost?** A direct `ats:slug` is one request. A website is one to three pages. A bare name is up to 13 small probe requests (most common ATS first, the search stops as soon as one answers), then its `.com` website.

### Changelog

- **2026-10-20** — First version: 13 ATS, resolution from names, domains, careers pages and ATS links, company summary records, exact `maxItems`, per-company limit, remote filter, descriptions without contact details, pay per job and per company.

### En español

**Career Page Jobs Scraper** extrae los avisos de empleo de la página de carreras de cualquier empresa. Entregas nombres, dominios o URLs; el actor detecta el sistema de reclutamiento (Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Teamtailor, Personio, Breezy HR, BambooHR, Pinpoint, Rippling o JazzHR), lee el tablero por su endpoint público y guarda cada vacante con título, ubicaciones, marca de remoto, departamento, tipo de contrato, salario cuando se publica, enlaces, fechas y, si lo pides, la descripción completa sin correos ni teléfonos de reclutadores. Además deja un registro por empresa con el ATS detectado y la cantidad de vacantes abiertas. Cuesta US$0,36 por cada 1.000 avisos y US$2,00 por cada 1.000 empresas resueltas. Si ya conoces el ATS y solo necesitas Greenhouse, Lever, Ashby o SmartRecruiters, también está nuestro [ATS Jobs Scraper](https://apify.com/fabrikit/ats-jobs-api).

# Actor input Schema

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

One company per line, in any of these forms: a company name (`bunq`), a website or domain (`ramp.com`, `https://www.pinpointhq.com/`), a careers page URL (`https://ramp.com/careers`), an ATS board URL (`https://jobs.lever.co/spotify`, `https://acme.recruitee.com`) or an explicit `ats:slug` pair (`greenhouse:stripe`, `ashby:ramp`, `recruitee:bunq`, `teamtailor:antonsport`, `personio:personio`, `bamboohr:nycballet`). Names and domains are resolved by reading the site and probing the 13 ATS; an explicit pair is fastest.

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

Stop after this many job records in total (exact; duplicates are never counted or charged). Company summary records do not count.

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

Keep at most this many jobs from each company. 0 = all open jobs.

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

Save only jobs the ATS marks as remote (or whose location says remote). Jobs without a remote flag are skipped.

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

Add the full job description as plain text (e-mail addresses and phone numbers removed). Greenhouse, Lever, Ashby, Workable, Recruitee, Teamtailor, Personio and Pinpoint ship it with the listing; Rippling, BambooHR and JazzHR need one extra request per job; SmartRecruiters and Breezy HR do not expose it publicly.

## `companiesOnly` (type: `boolean`):

Detect the ATS and count the open jobs of each company, but do not save the jobs themselves. Useful to find out which recruiting software a list of companies uses.

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

ATS endpoints are public APIs and work from datacenter proxies. Company websites (read only to find the ATS) are sometimes protected by Cloudflare or DataDome: after repeated blocks the Actor switches to Apify RESIDENTIAL proxies automatically.

## Actor input object example

```json
{
  "companies": [
    "ashby:ramp",
    "recruitee:bunq",
    "https://www.pinpointhq.com/",
    "teamtailor.com"
  ],
  "maxItems": 30,
  "maxJobsPerCompany": 8,
  "remoteOnly": false,
  "includeDescription": false,
  "companiesOnly": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All job records (recordType = job) collected during the run

## `companies` (type: `string`):

One record per company that was resolved to a careers board (recordType = 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": [
        "ashby:ramp",
        "recruitee:bunq",
        "https://www.pinpointhq.com/",
        "teamtailor.com"
    ],
    "maxItems": 30,
    "maxJobsPerCompany": 8,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("fabrikit/career-page-jobs-scraper").call(input);

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

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

```

## Python example

```python
from apify_client import ApifyClient

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

# Prepare the Actor input
run_input = {
    "companies": [
        "ashby:ramp",
        "recruitee:bunq",
        "https://www.pinpointhq.com/",
        "teamtailor.com",
    ],
    "maxItems": 30,
    "maxJobsPerCompany": 8,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("fabrikit/career-page-jobs-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "companies": [
    "ashby:ramp",
    "recruitee:bunq",
    "https://www.pinpointhq.com/",
    "teamtailor.com"
  ],
  "maxItems": 30,
  "maxJobsPerCompany": 8,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call fabrikit/career-page-jobs-scraper --silent --output-dataset

```

## MCP server setup

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

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/1tQOSPkCjZvnlxWF7/builds/OMIO1UtTCor1t0IOf/openapi.json
