# Career Page Jobs Search (`lightmoon/career-page-jobs-scraper`) Actor

Search the job boards of 867 companies at once by keyword, location and department - you never type a company name. Returns title, company, location, posting date and a direct apply link. Directory size and build date in every run. From $0.95 per 1,000 jobs.

- **URL**: https://apify.com/lightmoon/career-page-jobs-scraper.md
- **Developed by:** [Stable](https://apify.com/lightmoon) (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 $0.95 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

### Search 867 company career pages at once — by keyword, not by company name

You do not paste company URLs. You type what you are looking for — "backend
engineer", "London", "remote" — and this searches the job boards of **867
companies** in one run and returns every match.

The directory ships inside the Actor. It currently holds **867 boards and 28,205
open roles** across three applicant-tracking platforms, and you can see its size
and build date in every run's summary before you trust a single row.

#### One row, from a real run

Read on 27 August 2026, from a keyword search — no company was named in the
input.

```json
{
  "platform": "greenhouse",
  "companyToken": "apolloio",
  "companyName": "Apollo.io",
  "companyBoardUrl": "https://job-boards.greenhouse.io/apolloio",
  "jobId": "5823149004",
  "internalJobId": "5061583004",
  "requisitionId": "969",
  "title": "Account Manager, Mid Market (London)",
  "jobUrl": "https://job-boards.greenhouse.io/apolloio/jobs/5823149004",
  "applyUrl": "https://job-boards.greenhouse.io/apolloio/jobs/5823149004",
  "locationRaw": "Hybrid, London",
  "isRemote": false,
  "postedAt": "2026-08-17T20:03:33-04:00",
  "updatedAt": "2026-08-17T20:03:33-04:00",
  "language": "en",
  "customFields": "{\"Hiring Health\": \"On Track\"}",
  "scrapedAt": "2026-08-27T15:55:55+00:00"
}
```

### The directory is the product

No applicant-tracking platform publishes a list of the companies using it. There
is no index, no sitemap and no cross-board search: a board can only be reached
if you already know its token. That is why "search across company career pages"
is a hard product and why most tools ask you to bring the URLs yourself.

So the list ships with the Actor, and every run tells you what it used:

```json
"directory": { "builtAt": "2026-08-11", "boards": 867,
               "byPlatform": { "ashby": 541, "greenhouse": 250, "lever": 76 },
               "totalJobs": 28205 }
```

**Breadth comes first.** Every board gets an equal share of your row limit before
any board gets a second turn, so 60 rows over 120 boards means 60 different
employers — not 60 roles from whichever board answered first.

### What you search on

| | |
|---|---|
| `titleKeywords` | words in the job title |
| `excludeTitleKeywords` | words that disqualify it |
| `locationKeywords` | city, country or region as written on the posting |
| `remoteOnly` | remote roles only |
| `departmentKeywords` | engineering, sales, design |
| `postedAfter`, `updatedAfter` | only what is new since your last run |
| `platforms` | narrow to one of the three |
| `minJobsPerCompany` | skip boards with almost nothing on them |
| `companies` | and if you *do* know the companies, name them and skip the sweep |

`postedAfter` is the one that pays for itself: give it the date of your last run
and a daily check costs a handful of rows instead of the whole sweep.

### Fields

**17 per job**, counted. Descriptions are optional and off by default.

`platform` · `companyToken` · `companyName` · `companyBoardUrl` · `jobId` ·
`internalJobId` · `requisitionId` · `title` · `jobUrl` · `applyUrl` ·
`locationRaw` · `isRemote` · `postedAt` · `updatedAt` · `language` ·
`customFields` · `scrapedAt`

Turning descriptions on adds `descriptionHtml` and `descriptionText`.

### What it costs

Pay per event, and there is one paid event: **a job stored**.

| | GOLD per 1,000 |
|---|---|
| **Job** | **$0.95** |

**You are not billed for** a board that would not open, a job removed by one of
your filters, or a duplicate.

- A 100-role search: **$0.10**.
- A daily watch across the whole directory with `postedAfter` set: a few cents.
- Apify's $5 of monthly free credit: about **2,600 jobs**.

A 120-board sweep takes about 14 seconds.

### Limits, stated plainly

- **867 boards, built 2026-08-11.** That is what ships today; the number and the
  date are in every run summary, so you never have to take it on trust.
- **Three platforms** — the ones whose boards are addressable by a bare token.
  Companies on other systems are not in the directory.
- **A board that closes stays in the list until the next rebuild.** Those are
  reported as failures in the run summary rather than hidden.
- **Two of the three platforms publish no company name** anywhere in their board
  payload, so `companyName` is often the token. The token is unique and the
  board URL is always right.
- **No salary field** — these platforms do not publish one in machine-readable
  form.
- **On the free plan** everything works at the FREE rate until Apify's monthly
  platform credit runs out; the run then stops cleanly and keeps what it has.

# Actor input Schema

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

What you are looking for, matched against the job title. Case-insensitive, and a job is kept if it contains at least one of these. Leave empty to get everything the run reads — that fills up fast, so a keyword is nearly always what you want.

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

Matched against the location the employer wrote, for example `Berlin`, `Germany`, `Remote`, `EMEA`. Empty means any location.

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

Keeps only jobs that say they are remote. A posting that never mentions it is dropped rather than guessed at.

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

Drops jobs whose title contains any of these — useful for `intern`, `senior`, `manager`, `principal`.

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

For example `Engineering`, `Sales`. Departments arrive with the full description, so this needs descriptions turned on.

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

Keeps jobs first published on or after this date. The usual way to see only what is new.

## `updatedAfter` (type: `string`):

Keeps jobs edited on or after this date — use it to fetch only what changed since your last run.

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

Stops the run once this many matching rows are stored, and this is what you pay for. Set 0 for no limit.

## `maxCompanies` (type: `integer`):

How many boards the run is allowed to open, biggest employers first. Higher means better coverage and a longer run; it does not change what you pay, since you pay per matching job. Set 0 to read the whole directory.

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

Off by default: descriptions make each board slower to read and each row much larger. Turn it on when you need the body text or the department, and note that rows with a description are billed at the higher rate.

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

Optional. Names or board tokens, one per line — the run then reads only these, still without you having to know which system each of them uses. Empty means the whole directory.

## `platforms` (type: `array`):

Which applicant tracking systems to read. All three by default.

## `minJobsPerCompany` (type: `integer`):

Ignores employers with fewer open roles than this. 0 reads every board in the directory.

## `concurrency` (type: `integer`):

Each board is a single request. Raise it to cover more employers in the same time.

## Actor input object example

```json
{
  "titleKeywords": [
    "engineer"
  ],
  "locationKeywords": [],
  "remoteOnly": false,
  "excludeTitleKeywords": [],
  "departmentKeywords": [],
  "maxJobs": 100,
  "maxCompanies": 500,
  "includeDescription": false,
  "companies": [],
  "platforms": [
    "greenhouse",
    "lever",
    "ashby"
  ],
  "minJobsPerCompany": 0,
  "concurrency": 5
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `descriptions` (type: `string`):

No description

## `all` (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 = {
    "titleKeywords": [
        "engineer"
    ],
    "locationKeywords": [],
    "excludeTitleKeywords": [],
    "departmentKeywords": [],
    "maxCompanies": 500,
    "companies": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("lightmoon/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 = {
    "titleKeywords": ["engineer"],
    "locationKeywords": [],
    "excludeTitleKeywords": [],
    "departmentKeywords": [],
    "maxCompanies": 500,
    "companies": [],
}

# Run the Actor and wait for it to finish
run = client.actor("lightmoon/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 '{
  "titleKeywords": [
    "engineer"
  ],
  "locationKeywords": [],
  "excludeTitleKeywords": [],
  "departmentKeywords": [],
  "maxCompanies": 500,
  "companies": []
}' |
apify call lightmoon/career-page-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lightmoon/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/905nWdOJKf07mMgA0/builds/aImZUNBYYIEsqY2QV/openapi.json
