Lever Jobs Scraper: Postings, Teams & Commitments avatar

Lever Jobs Scraper: Postings, Teams & Commitments

Pricing

from $0.74 / 1,000 posting scrapeds

Go to Apify Store
Lever Jobs Scraper: Postings, Teams & Commitments

Lever Jobs Scraper: Postings, Teams & Commitments

Pull every public posting from any Lever careers site: title, team, commitment, workplace type, location and full description. No login, no proxy, no browser.

Pricing

from $0.74 / 1,000 posting scrapeds

Rating

0.0

(0)

Developer

Arman Hossain

Arman Hossain

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

21 hours ago

Last modified

Share

Lever Jobs Scraper: Postings with typed salary ranges, workplace type and structured requirement blocks

Pulls every public posting from any Lever-hosted careers site. You get the title, team, department, commitment, workplace type, location list, requirement bullets, the salary range where the company publishes one, and the direct apply URL.

Lever runs the applicant tracking system behind thousands of startups and scale-ups, and every careers site is backed by a public endpoint. This Actor reads that endpoint directly, so there's no browser, no proxies, no login and no rate-limit games. A board with 400 postings comes back in a few seconds.

Agent skill: SKILL.md

https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/lever-jobs-scraper.md

What you get

FieldWhat it holds
companyThe Lever slug the posting came from
postingIdLever's UUID for the posting
titleJob title, which Lever calls text on the wire
team, department, levelLever's category taxonomy. department and level are only set by companies that use them
commitmentFree-text employment type, e.g. Full-time, Contract, Internship
workplaceTyperemote, onsite, hybrid or unspecified
location, allLocations, countryPrimary location, the full location list, and the ISO country code
categoriesThe raw Lever category object, kept verbatim
salaryRange, salaryDescription{ min, max, currency, interval } and any free-text pay note, when the company publishes them
descriptionPlainOpening and body as plain text, straight from Lever
listsRequirement and responsibility blocks as { text, items[] }, with bullets split into an array
additionalPlainThe closing "about the company" section as plain text
hostedUrl, applyUrlPosting page and the direct application form
createdAtPosting creation time, converted from Lever's epoch milliseconds to ISO 8601
scrapedAtWhen the run happened

RUN_SUMMARY in the key-value store holds per-run counts, the filters you used, and any company that failed.

Use cases

  • Portfolio hiring tracking. Watch every company a fund has invested in and diff headcount signals week over week.
  • Job aggregators. Ingest hundreds of Lever careers sites on a schedule into one normalised feed.
  • Remote-supply analysis. Count workplaceType: "remote" postings by team across a sector.
  • Lead generation. A company hiring three data engineers is a company buying data tooling.
  • Compensation research. Collect the salaryRange objects that pay-transparency laws now force onto public postings.

Quick start

Two companies, everything they have:

{
"companies": ["leverdemo", "spotify"]
}

Remote engineering roles only, capped:

{
"companies": ["leverdemo", "https://jobs.lever.co/ro"],
"searchTerms": ["engineer", "developer"],
"teamFilter": ["engineering"],
"workplaceType": ["remote"],
"maxJobsPerCompany": 50,
"includeDescription": true
}

A light sweep for change detection:

{
"companies": ["spotify"],
"includeDescription": false
}

Input

FieldTypeDefaultNotes
companiesarrayrequiredCompany slugs like leverdemo, or full careers URLs. You can mix both. URLs get normalised to slugs for you.
searchTermsarray[]Keep only titles containing one of these terms, case-insensitive. Empty means keep everything.
teamFilterarray[]Matched against team and department. Empty means all teams.
commitmentFilterarray[]Substring match, so full catches both Full-time and Regular Full Time (Salary). Empty means all.
workplaceTypearray[]Exact match on remote, onsite, hybrid, unspecified. on-site and on site are normalised to onsite. Empty means all.
locationFilterarray[]Matched against the primary location and every entry in allLocations. Empty means all locations.
maxJobsPerCompanyinteger0Cap postings saved per company, applied after filtering. 0 means no limit.
includeDescriptionbooleantrueInclude descriptionPlain, lists and additionalPlain. Turn it off for a far smaller dataset.

All filters are independent and combine with AND. A posting has to match at least one term in each filter you actually filled in.

Output example

A real record, trimmed only in descriptionPlain:

