# Recruitee Jobs API - Career Page Scraper, Remote & Pay Data (`starbright_overlap/recruitee-jobs-scraper`) Actor

Recruitee jobs API and career page scraper. Read live postings from any Recruitee job board or careers page, or search thousands of known Recruitee ATS boards in one run. Structured pay ranges, publish dates and the employer's own remote flag on every row.

- **URL**: https://apify.com/starbright\_overlap/recruitee-jobs-scraper.md
- **Developed by:** [Sulle H](https://apify.com/starbright_overlap) (community)
- **Categories:** Jobs, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 job results

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/platform/actors/running/actors-in-store#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

## Recruitee Jobs API — 1,126 Career Pages, With Remote and Pay Fields

Recruitee is an applicant tracking system used by mid-market employers, with the widest country
spread of the platforms this family covers. Its public endpoint is also the most complete: it is
the only one that publishes a **structured pay range** — separate minimum, maximum, currency and
period — next to **the employer's own work-arrangement flag** and a **publish date**.

(Ashby also ships a work-arrangement boolean and a date, but quotes pay as prose. Pinpoint ships
structured numbers but no publish date. Recruitee is the one place all three arrive together.)

Point it at a company, or leave the list empty and search a bundled registry of **1,126 live
Recruitee career pages** carrying **21,621 open postings**.

```json
{ "keywords": ["engineer"], "remoteOnly": true, "maxJobs": 200 }
```

```json
{ "companies": ["https://movares.recruitee.com"] }
```

No login, no cookies, no proxies, no API key.

### Remote is a fact here, not a guess

Most of the ATS platforms in this family force the same compromise: the only place "remote" appears
is inside a free-text location string, so a scraper has to pattern-match `"Remote — EMEA"` and hope. That
misses `"Anywhere"`, and it misfires on `"Remote Support Engineer, London office"`.

Recruitee asks the employer to tick one of three boxes and publishes all three as separate booleans.
This Actor reads them directly:

- `remote: true` — the employer marked the role remote
- `remote: false` — the employer marked it on-site or hybrid
- `remote: null` — the employer left it blank, so we say we don't know

**A work arrangement is stated on 100% of rows in this registry.** `remoteOnly` on this Actor
filters on the employer's own answer. On the other platforms it is filtering on a regular
expression, and the README says so there too.

### What you get

| Field | Description |
|---|---|
| `provider` | Always `recruitee` — the same schema the multi-ATS Actors below emit |
| `company` / `companySlug` | Employer name and subdomain |
| `jobId` | Recruitee posting id — stable, so it works as a dedupe key across runs |
| `title` | Job title |
| `location` | City and country, e.g. `Utrecht, Nederland` |
| `department` | Department, from the employer's own org structure |
| `employmentType` | `fulltime_permanent`, `internship`, `contract` and similar, as classified by the employer |
| `remote` | The employer's own flag — see above |
| `postedAt` | When the posting was published. Present on 100% of rows |
| `applyUrl` | Direct link to the application form |
| `descriptionText` | Full posting text plus requirements, as readable plain text |
| `salary` | Present when the employer filled it in — see below |
| `scrapedAt` | When this row was read |

### Pay ranges, already structured at the source

Recruitee stores minimum, maximum, currency and period as separate fields rather than a sentence.
Measured across **21,621 postings from every live board in this registry, 26.9% carry a pay range.**

```json
{ "salary": "4500–6500 EUR month" }
```

Note the period: European employers commonly quote **monthly**, not annual, and this Actor keeps
whichever the employer chose rather than converting. A converted number would be a guess about
holiday allowance and 13th-month pay, which the source does not contain.

Where a fixed rate is quoted, minimum equals maximum and it renders as one number rather than
`550–550`.

The rest come back `null` because the employer left the fields blank — not because the Actor failed
to read them.

### Input

| Option | What it does |
|---|---|
| `keywords` | Keep only titles containing one of these. Case-insensitive. |
| `excludeKeywords` | Drop titles containing any of these, e.g. `senior`, `intern`. |
| `locations` | Keep only locations containing one of these. |
| `remoteOnly` | Keep only postings the employer marked remote. Real field, not a regex. |
| `postedWithinDays` | Freshness filter. Recruitee rows carry real publish dates, so this works properly. |
| `companies` | Subdomains or board URLs. Leave empty to search all 1,126. |
| `maxBoards` | How many boards to scan, largest-first. |
| `maxJobs` | Hard cap on rows, so a run costs what you expect. |

### Finding a company slug

The career page lives at `<slug>.recruitee.com`, so the slug is the subdomain. Paste the whole URL
and the Actor extracts it. Or run without `companies` and read the `companySlug` column.

### Recipes

**European remote roles, dated.** `remoteOnly` plus `postedWithinDays` is a combination that only
works properly on this platform in this family — everywhere else one half of it is missing or
inferred.

**Salary benchmarking.** Filter to rows where `salary` is non-null, group by `department`. Check
the currency and period on each row rather than assuming — this registry spans dozens of countries.
Two platforms here publish pay as separate numbers rather than prose: Pinpoint fills it more often
(42.5% vs 26.9%) but is UK-weighted, and this one is where the European rows are.

**Watch one company.** One slug, run on a schedule, diff `jobId` between runs.

### Pricing

Pay per result — you are charged per job row delivered. A board that fails or returns nothing costs
you nothing. Platform usage is included rather than billed on top.

### Beyond Recruitee

Companies move between applicant tracking systems, and most job-data projects need more than one:

- **[Career Site Job Feed](https://apify.com/starbright_overlap/ats-job-feed)** — the same engine
  across every platform in this family, in one run, with an identical output schema.
- **[New Job Alerts](https://apify.com/starbright_overlap/new-jobs-feed)** — the same coverage, but
  each run returns only what appeared since the previous run.

### Notes

- **A dead slug never aborts the run.** Failures land in a `FAILED_BOARDS` record in the key-value
  store, with the reason for each.
- **`companySlug:jobId` is a stable key**, safe for detecting what opened and closed between runs.
- **No login, no proxies, no API key.** Recruitee publishes this endpoint openly. Private boards are
  invisible to every scraper, including this one.
- **Where the postings are.** Measured across 5,528 postings from a 71-board sample of this
  registry: Europe **46.5%**, United States **16.8%**, rest of world **36.7%**. The largest single
  countries are the US (16.8%), Germany (8.9%), France (7.2%), the UK (5.7%) and the Netherlands
  (4.4%). So it is Europe-leading rather than Europe-only, and it is not a US-first source — for
  US-weighted coverage start with the multi-ATS feed above.

# Actor input Schema

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

Keep only jobs whose title contains at least one of these. Case-insensitive. Leave empty for every job.

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

Drop jobs whose title contains any of these, e.g. `senior`, `intern`.

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

Keep only jobs whose location contains one of these, e.g. `london`, `new york`, `germany`.

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

Keep only postings flagged remote by the ATS or with a remote-looking location.

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

Freshness filter. Defaults to 90 days because some employers leave postings open for years — measured across the registry, 15% of Greenhouse and about half of the largest SmartRecruiters boards are over a year old. Set a large number such as 3650 to include everything. Postings with no publication date (most Workday rows) are always kept.

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

Board slugs, e.g. `rebootmonkey`. Leave empty to search all 1,126 known recruitee employers.

## `maxBoards` (type: `integer`):

Boards are scanned largest-first, so a capped run still returns the most jobs. Raise it to sweep all 1,126 boards.

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

Hard cap on results, so a run costs what you expect. Defaults to 500 — enough to evaluate the feed on free-tier credits. Clearing the box falls back to that, so type a large number such as 500000 to sweep everything.

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

Fetch the full description text. Available on Greenhouse, Workable, Ashby and Breezy. SmartRecruiters and Workday do not expose descriptions on their listing endpoints, so those rows return null however this is set. Turning it off makes runs several times faster.

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

Higher is faster but more likely to hit ATS rate limits.

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

Keeps one huge employer from filling the whole run. Boards are scanned largest-first, so without this the first few boards use up the entire result budget. Raise it when you want depth on a few employers rather than breadth across many.

## Actor input object example

```json
{
  "keywords": [
    "engineer"
  ],
  "remoteOnly": false,
  "postedWithinDays": 90,
  "maxBoards": 300,
  "maxJobs": 500,
  "includeDescription": true,
  "concurrency": 8,
  "maxJobsPerCompany": 25
}
```

# Actor output Schema

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

Every posting matching your filters, normalized across all six ATS platforms.

## `failedBoards` (type: `string`):

Written only when a board was unreachable or rate-limited. The run itself is unaffected.

# 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 = {
    "keywords": [
        "engineer"
    ],
    "postedWithinDays": 90,
    "maxJobs": 500,
    "maxJobsPerCompany": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("starbright_overlap/recruitee-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 = {
    "keywords": ["engineer"],
    "postedWithinDays": 90,
    "maxJobs": 500,
    "maxJobsPerCompany": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("starbright_overlap/recruitee-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 '{
  "keywords": [
    "engineer"
  ],
  "postedWithinDays": 90,
  "maxJobs": 500,
  "maxJobsPerCompany": 25
}' |
apify call starbright_overlap/recruitee-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,starbright_overlap/recruitee-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/3PCogIYz4h4TGJ2AS/builds/K2mXzvOozuXb9CuA4/openapi.json
