# Lever Jobs Scraper \[Free💰] | 1 Request/Board | Salary Data (`ahmed_jasarevic/jobs-lever-scraper`) Actor

Scrape every open job from any Lever company board in one request per company — title, team, location, remote flag, salary range, full description and apply URL. Free to run: no browser, no proxy, no per-job fee. Ideal for job aggregators, hiring-intent research and compensation benchmarks.

- **URL**: https://apify.com/ahmed_jasarevic/jobs-lever-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 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/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

## Lever Jobs Scraper — Free Job Board Data From Any Lever Company

**Get every open job from any Lever-hosted company board in a single HTTP request per company.** This Actor pulls the complete, structured job feed straight from Lever's public postings API — title, company, location, remote flag, team, department, commitment type, salary range, full description, apply URL and posted date — into one clean dataset.

It is **free to run** (you pay only Apify platform usage, never a per-job fee) and uses Lever's own public API rather than rendering pages, so a company with 916 open roles costs the same single request as a company with 3. Built for **job aggregators, recruiting agencies, hiring-intent lead generation and compensation benchmarking**.

***

### Use Cases: Job Aggregators, Hiring Research & Salary Data

- **Job board aggregation** — mirror any number of Lever career boards into one normalized feed for your own board, app or database.
- **Hiring-intent lead generation** — spot which companies are actively expanding a team (a company adding SDRs is a sales signal) and target them.
- **Recruiting agency & client research** — pull a client's or prospect's full Lever board to see team structure, seniority mix and open headcount.
- **Compensation benchmarking** — collect structured `salaryMin` / `salaryMax` / `salaryCurrency` / `salaryInterval` columns from pay-transparent employers, and fall back to regex-parsed free-text ranges elsewhere.
- **Remote-work monitoring** — filter to roles Lever flags as remote (or whose location contains "Remote") to track the remote-first market.
- **Talent-market & labour-market analysis** — track posting volume, department mix and salary bands over time across a watchlist of companies.

***

### How It Works: 1 HTTP Request Per Lever Company Board

```
GET https://api.lever.co/v0/postings/{companySlug}?mode=json
```

This is Lever's own publicly documented postings endpoint — the same machine-readable feed that powers a Lever-hosted careers page. It returns a **JSON array containing every open posting for that company in one response**. There is no pagination and no cursor: the response *is* the complete dataset.

Verified response shape (one array element):

```json
{
    "id": "9a30f231-9e7d-42bf-afab-59ede687eb41",
    "text": "Account Manager",
    "hostedUrl": "https://jobs.lever.co/dlocal/9a30f231-...",
    "applyUrl": "https://jobs.lever.co/dlocal/9a30f231-.../apply",
    "country": "AR",
    "workplaceType": "hybrid",
    "createdAt": 1787601815520,
    "categories": {
        "commitment": "Full Time",
        "department": "Commercial",
        "team": "Account Management & Partnerships",
        "location": "Buenos Aires",
        "allLocations": ["Buenos Aires", "Montevideo", "Sao Paulo (Hybrid)"]
    },
    "description": "<div>…</div>",
    "descriptionPlain": "…",
    "additionalPlain": "…",
    "lists": [{ "text": "What will I be doing?", "content": "<div><li>…</li></div>" }],
    "salaryRange": { "min": 110000, "max": 175000, "currency": "USD", "interval": "per-year-salary" },
    "salaryDescriptionPlain": "This range represents base compensation only…"
}
```

**Why this endpoint instead of the HTML board:**

| Approach | Requests per company | JS required | Anti-bot | Fields available |
| --- | --- | --- | --- | --- |
| `jobs.lever.co/{slug}` HTML + Cheerio | 1–many (paginated, `?page=2`…) | No | Mild | Missing salary, needs CSS selectors |
| `application/ld+json` per posting page | 1 **per job** | No | Mild | Title/location/date only, no team/salary |
| Browser rendering | 1 **per job** | Yes | Heavy | Same as HTML |
| **`api.lever.co/v0/postings/{slug}?mode=json`** | **1 per company** | **No** | **None** | **Everything** |