{
"company": "ro",
"postingId": "d2e897ae-3b4c-4219-ab0d-0403decc2115",
"title": "Engineering Manager, Core Infrastructure",
"team": "Engineering",
"department": null,
"level": null,
"commitment": "Full-time",
"workplaceType": "hybrid",
"location": "New York, NY",
"allLocations": ["New York, NY"],
"country": "US",
"categories": {
"commitment": "Full-time",
"location": "New York, NY",
"team": "Engineering",
"allLocations": ["New York, NY"]
},
"salaryRange": null,
"salaryDescription": null,
"descriptionPlain": "Join Tech @ Ro to build the future of healthcare, from the ground up .",
"lists": [
{
"text": "What You'll Do",
"items": [
"Lead and develop a Core Infrastructure team responsible for production-critical systems and foundational engineering capabilities.",
"Own execution across the team's portfolio: clarify priorities, sequence work, manage tradeoffs, and ensure high-quality delivery."
]
}
],
"additionalPlain": "The target base salary for this position ranges from $219,300 to $260,000 .",
"hostedUrl": "https://jobs.lever.co/ro/d2e897ae-3b4c-4219-ab0d-0403decc2115",
"applyUrl": "https://jobs.lever.co/ro/d2e897ae-3b4c-4219-ab0d-0403decc2115/apply",
"createdAt": "2026-06-15T13:33:29.004Z",
"scrapedAt": "2026-08-06T11:40:18.574Z"
}

This posting leaves salaryRange empty and states pay in prose instead, which is a common pattern. Where the structured field is filled in it looks like { "min": 108097, "max": 135121, "currency": "USD", "interval": "per-year-salary" }.

Finding a company slug

Open the company's careers page and look at the URL.

URL you seeSlug
jobs.lever.co/acmeacme
jobs.eu.lever.co/acmeacme
jobs.lever.co/acme/1234-5678acme

You can paste the whole URL and let the Actor pull the slug out. If a company's careers page sits on its own domain, view source and search for lever.co. The slug is almost always in an iframe or a fetch URL.

API example

curl -X POST "https://api.apify.com/v2/acts/arman-bd~lever-jobs-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"companies": ["leverdemo"],
"searchTerms": ["engineer"],
"maxJobsPerCompany": 25
}'

JavaScript example

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('arman-bd/lever-jobs-scraper').call({
companies: ['leverdemo', 'spotify'],
searchTerms: ['engineer'],
workplaceType: ['remote'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const job of items) console.log(`${job.company} - ${job.title} (${job.location})`);

Notes

  • Lever returns every posting in one response, so there is no pagination to walk. Filtering and maxJobsPerCompany are applied after the fetch, which means a capped run is not a cheaper request.
  • Timeouts are generous. Large boards return multi-megabyte payloads and Lever has been observed taking around 100 s, so each request gets 120 s before it is abandoned, with up to three attempts and linear backoff.
  • A bad slug won't kill the run. An unknown company returns HTTP 404 with {"ok":false,"error":"Document not found"} and lands in RUN_SUMMARY.failures. The Actor only errors out if every company fails.
  • Bullets are split, not stripped. Lever ships requirement blocks as a bare run of <li> elements, and each block becomes { text, items[] } so you can count or filter requirements without touching HTML.
  • Public data only. No authentication, no personal data, nothing that gets around access controls.

FAQ

Do I need a Lever API key? No. You supply no credentials.

Why is title not called text? Because Lever's wire field is text, which is unusable in a spreadsheet. It is renamed to title, and everything else keeps Lever's own naming.

Does every posting have a salary? No. salaryRange is populated only where the company filled it in, commonly for US roles covered by pay-transparency rules. Elsewhere it is null, and nothing is inferred.

Why did I get an empty array back? A valid slug with no open roles returns [] with HTTP 200, which is different from a wrong slug returning HTTP 404. RUN_SUMMARY distinguishes the two: the first shows 0 listed, the second shows up in failures.

Can I get only new postings? Run it on a schedule and diff on postingId. createdAt gives you a genuine first-seen date, so a daily run reconstructs a hiring timeline.

Can I plug it into something else? Yes. Apify API, the client libraries, webhooks, scheduled runs, dataset exports to JSON, CSV or Excel, or MCP. The output is structured JSON.