# Career Site Job Listing API (`om_kh/careers-page-scraper`) Actor

Career site job listing API: paste company websites and get clean, current openings from official career sources. Automatic ATS detection. First 3 free.

- **URL**: https://apify.com/om\_kh/careers-page-scraper.md
- **Developed by:** [omar khandji](https://apify.com/om_kh) (community)
- **Categories:** Jobs, MCP servers
- **Stats:** 4 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event + usage

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Career Site Job Listing API — Company Domain to Open Jobs

> **You paste `stripe.com`. You get all 545 open roles.**
> **Paste 50 domains and one run answers for all 50.**
>
> One input: company websites. The Actor works out which applicant tracking
> system sits behind each careers page and reads that system's own public
> endpoint. No tokens to look up, no provider to choose, no proxies.
> **3 job listings free on every run.**

### Measured, on real companies

| You paste | It finds | You get |
| --- | --- | --- |
| `stripe.com` | Greenhouse | 545 roles |
| `anthropic.com` | Greenhouse | 399 roles |
| `figma.com` | Greenhouse | 177 roles |
| `ramp.com` | Ashby | 123 roles |
| `notion.so` | Ashby | 110 roles |
| `vercel.com` | Greenhouse | 81 roles |
| `monzo.com` | Greenhouse | 75 roles |

*(2026-08-03 — 1,550 live roles from eight bare domains, nothing else supplied.)*

### How it finds the ATS

Two passes. It reads the company's careers page and looks at where it links —
`boards.greenhouse.io/stripe`, `jobs.lever.co/figma` — and if nothing is linked
it derives the likely handle from the domain and asks the providers directly.

Nine systems are supported: **Greenhouse, Lever, Ashby, Workday,
SmartRecruiters, Rippling, Breezy HR, Personio, BambooHR**.

A company running its own careers page with no hosted ATS behind it comes back
with `"ats": null` and no rows — an answer, not an error.

### Why not scrape a job board

Job aggregators mean cookies, proxies, rate limits, and roles that are stale or
reposted by three agencies. This reads the employer's own feed.

| | Aggregator scraper | This Actor |
| --- | --- | --- |
| What breaks it | anti-bot, layout changes, expired cookies | nothing — these are the companies' own public endpoints |
| Freshness | an aggregator's copy | the role as the employer published it |
| Duplicates | the same role three times | one row per role |
| Proxy bill | yes | none |

### Filter before you pay

Filters run **before billing**, so you are never charged for a job you excluded.

| Input | Effect |
| --- | --- |
| `keywords` | Keep jobs whose title, department, company or location contains one of these |
| `excludeKeywords` | Drop jobs matching any of these — `intern`, `senior`, `sales` |
| `locations` | Keep jobs whose location contains one of these |
| `remoteOnly` | Keep only roles whose location says remote, anywhere or distributed |
| `postedAfter` | Keep jobs posted on or after `YYYY-MM-DD` |

**Keywords match whole words and do not stem.** `engineer` returns "Backend
Engineer" but not "Engineering Intern" — pass both if you want both. A substring
filter for `ai` would match "m**ai**ntainer", which on a real board kept 40% of
unrelated roles.

### Output

```json
{
  "domain": "stripe.com",
  "source_url": "https://boards.greenhouse.io/stripe/jobs/6789",
  "title": "Account Executive, AI Sales",
  "company": "stripe",
  "location": "New York",
  "department": "Sales",
  "posted_at": "2026-07-20T09:12:00Z",
  "source": "greenhouse",
  "function": "Sales",
  "seniority": "Mid",
  "is_remote": false
}
```

`is_remote` is set on every row (not only when you filter with **Remote only**), the same check that input runs, so you can see per-row which postings are remote without needing to turn the filter on.

Roles are deduplicated by URL, so two domains resolving to the same board never
bill you twice. **Seniority and job function are inferred and attached.**

### What a run costs

**Standard price: $2 per 1,000 job listings** (base FREE-tier price). You pay
only for listings actually delivered to you. There is no per-run fee: a run
that finds nothing costs $0. Paid Apify Store plans (Bronze through Diamond)
receive a variable discount on this price — the exact current discount for
your plan is shown on this Actor's **Pricing** tab in the Store, not repeated
here since Apify's tier discounts change independently of this README.

#### Ask for many companies at once

Measured on this Actor at ~35 open roles per company:

| Companies in one run | Jobs returned | You pay | Per job |
|---|---|---|---|
| 1 | 35 | **$0.05** | $0.0014 |
| 10 | 350 | **$0.68** | $0.0019 |
| 50 | 1,750 | **$3.48** | $0.0020 |

Batching does not change the price per job — it changes your wall clock. Fifty
companies asked together take one run instead of fifty, and the free allowance
below is the only thing that makes a small run cheaper per row.

Up to **100 companies per run**; **15 per HTTP request**, so a Standby/MCP call
answers inside Apify's five-minute ceiling. Split a larger list across requests.

### Free tier — 3 job listings on every run

**The first 3 job listings of every run are free**, on every run you ever make,
not just the first. Wire it into a pipeline and evaluate it on your own target
companies before a cent is billed.

The free allowance never covers more than half of a run, so a run returning 20
listings gets 3 free rather than 10 — that is what stops it becoming an
unlimited free plan for anyone willing to split one job into many tiny runs.

### Pricing

**Standard rate: $0.002 per job listing — $2 per 1,000** (base FREE-tier
price), after the free 3. Paid Apify Store plans (Bronze through Diamond)
receive a variable discount on this price — see this Actor's **Pricing** tab
in the Store for the exact current discount on your plan.

Same price as the [ATS Jobs API](https://apify.com/om_kh/ats-jobs-api), which
reads the same endpoints and returns the same rows with more control over
providers and deltas.

### Limits

- **100 companies per run**, **15 per request** in HTTP mode, so a request
  finishes inside Apify's five-minute ceiling.
- Workday pages 20 roles at a time and is capped at 200 roles per tenant.

### Use it from an AI agent (MCP)

This Actor is a **Model Context Protocol server**. Point any MCP client at it and
the tool appears with its full input schema — no wrapper code:

```
https://om-kh--careers-page-scraper.apify.actor/mcp
```

```json
{
  "mcpServers": {
    "careers_page_jobs": {
      "url": "https://om-kh--careers-page-scraper.apify.actor/mcp",
      "headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
    }
  }
}
```

One tool, `careers_page_jobs`. It takes the same arguments as the Start form and returns the
same rows, so an agent and a `curl` user can never get different answers.

### Related tools

- Want one call across multiple ATS providers instead of one company at a time? → [ATS Jobs Search API](https://apify.com/om_kh/ats-jobs-api)
- Want to know when hiring activity changes, not just current listings? → [Hiring Signals](https://apify.com/om_kh/company-hiring-signals)

### All input fields

Every field the Start form accepts, so nothing in the schema is undocumented. Most runs only need the fields already covered above — these are the rest, including advanced/bring-your-own-data options.

- **`companyDomains`** (Company websites) — The company websites you want jobs from. Just the domain - stripe.com, figma.com. The Actor works out which applicant tracking system each one uses. Max 100 per run.

### Support

Found a bug or have a feature request? Use the **Issues** tab on this Actor's Apify Store page, or message the author (`om_kh`) directly through Apify — every report gets a reply.

# Actor input Schema

## `companyDomains` (type: `array`):

The company websites you want jobs from. Just the domain - stripe.com, figma.com. The Actor works out which applicant tracking system each one uses. Max 100 per run.

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

Keep only jobs whose title, department, company or location contains one of these words. Whole-word match. Filtering happens before billing - you are never charged for a job you filtered out.

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

Drop jobs matching any of these words, e.g. intern, senior, sales.

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

Keep only jobs whose location contains one of these, e.g. Berlin, United Kingdom.

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

Keep only roles whose location says remote, anywhere or distributed.

## `postedAfter` (type: `string`):

Keep only jobs posted on or after this date (YYYY-MM-DD). Jobs from providers that publish no date are kept.

## `maxTotalChargeUsd` (type: `number`):

Hard ceiling on what this run can bill you. The run stops delivering paid rows once it is reached.

## Actor input object example

```json
{
  "companyDomains": [
    "stripe.com",
    "figma.com",
    "notion.so"
  ],
  "remoteOnly": false,
  "maxTotalChargeUsd": 1
}
```

# Actor output Schema

## `report` (type: `string`):

A visual summary of delivery, charges, changes, and source issues.

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

Business-ready results in a sortable table. No JSON knowledge required.

## `csv` (type: `string`):

Results ready for spreadsheets, CRMs, and analytics tools.

## `excel` (type: `string`):

Results as an Excel workbook for non-technical teams.

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

Machine-readable delivery, billing, and source diagnostics.

# 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 = {
    "companyDomains": [
        "stripe.com",
        "figma.com",
        "notion.so"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("om_kh/careers-page-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 = { "companyDomains": [
        "stripe.com",
        "figma.com",
        "notion.so",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("om_kh/careers-page-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 '{
  "companyDomains": [
    "stripe.com",
    "figma.com",
    "notion.so"
  ]
}' |
apify call om_kh/careers-page-scraper --silent --output-dataset

```

## MCP server setup

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