No API key, no session, no cookies, no browser. **This Actor makes exactly one HTTP request per company board** (see [Regional fallback hosts](#regional-fallback-hosts) for the one exception).

#### Regional fallback hosts

Some Lever boards are served from region-specific hosts. A board at `jobs.eu.lever.co/{slug}` is backed by `api.eu.lever.co`. The Actor automatically walks this chain until one responds with a JSON array:

```
https://api.lever.co
  → https://api.eu.lever.co
    → https://api.uk.lever.co
      → https://api.ca.lever.co
```

Verified example: `api.lever.co/v0/postings/lever` returns an empty board, while `api.eu.lever.co/v0/postings/lever?mode=json` returns 6 live postings. **This is why an EU or UK Lever board is often invisible to tools that only call the global host** — and why competitors that make you pick an "instance" manually return zero rows for the wrong one.

#### How company slugs are discovered

The slug is the path segment of a Lever board URL. `https://jobs.lever.co/dlocal/9a30f231-…` → `dlocal`. The Actor accepts **either** a bare slug or any full board/API URL and parses the slug for you, so you can paste whatever a recruiter sent you.

#### Salary handling

- **Structured (preferred):** Lever's `salaryRange` object → `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryInterval` (normalised to `YEAR` / `HOUR` / `MONTH` / `WEEK` / `DAY` / `PROJECT`). `salaryStructured: true` marks these.
- **Fallback (regex):** some employers write the range as free text instead of configuring the field. The Actor scans the description for patterns like `$120,000 – $180,000`, `USD 90.000 - 110.000`, `£50k–£60k` and infers currency and interval from surrounding text. `salaryStructured: false` marks these.

⚠️ **Not every Lever board discloses salary.** Lever only returns a range when the hiring company has enabled and filled in the field. On a mixed sample measured by this Actor's author, roughly 3% of postings carried a structured range — use the `requireSalary` input to filter down to pay-transparent employers. That is a feature for labour-market analysts, not a bug.

***

### Input: Lever Company Slugs, URLs & Filters

| Field | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `companySlugs` | `array` | No | `["dlocal","veeva","foundation-llm-technologies","arcadia","alloy","leverdemo"]` | Lever slugs or full board URLs. One HTTP request each. **Takes priority over `startUrls`.** |
| `startUrls` | `array` | No | `[]` | Alternative to `companySlugs` — paste board/API URLs. **Ignored if `companySlugs` is filled in.** |
| `companyNames` | `object` | No | `{}` | Optional slug → display-name map, e.g. `{"dlocal":"dLocal"}`. Affects the `company` output field only. |
| `maxCompanies` | `integer` | No | `100` | Max company boards per run. |
| `maxItems` | `integer` | No | `2000` | Max job rows pushed to the dataset. Free-plan users are additionally capped at 10 rows. |
| `maxRequestsPerCrawl` | `integer` | No | `200` | Hard ceiling on HTTP requests. Each board costs 1; a regional fallback walk can cost up to 4. |
| `remoteOnly` | `boolean` | No | `false` | Only output roles Lever marks remote. |
| `requireSalary` | `boolean` | No | `false` | Only output roles that expose a salary range (structured or regex-parsed). |
| `includeHtml` | `boolean` | No | `false` | Also output raw `descriptionHtml`. Plain-text `description` is always included. |
| `userAgent` | `string` | No | Desktop Chrome UA | Optional User-Agent override. |
| `proxy` | `object` | No | `{ "useApifyProxy": false }` | Standard Apify proxy picker. Off by default — this API needs no proxy. |

***

### Output: Job Title, Team, Location, Salary & Apply URL Fields

One dataset row per job posting:

```json
{
    "postingId": "eeb266e8-5960-4578-8eb9-05ced9dccd75",
    "title": "CAD Integrations Backend Engineer",
    "company": "Foundation Llm Technologies",
    "companySlug": "foundation-llm-technologies",
    "location": "Boston, MA",
    "locations": ["Boston, MA", "Remote"],
    "remote": true,
    "workplaceType": "remote",
    "team": "Engineering",
    "department": null,
    "commitment": "Full-time Exempt",
    "country": "US",
    "salaryMin": 110000,
    "salaryMax": 175000,
    "salaryCurrency": "USD",
    "salaryInterval": "YEAR",
    "salaryStructured": true,
    "salaryText": "This range represents base compensation only…",
    "description": "You'll build the software that connects engineering intelligence to…",
    "sections": [{ "title": "What you'll do", "content": "…" }],
    "applyUrl": "https://jobs.lever.co/foundation-llm-technologies/eeb266e8-5960-4578-8eb9-05ced9dccd75/apply",
    "jobUrl": "https://jobs.lever.co/foundation-llm-technologies/eeb266e8-5960-4578-8eb9-05ced9dccd75",
    "postedAt": "2026-07-07T00:50:42.576Z",
    "postedAtTimestamp": 1783385442576,
    "scrapedAt": "2026-09-28T07:55:00.000Z"
}
```

You can download the dataset in JSON, CSV, Excel, XML, JSONL or HTML format.

#### Field reference

| Field | Type | Description | Coverage on a mixed sample |
| --- | --- | --- | --- |
| `postingId` | string | Lever's UUID for the posting | 100% |
| `title` | string | Job title (Lever's `text`) | 100% |
| `company` | string | Human-readable company name (overridable via `companyNames`) | 100% |
| `companySlug` | string | Lever board slug | 100% |
| `location` | string | Primary location | 100% |
| `locations` | array | All locations (Lever's `allLocations`) | 100% |
| `remote` | boolean | `true` if `workplaceType=remote` **or** a location contains "Remote" | 100% |
| `workplaceType` | string | `onsite` / `hybrid` / `remote` / `unspecified` | 100% |
| `team` | string | Lever "Team" category | 100% |
| `department` | string | null | Lever "Department" category | 98% |
| `commitment` | string | Employment type (`Full Time`, `Full-time Exempt`, `Contract`, …) | 99% |
| `country` | string | ISO country code of the primary location | 100% |
| `salaryMin` | number | null | Lower salary bound, numeric | ~3%\* |
| `salaryMax` | number | null | Upper salary bound, numeric | ~3%\* |
| `salaryCurrency` | string | null | `USD`, `EUR`, `GBP`, … | ~3%\* |
| `salaryInterval` | string | null | `YEAR` / `HOUR` / `MONTH` / `WEEK` / `DAY` / `PROJECT` | ~3%\* |
| `salaryStructured` | boolean | `true` = Lever's `salaryRange`; `false` = regex-parsed from text | 100% |
| `salaryText` | string | Verbatim salary blurb from the employer | — |
| `description` | string | Full plain-text description incl. employer custom sections | 100% |
| `descriptionBody` | string | null | Plain-text description body before custom sections are appended | 98% |
| `additional` | string | null | Employer additional-content block (Lever `additional`) | 12% |
| `sections` | array | Structured `{title, content}` blocks from Lever's `lists` | 99% |
| `descriptionHtml` | string | Raw description HTML — **only when `includeHtml: true`** | opt-in |
| `applyUrl` | string | Direct apply link | 100% |
| `jobUrl` | string | Public posting URL | 100% |
| `postedAt` | string | ISO-8601 posted date (from Lever's epoch-ms `createdAt`) | 100% |
| `postedAtTimestamp` | number | Original `createdAt`, epoch milliseconds | 100% |
| `scrapedAt` | string | ISO-8601 timestamp of when this run fetched the row | 100% |

\* Salary coverage depends entirely on what each employer publishes on Lever. Use `requireSalary: true` to isolate pay-transparent companies.

***

### Example Input: Pull Remote, Salary-Disclosed Roles from 3 Lever Boards

```json
{
    "companySlugs": ["dlocal", "veeva", "arcadia"],
    "remoteOnly": true,
    "requireSalary": true,
    "maxItems": 500
}
```

Full board URLs work identically — the slug is parsed out:

```json
{
    "companySlugs": [
        "https://jobs.lever.co/dlocal",
        "https://jobs.eu.lever.co/lever",
        "api.lever.co/v0/postings/arcadia?mode=json"
    ],
    "companyNames": {
        "dlocal": "dLocal",
        "veeva": "Veeva Systems"
    },
    "remoteOnly": true
}
```

***

### Example Output: One Normalized Row per Lever Job Posting

```json
{
    "postingId": "9a30f231-9e7d-42bf-afab-59ede687eb41",
    "title": "Account Manager",
    "company": "dLocal",
    "companySlug": "dlocal",
    "location": "Buenos Aires",
    "locations": ["Buenos Aires", "Montevideo", "Sao Paulo (Hybrid)"],
    "remote": false,
    "workplaceType": "hybrid",
    "team": "Account Management & Partnerships",
    "department": "Commercial",
    "commitment": "Full Time",
    "country": "AR",
    "salaryMin": 110000,
    "salaryMax": 175000,
    "salaryCurrency": "USD",
    "salaryInterval": "YEAR",
    "salaryStructured": true,
    "salaryText": "This range represents base compensation only…",
    "description": "About the role…",
    "sections": [
        { "title": "What will I be doing?", "content": "…" },
        { "title": "Who are we looking for", "content": "…" }
    ],
    "applyUrl": "https://jobs.lever.co/dlocal/9a30f231-9e7d-42bf-afab-59ede687eb41/apply",
    "jobUrl": "https://jobs.lever.co/dlocal/9a30f231-9e7d-42bf-afab-59ede687eb41",
    "postedAt": "2026-07-07T00:50:42.576Z",
    "postedAtTimestamp": 1787601815520,
    "scrapedAt": "2026-09-28T07:55:00.000Z"
}
```

Rows are normalised across companies: Lever clients configure commitment inconsistently (`"Full Time"`, `"Full-time"`, `"Full-time Exempt"`), so you get one clean `commitment` column, a single `remote` boolean, one `workplaceType` vocabulary, and consistent ISO-8601 dates.

***

### Integrations & Automation: Schedule, Webhooks & API Access

- **REST API** — `POST https://api.apify.com/v2/acts/ahmed_jasarevic~jobs-lever-scraper/runs`, then read the dataset. Example:

  ```bash
  curl -X POST "https://api.apify.com/v2/acts/ahmed_jasarevic~jobs-lever-scraper/runs?token=YOUR_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{ "companySlugs": ["spotify", "binance"], "remoteOnly": true, "maxItems": 500 }'
  ```

- **Python SDK / JavaScript SDK / n8n / Make / Zapier** — every Actor on Apify is callable from all of them.

- **Webhooks** — attach a webhook to the run to push each finished dataset straight into your database, CRM or Slack channel.

- **Schedules** — the recommended cadence for this data:
  - **Hourly** if you are powering job alerts or a live aggregator (Lever's feed is live, so hourly is meaningful, not wasteful).
  - **Daily** for hiring-intent monitoring and competitive-hiring research.
  - **Weekly** for compensation benchmarking and talent-market trend analysis.

- **Dataset exports** — JSON, CSV, Excel, XML, JSONL, HTML, or paginated straight from the API.

- **Incremental runs** — filter on `postedAt` in your own pipeline to keep only new postings between runs. This Actor has no built-in delta mode, so do the diff downstream (or on a short hourly schedule).

***

### Related Actors: Greenhouse, Indeed and Other Job Data Scrapers

- **[Greenhouse, Lever & Ashby Job Scraper API](https://apify.com/bovi/greenhouse-lever-ashby-job-scraper)** (`bovi/greenhouse-lever-ashby-job-scraper`) — six ATS platforms (Greenhouse, Lever, Ashby, Recruitee, SmartRecruiters, Personio) in one unified schema, with change detection between runs. The right pick if you need Lever **and** the other major ATS platforms in the same run.
- **[Lever.co Jobs API](https://apify.com/fantastic-jobs/lever-co-jobs-api)** (`fantastic-jobs/lever-co-jobs-api`) — Lever-only, but enriches every posting with AI-derived fields and LinkedIn company data, up to 60 fields per job. Best if you want enrichment rather than raw Lever fields.
- **[Indeed Job Scraper | Salary | Jobs | Company Data](https://apify.com/ahmed_jasarevic/indeed-job-scraper)** (`ahmed_jasarevic/indeed-job-scraper`) — the same job-market-research workflow on Indeed instead of Lever: salary ranges, company data and skills across many countries.
- **[Freelancer Jobs Scraper](https://apify.com/ahmed_jasarevic/freelancer-jobs-scraper)** (`ahmed_jasarevic/freelancer-jobs-scraper`) — real-time freelance project listings with budget, skills and country filters, if your market research also covers contract and freelance work.
- **[Job Postings Scraper — Greenhouse, Lever & Ashby](https://apify.com/bujhmml/ats-jobs-scraper)** (`bujhmml/ats-jobs-scraper`) — a lower-priced multi-ATS alternative (verified at $0.0004 per job) with keyword, location, department and remote filters.

> If your target companies are on **Greenhouse, Ashby, Workday, SmartRecruiters, iCIMS or Personio**, this Actor will not read them. Use one of the multi-ATS actors above.

***

### Free vs Pay-Per-Event Lever Scrapers: Verified Comparison

Every other Lever-only scraper on the Apify Store is billed per job. This Actor is free to run — you pay only Apify platform usage. Here is what that actually buys you, based on each actor's public Store listing:

| Capability | Pay-per-event Lever actors (verified) | This Actor |
| --- | --- | --- |
| Per-job fee | $0.0004 – $0.0031 per job across 8 Store listings (`bujhmml` $0.0004, `ninhothedev` $0.0005, `memo23` $0.00099, `benthepythondev` $0.00135, `bovi` $0.001485, `fantastic-jobs` $0.002, `fourwake` $0.002, `jobo.world` $0.0031) | **$0 per job** — free to use, Apify platform usage only |
| Cost of 1,000 jobs | ~$0.40 – ~$3.10 in per-job fees | $0 in per-job fees |
| EU / UK / CA boards | `logiover/lever-postings-scraper` exposes a manual global/EU "Instance" selector — pick wrong, get zero rows | Automatic host walk (`api.lever.co` → `.eu.` → `.uk.` → `.ca.`) until JSON returns |
| Structured salary | Varies by actor; several return `null` where Lever omits `salaryRange` | `salaryRange` → numeric columns **plus** a regex fallback for free-text ranges, with `salaryStructured` marking which is which |
| Company name → board resolution | Available in `fourwake`, `appdata-labs`, `deadlyaccurate` (600+ board registry) | Not available — pass a slug or board URL |
| Multi-ATS coverage | Available in `bovi`, `bujhmml`, `scrapersdelight`, `maydit` | Lever only |
| Built-in delta / change detection | Available in `blackfalcondata`, `nomad-agent`, `bovi`, `esco.api` | Not available — diff on `postedAt` yourself |
| AI enrichment / auto-translation | Available in `fantastic-jobs` (up to 60 fields), `memo23` (translation, email enrichment) | Not available — raw Lever fields, normalised |
| Requests per company board | 1 | 1 (up to 4 only when a regional fallback is needed) |

**Bottom line:** if you need enrichment, delta tracking or multi-ATS coverage, a pay-per-event actor is the better tool. If you want the raw Lever feed at scale — hundreds of boards, thousands of postings, run repeatedly on a schedule — paying per job is the single largest avoidable cost, and this Actor removes it.

***

### FAQ: Lever API, Salary Gaps, EU Boards & Alternatives

#### Why use this Actor instead of calling Lever's API directly?

You can, and it costs nothing — `curl "https://api.lever.co/v0/postings/dlocal?mode=json"` works. This Actor exists because the raw response is a *raw* response. It handles the parts you would otherwise rebuild:

- **Region fallback.** The global host returns an empty array for boards served from `api.eu.lever.co` / `api.uk.lever.co` / `api.ca.lever.co`. The Actor walks the chain automatically.
- **Salary normalisation.** `salaryRange.interval` is a verbose string (`per-year-salary`). You get `YEAR` / `HOUR` / `MONTH` / `WEEK` / `DAY` / `PROJECT` as clean values, plus a regex fallback for employers who write the range as prose.
- **Cross-company consistency.** `commitment` values differ per employer (`"Full Time"`, `"Full-time"`, `"Full-time Exempt"`). You get one vocabulary, one `remote` boolean, one `workplaceType` vocabulary and one date format.
- **Everything else the platform gives you** — datasets, schedules, webhooks, exports, run history and API access — which a bare `curl` loop does not.

#### What are the alternatives to this Actor?

- **Greenhouse, Ashby, Workday, SmartRecruiters, iCIMS, Personio or Recruitee boards** — different ATS, different public API. Use a multi-ATS Actor (see [Related Actors](#related-actors-greenhouse-indeed-and-other-job-data-scrapers)).
- **The vendor feed yourself** — free, no key, and legitimately syndication-grade. Lever's own `postings-api` docs state that published postings are publicly viewable and may be scraped by third parties. The cost is that you build the fallbacks, normalisation and scheduling yourself.
- **Paid aggregators** — services that normalise and deduplicate *across* all ATS platforms, not just Lever. Worth it if you need cross-platform dedup and normalised role titles; unnecessary if you already know your targets run on Lever.
- **Aggregator job boards (Indeed, LinkedIn, Glassdoor)** — they read the Lever XML feed for syndication, but lag behind the source, deduplicate loosely, and may not carry every posting. Good for breadth, poor for freshness or completeness.

#### Why is salary missing for some jobs?

Because the employer did not publish one. Lever only returns `salaryRange` when the company enables and fills in the field — a recruiting-company decision, not a scraping limitation. Independent measurement across 46,005 postings from 1,917 Lever boards found no reliable `pay` field on the endpoint, which matches what you see in practice. Use `requireSalary: true` to filter to employers that do disclose, and check `salaryStructured` to know whether a value came from Lever or from the regex fallback.

#### Why does a company I know is hiring show zero jobs?

Four likely causes, in order:

1. **Wrong region host** — the board lives on `api.eu.lever.co`, not `api.lever.co`. The Actor handles this automatically; a raw `curl` or an instance-picking tool will not.
2. **Wrong slug** — companies sometimes run multiple boards, and the slug is not always the company name. It is the path segment in `jobs.lever.co/{slug}`. Use `companyNames` to label the results sensibly.
3. **No public board** — some companies use a custom careers site or a different ATS entirely. Lever only exposes postings in the *published* state; anything in a draft or internal state is invisible by design.
4. **Caps** — `maxCompanies` (100) or `maxItems` (2000) truncated the run, or a free-plan account hit the 10-row cap.

An unknown or renamed slug is **not** an error. The Actor tries the four API hosts, logs a warning, and moves on — the rest of your run is unaffected.

#### What about companies that use Greenhouse, Ashby, Workday or SmartRecruiters?

Not supported. This Actor is Lever-only by design. See [Related Actors](#related-actors-greenhouse-indeed-and-other-job-data-scrapers) for multi-ATS options.

#### How fresh is the data, and how should I schedule it?

As fresh as the request — Lever's feed is live, and `postedAt` comes from Lever's own `createdAt` epoch timestamp, so it is a real publish date, not a re-scrape date. Use `postedAt` to drop stale postings. Schedule hourly for job alerts or a live board, daily for hiring-intent monitoring, weekly for benchmarking.

#### Can I find a company's Lever slug automatically?

Not in this Actor — pass the slug or the full board URL. If you do not know it, it is the first path segment of the company's careers-page link, or use an Actor that resolves company names/domains to boards (e.g. `fourwake/lever-jobs-api`, `appdata-labs/lever-jobs`).

#### How much does it cost to run?

Nothing per job. This Actor is **free to use** — you are only charged for Apify platform usage (compute). Compared with a pay-per-event Lever scraper at $0.0004–$0.0031 per job, 1,000 jobs means ~$0.40–$3.10 in per-job fees avoided. A run covering 10 company boards typically finishes in **under 10 seconds** at 256–512 MB RAM. Very large single boards (e.g. a 12.9 MB, 916-posting response) need the upper memory bound. Free-plan accounts are capped at 10 job rows per run; paid accounts are not.

***

### For AI Agents & LLM Apps

**Purpose:** given one or more Lever company slugs (or board URLs), returns one flat dataset row per open job posting with title, company, location, remote flag, team, department, commitment type, salary bounds, description and apply URL.

**Minimal working input** (smallest input that produces a valid run):

```json
{ "companySlugs": ["spotify"] }
```

**Variant — remote roles only:**

```json
{ "companySlugs": ["spotify", "binance"], "remoteOnly": true, "maxItems": 500 }
```

**Variant — pay-transparent roles only, as raw Lever fields with HTML:**

```json
{ "companySlugs": ["arcadia"], "requireSalary": true, "includeHtml": true, "maxItems": 200 }
```

**Output fields:** `postingId`, `title`, `company`, `companySlug`, `location`, `locations`, `remote`, `workplaceType`, `team`, `department`, `commitment`, `country`, `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryInterval`, `salaryStructured`, `salaryText`, `description`, `sections`, `applyUrl`, `jobUrl`, `postedAt`, `postedAtTimestamp`, `scrapedAt` — plus `descriptionHtml` when `includeHtml` is `true`.

**Behaviors an agent should know:**

- **`companySlugs` wins over `startUrls`.** If `companySlugs` is non-empty, `startUrls` is ignored entirely. Send one or the other, never both.
- **`startUrls` accepts anything board-shaped.** A bare slug, a `jobs.lever.co/{slug}` URL, a `jobs.eu.lever.co/{slug}/uuid` posting URL, or even an `api.lever.co/v0/postings/{slug}?mode=json` URL all resolve to the same slug. The `companySlugs` field does the same parsing.
- **Free-plan accounts are hard-capped at 10 dataset rows per run**, regardless of `maxItems`. This is an Apify plan limit, not an Actor input.
- **Regional fallback can multiply requests.** One board normally costs 1 HTTP request, but a board served from a non-global host can cost up to 4 (the `api.` → `api.eu.` → `api.uk.` → `api.ca.` walk). `maxRequestsPerCrawl` (default 200) bounds this — a watchlist of more than ~50 boards that all miss the global host can hit that ceiling and truncate the run. Raise it if you scrape a large EU/UK watchlist.
- **Caps stack in this order:** `maxCompanies` (default 100) → `maxRequestsPerCrawl` (default 200) → `maxItems` (default 2000). The first one hit truncates the run.
- **`proxy` defaults to `{ "useApifyProxy": false }` and needs no change.** The Lever postings endpoint has no anti-bot wall, so enabling the proxy adds cost for no benefit.
- **`companyNames` is presentational only.** It rewrites the `company` string; it does not affect matching, filtering or the `companySlug` join key.
- **`remoteOnly` is a heuristic, not a Lever flag read.** It is `true` when `workplaceType === "remote"` **or** any entry in `locations` contains the substring "Remote" — so a hybrid role listed as `"Boston, MA or Remote"` is included. Independent measurement across 46,005 Lever postings found only 4.8% carry an explicit remote workplace flag, so substring matching catches materially more rows than the flag alone.
- **`salaryStructured` is the field to branch on.** `true` means the value came from Lever's own `salaryRange` object. `false` means it was regex-parsed from free-text description prose, so treat it as lower-confidence and check `salaryText`. Rows with no discoverable range have `null` bounds and `salaryStructured: false`.
- **A dead or renamed slug is not an error.** The run logs a warning and continues. Do not treat a short result set as a failed run without checking the run log.
- **`sections` is the structured form of the description.** It is Lever's `lists` array, so "What you'll do" / "Qualifications" blocks are addressable by index instead of requiring text parsing.
- **Billing: no pay-per-event, no per-result charge.** Cost is Apify platform usage (compute time × memory) only. At 256–512 MB and sub-10-second runs, a 10-board run costs a fraction of a compute unit.

***

### Legal & Compliance Disclaimer

- This Actor is an independent community tool. It is **not affiliated with, endorsed by, or sponsored by Lever, Inc. (Employ)** or by any company whose job board you read. "Lever" is a trademark of its respective owner, used here only to describe the data source.
- What it actually does: it makes plain HTTP GET requests to Lever's **own publicly documented postings endpoint** (`api.lever.co/v0/postings/{slug}?mode=json` and its regional equivalents). It does not log in, does not bypass authentication, does not solve CAPTCHAs, does not use a browser, and does not circumvent any technical access control. It collects only the job advertisements companies publish for public candidate consumption.
- No personal data is collected. The output contains job advertisements, company names, locations and salary bands — corporate and role-level facts, not candidate records. Some employer-written descriptions may incidentally contain a recruiter's name or contact details; those are the employer's own published content.
- You are responsible for your own compliance. Review Lever's Terms of Service at [lever.co/legal](https://www.lever.co/legal), each target company's terms and `robots.txt`, and the data-protection and database-rights rules that apply to your jurisdiction and use case — GDPR in the EU/UK (including the EU sui generis database right for systematic reuse of a substantially-invested database), and CCPA/CPRA in California — before redistributing harvested job data commercially.
- If you republish descriptions verbatim, be aware they are employer-authored copyrighted text. Prefer using the structured fields and your own summaries for any commercial republication, and honour removal requests.
- The Actor is provided as-is, without warranty of accuracy, completeness or fitness for a particular purpose. Lever's data is supplied live and can change between runs.

***

### SEO Keywords

lever jobs scraper, lever jobs api, lever job board api, jobs.lever.co scraper, scrape lever jobs, api.lever.co postings, lever postings api, lever xml job feed, find lever job board, free lever jobs scraper, job board aggregator data, job aggregator api, startup jobs database, tech startup hiring data, hiring intent signals, recruiting lead generation, compensation benchmarking from job postings, salary range job data, remote job monitoring, talent market analysis, labour market analysis, eu lever jobs, uk lever jobs, canada lever jobs

# Actor input Schema

## `companySlugs` (type: `array`):

Company slugs from jobs.lever.co, e.g. 'dlocal'. Full board URLs (https://jobs.lever.co/dlocal) are accepted too — the slug is parsed out automatically. One HTTP request per board returns all of that company's postings.

## `startUrls` (type: `array`):

Optional. Lever board or API URLs to scrape, e.g. https://jobs.lever.co/dlocal or https://api.lever.co/v0/postings/dlocal. Ignored if companySlugs is filled in.

## `companyNames` (type: `object`):

Optional map of slug -> display name, e.g. {"dlocal": "dLocal"}. Used only for the 'company' output field.

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

Maximum number of company boards to fetch in one run (1 HTTP request each).

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

Maximum number of job rows to push to the dataset. Free users are additionally capped at 10.

## `maxRequestsPerCrawl` (type: `integer`):

Hard ceiling on HTTP requests. Each company board costs 1 request.

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

Only output jobs Lever flags as remote (workplaceType = remote or a location containing 'Remote').

## `requireSalary` (type: `boolean`):

Only output jobs that expose a salary range (structured salaryRange field or a parsed range in the description).

## `includeHtml` (type: `boolean`):

Include the raw descriptionHtml field in output. Plain-text 'description' is always included.

## `userAgent` (type: `string`):

Optional User-Agent override. A realistic desktop Chrome UA is used by default.

## `proxy` (type: `object`):

Select proxies to be used by your crawler.

## Actor input object example

```json
{
  "companySlugs": [
    "dlocal",
    "veeva",
    "foundation-llm-technologies",
    "arcadia",
    "alloy",
    "leverdemo"
  ],
  "startUrls": [],
  "companyNames": {},
  "maxCompanies": 100,
  "maxItems": 2000,
  "maxRequestsPerCrawl": 200,
  "remoteOnly": false,
  "requireSalary": false,
  "includeHtml": false,
  "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",
  "proxy": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (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 = {
    "companySlugs": [
        "dlocal",
        "veeva",
        "foundation-llm-technologies",
        "arcadia",
        "alloy",
        "leverdemo"
    ],
    "startUrls": [],
    "companyNames": {},
    "proxy": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/jobs-lever-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 = {
    "companySlugs": [
        "dlocal",
        "veeva",
        "foundation-llm-technologies",
        "arcadia",
        "alloy",
        "leverdemo",
    ],
    "startUrls": [],
    "companyNames": {},
    "proxy": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/jobs-lever-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 '{
  "companySlugs": [
    "dlocal",
    "veeva",
    "foundation-llm-technologies",
    "arcadia",
    "alloy",
    "leverdemo"
  ],
  "startUrls": [],
  "companyNames": {},
  "proxy": {
    "useApifyProxy": false
  }
}' |
apify call ahmed_jasarevic/jobs-lever-scraper --silent --output-dataset

```

## MCP server setup

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