# Lever Jobs Scraper · Job Postings, Teams, Locations & Salary (`reapx/lever-jobs-scraper`) Actor

Scrape open job postings, departments, locations, remote status, compensation and application URLs from any Lever company job board.

- **URL**: https://apify.com/reapx/lever-jobs-scraper.md
- **Developed by:** [Tarek Etman](https://apify.com/reapx) (community)
- **Categories:** Jobs, Business, Developer tools
- **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 returneds

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

![reapX — public sources in, addressable records out](https://reapx.dev/reapx.gif)

## Lever Jobs Scraper · Job Postings, Teams, Locations & Salary

Scrape every open job posting from any Lever company job board. Give this **Lever jobs scraper** a list of company slugs — `spotify`, `palantir`, `qonto`, `ro` — or paste full board URLs, and get back one clean row per opening: job title, company name, department, team, location, workplace type, remote status, full job description, application links, and publication dates. It fetches Lever's public postings API over plain HTTP, so there is no browser, no login, no API key, and no blocking.

> Maintained by **reapX**. Every row cites the Apify run that produced it — nothing is
> inferred, modelled or filled in, and a field absent from the source is absent from the row.
> The extracted archive for this source is browsable at
> [reapx.dev/data/lever-jobs-scraper/](https://reapx.dev/data/lever-jobs-scraper/) and mirrored as an open dataset on
> [Hugging Face](https://huggingface.co/datasets/reapxdev/lever-jobs-scraper) and
> [Kaggle](https://www.kaggle.com/datasets/reapxdev/lever-jobs-scraper). Questions: reapxdev@proton.me

### What this Lever jobs scraper returns

One row per open job posting, formatted into a standardized dataset with these fields:

| Field | Description |
|---|---|
| `companyName` | Name of the hiring employer (aggregates multiple postings per employer) |
| `jobId` | Unique Lever UUID for this job posting |
| `title` | Job title as published by the employer |
| `commitment` | Employment type (e.g., Permanent, Full-time, Contract, Internship) |
| `department` | Main department or functional unit |
| `team` | Specific internal team or sub-department |
| `location` | Primary location published for the position |
| `allLocations` | Complete array of all locations offered for the role |
| `country` | Country code (ISO 3166-1 alpha-2) when available |
| `workplaceType` | Workplace model: `remote`, `hybrid`, or `on-site` |
| `isRemote` | Boolean flag indicating whether the job is remote-friendly |
| `createdAt`, `publishedAt`, `publishedDate` | Epoch timestamp (ms), ISO 8601 timestamp, and publication date (YYYY-MM-DD) |
| `descriptionText` | Plain text job description |
| `descriptionHtml` | Full HTML job description with formatting |
| `hostedUrl`, `applyUrl` | Public Lever posting page URL and direct application link |
| `scrapedAt` | ISO 8601 timestamp when the posting was collected |

### How to find a Lever company board slug

The company slug is the identifier in a Lever job board URL. For example:

- In `https://jobs.lever.co/spotify`, the company slug is `spotify`.
- In `https://api.lever.co/v0/postings/palantir`, the company slug is `palantir`.

You can paste either form — full URLs or bare company slugs. Both are automatically parsed and normalized.

### Scrape jobs from multiple Lever boards at once

Pass up to 200 company board slugs in a single run to gather postings across an entire cohort — venture portfolios, competitor sets, or industry verticals. The results are aggregated into a single, unified dataset sorted across all companies.

### Filter Lever job postings by department, location and remote status

Optionally filter job postings using flexible parameters:

- **Job title keywords**: Filter by required or excluded keywords in job titles.
- **Department & team keywords**: Match against department or team names (e.g. `engineering`, `sales`, `product`).
- **Location keywords**: Match against primary or alternative office locations (e.g. `London`, `San Francisco`, `Remote`).
- **Remote jobs only**: Restrict results to remote-friendly opportunities.
- **Posted within N days**: Keep only recent postings published within a specified number of days.
- **Full-text description keywords**: Search inside job descriptions for specific skills, tech stacks, or qualifications.

### Extract job postings with compensation and salary data

Lever job descriptions frequently publish compensation ranges, salary bands, and benefits. Setting `includeDescription` to `true` extracts the complete text for salary analysis, LLM processing, or job market intelligence.

### Track hiring trends and new postings over time

By combining `postedWithinDays` with scheduled daily or weekly runs, you can track hiring velocity, new opening announcements, and team expansions across your target company list.

### Pricing

Pay per event: **$0.003 per job returned**, with tiered volume discounts on every Apify plan tier. You are billed only for completed rows returned to your dataset. Unreachable boards, empty results, or queries that match no filters cost nothing.

### ❓ FAQ

**Do I need a Lever API key or account?**
No. This scraper accesses Lever's public job board endpoints over plain HTTP. No authentication, API key, or credentials are required.

**How many company boards can I scrape in one run?**
You can include up to 200 company board slugs per run.

**Why does each dataset row use `companyName` as its identifier?**
`companyName` identifies the employer hiring for the role, allowing dataset items to be aggregated cleanly per employer across pages.

**Can an AI agent or LLM invoke this Actor?**
Yes. The input and dataset schemas are fully typed and documented for agentic integration via the Apify platform and MCP.

**What happens if a company board slug is invalid or closed?**
If a board is 404 or inactive, it is skipped cleanly and noted in the status log without failing the run or charging any fee.

***

Unofficial - not affiliated with Lever. Collects public data only. reapx.
Contact reapxdev@proton.me.

### ⬇️ Input

Every field is optional unless marked. Run it with no input at all to get a sensible default slice.

| Field | Type | Required | What it does |
| --- | --- | --- | --- |
| `companies` | array | no | One entry per company. Paste the board slug (e.g. "spotify") or full URL (e.g. "https://jobs.lever.co/spotify"). Example: spotify, palantir, coins,… |
| `titleKeywords` | array | no | Case-insensitive filter. Keeps postings whose title contains at least one of these keywords. Example: engineer, developer. Leave this field empty to… |
| `excludeTitleKeywords` | array | no | Case-insensitive exclusion filter. Drops postings whose title contains any of these keywords. Example: intern, contract. Leave this field empty to… |
| `departmentKeywords` | array | no | Matched against department and team names. Example: engineering, sales, product. Leave this field empty to include every option. |
| `locationKeywords` | array | no | Matched against location and allLocations fields. Example: San Francisco, London, Remote. Leave this field empty to include every option. |
| `descriptionKeywords` | array | no | Full-text keyword search inside the job description. Example: Python, Kubernetes, React. Leave this field empty to include every option. |
| `workplaceTypes` | array | no | Filter by workplace environment as published by Lever. Example: remote, hybrid, on-site. Leave this field empty to include every option. |
| `remoteOnly` | boolean | no | Keep only postings whose workplace type or location indicates remote work. Example: true. |
| `postedWithinDays` | integer | no | Filter by posting creation date in days. Example: 30 for jobs posted in the past month. The higher the number, the longer the run takes and the more… |
| `includeDescription` | boolean | no | Adds descriptionText to every output row. Turn off for a compact feed. Example: true. |
| `includeDescriptionHtml` | boolean | no | Adds descriptionHtml with original HTML formatting. Example: false. |
| `maxItems` | integer | no | Maximum number of total job postings returned across all company boards. Example: 200. The higher the number, the longer the run takes and the more you… |
| `maxItemsPerCompany` | integer | no | Cap the number of postings returned per single company board. Example: 50. The higher the number, the longer the run takes and the more you are… |

### ⬆️ Output

One row per record, as JSON, CSV, Excel or XML — and through the API.

| Field | What it gives you |
| --- | --- |
| `title` | Job title |
| `companyName` | Company |
| `location` | Location |
| `department` | Department |
| `commitment` | Commitment |
| `workplaceType` | Workplace |
| `publishedDate` | Published |
| `hostedUrl` | Posting link |
| `team` | Team |
| `jobId` | Job ID |
| `applyUrl` | Apply link |
| `isRemote` | Remote |
| `country` | Country |
| `descriptionText` | Description |
| `scrapedAt` | Scraped at |

### 🧪 Example input

A real, runnable configuration — this is an actual input this Actor has run with.

```json
{
  "companies": [
    "coins",
    "finix",
    "capital",
    "nium",
    "anchorage",
    "ro"
  ],
  "maxItems": 200,
  "includeDescription": true,
  "includeDescriptionHtml": false
}
```

### 📄 Sample output

One real row from a real run of this Actor, unedited.

```json
{
  "jobId": "890b2c0f-f46f-4a4b-bb73-3a6af6e0edd5",
  "companyName": "Spotify",
  "title": "Advertiser Solutions Vendor Lead - Programmatic and Direct Support",
  "commitment": "Permanent",
  "department": "Advertising",
  "team": "Advertising Sales - Emerging and Scaled Sales",
  "location": "London",
  "allLocations": [
    "London"
  ],
  "country": "GB",
  "workplaceType": "hybrid",
  "isRemote": false,
  "createdAt": 1784569799619,
  "publishedAt": "2026-07-20T17:49:59.619000Z",
  "publishedDate": "2026-07-20",
  "descriptionText": "Sell what you love. For us and millions of users across the globe, that’s Spotify. Join the Sales team and you’ll build the relationships that help grow our business in existing markets and beyond. We don’t just sell creative solutions to our clients and partners, we help to shape them; using our expert knowledge of ad products, sales channels and the industry to impact the way the world experiences music and podcasts.",
  "descriptionHtml": null,
  "hostedUrl": "https://jobs.lever.co/spotify/890b2c0f-f46f-4a4b-bb73-3a6af6e0edd5",
  "applyUrl": "https://jobs.lever.co/spotify/890b2c0f-f46f-4a4b-bb73-3a6af6e0edd5/apply",
  "scrapedAt": "2026-08-03T10:53:09.506383Z"
}
```

### How it works

1. You set the filters below, or none at all.
2. The Actor calls the source's own public endpoint and pages through the results.
3. Every row is pushed to the dataset **as it is built**, not buffered to the end — so a
   run that hits its time limit still returns everything it collected up to that point.
4. You are charged per row returned, so the maximum-results field is also your cost cap.

### 💬 Your feedback

Found a bug, or need a field this does not return yet? Open an issue on the Actor's **Issues**
tab, or write to **reapxdev@proton.me**. Bugs get fixed and reasonable field requests get
added.

### ⚠️ Run outcomes and error handling

This Actor reports what happened in the run's **status message**, and it always keeps whatever it collected. These are the outcomes you can get and what each one means.

| Outcome | What it means |
|---|---|
| **Success** | Rows were returned and you were charged `job-returned` at $0.003 per row. |
| **No matches** | The source returned nothing for your filters. **Nothing is charged.** Widen the date window or drop a filter. |
| **Partial - source refused** | The source rate-limited or refused some requests. The affected items are skipped and named in the log, and **everything already collected is still pushed**. A block never discards a run's work. |

#### What is guaranteed either way

- **Every row is pushed as it is built**, not buffered to the end of the run. Anything that buffers output loses everything to a timeout, a block or a migration; this does not.
- **A field absent from the source is absent from the row.** Nothing is inferred, modelled or filled in to make a row look complete.

# Actor input Schema

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

One entry per company. Paste the board slug (e.g. "spotify") or full URL (e.g. "https://jobs.lever.co/spotify"). Example: spotify, palantir, coins, qonto. Leave empty to run sample boards.

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

Case-insensitive filter. Keeps postings whose title contains at least one of these keywords. Example: engineer, developer.<br><br>Leave this field empty to include every option.

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

Case-insensitive exclusion filter. Drops postings whose title contains any of these keywords. Example: intern, contract.<br><br>Leave this field empty to include every option.

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

Matched against department and team names. Example: engineering, sales, product.<br><br>Leave this field empty to include every option.

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

Matched against location and allLocations fields. Example: San Francisco, London, Remote.<br><br>Leave this field empty to include every option.

## `descriptionKeywords` (type: `array`):

Full-text keyword search inside the job description. Example: Python, Kubernetes, React.<br><br>Leave this field empty to include every option.

## `workplaceTypes` (type: `array`):

Filter by workplace environment as published by Lever. Example: remote, hybrid, on-site.<br><br>Leave this field empty to include every option.

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

Keep only postings whose workplace type or location indicates remote work. Example: true.

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

Filter by posting creation date in days. Example: 30 for jobs posted in the past month.<br><br>The higher the number, the longer the run takes and the more you are charged, because you pay per row returned.

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

Adds descriptionText to every output row. Turn off for a compact feed. Example: true.

## `includeDescriptionHtml` (type: `boolean`):

Adds descriptionHtml with original HTML formatting. Example: false.

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

Maximum number of total job postings returned across all company boards. Example: 200.<br><br>The higher the number, the longer the run takes and the more you are charged, because you pay per row returned.

## `maxItemsPerCompany` (type: `integer`):

Cap the number of postings returned per single company board. Example: 50.<br><br>The higher the number, the longer the run takes and the more you are charged, because you pay per row returned.

## Actor input object example

```json
{
  "companies": [
    "spotify",
    "palantir",
    "coins",
    "qonto",
    "ro",
    "lalamove"
  ],
  "remoteOnly": false,
  "includeDescription": true,
  "includeDescriptionHtml": false,
  "maxItems": 200
}
```

# Actor output Schema

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

Every record found by this run, one row per item, in the default dataset. Switch between views in Console.

# 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": [
        "spotify",
        "palantir",
        "coins",
        "qonto",
        "ro",
        "lalamove"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("reapx/lever-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": [
        "spotify",
        "palantir",
        "coins",
        "qonto",
        "ro",
        "lalamove",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("reapx/lever-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": [
    "spotify",
    "palantir",
    "coins",
    "qonto",
    "ro",
    "lalamove"
  ]
}' |
apify call reapx/lever-jobs-scraper --silent --output-dataset

```

## MCP server setup

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