Lever Jobs Scraper - Career Postings avatar

Lever Jobs Scraper - Career Postings

Pricing

from $3.00 / 1,000 job scrapeds

Go to Apify Store
Lever Jobs Scraper - Career Postings

Lever Jobs Scraper - Career Postings

Scrape all open postings from any Lever career site: title, team, commitment, workplace type, country and the direct apply link. No API key, no login, no proxy.

Pricing

from $3.00 / 1,000 job scrapeds

Rating

0.0

(0)

Developer

Renzo Madueno

Renzo Madueno

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

Lever Jobs Scraper — Career Site Postings

Scrape every open posting from any Lever career site by slug. No API key, no login, no cookies, no proxy, no browser. Lever's public postings endpoint returns the full job — description, requirement bullets, team, commitment, workplace type and country — in a single request.

Lever is the ATS behind a distinctive slice of the market: companies that adopted it early and stayed. That means less overlap with Greenhouse-heavy datasets and a set of postings most job aggregators miss.


Read this before you build a company list

Most companies are not on Lever. This is the single most common surprise, and it is not a bug in this Actor. We probed thirteen well-known company slugs and got:

  • 404 (no Lever site at all): shopify, figma, brex, ramp, notion, linear, netflix, github, cohere, sourcegraph
  • 200 with an empty list (on Lever, nothing open right now): plaid, mistral
  • 200 with postings: spotify (95), palantir (308), ro (51)

The Actor treats those three outcomes as three different things and reports them separately:

  • company_not_on_lever — HTTP 404. The slug does not exist on Lever.
  • no_open_roles — HTTP 200 with []. The company IS on Lever, it just has nothing posted today.
  • delivered rows — the third case.

Feeding a list of 20 companies and having 15 come back company_not_on_lever is the normal, expected outcome. The FAILURES record even gives you the list under a dedicated notOnLever key so you can prune your input for next time.


What you get, with the fill rate actually measured

Measured across 3 real sites — 454 live postings (spotify, palantir, ro):

FieldFill rateNotes
title100%Lever calls this text, not title — a classic parsing trap, handled
jobId100%Lever UUID
location100%From categories.location
locations[]100%From categories.allLocations
country100%ISO-2 country code at the posting root
department100%
team100%
employmentType98.7%Normalised from categories.commitment
workplaceType100%Lever publishes hybrid / remote / onsite on every posting
isRemote100%100% from Lever's own fieldremoteSource: "ats_field" on every row
postedAt100%Converted from Lever's epoch-millisecond createdAt
jobUrl100%hostedUrl
applyUrl100%applyUrl — a genuinely different URL that opens the application form
descriptionText100%Description plus the "additional" block, concatenated
descriptionHtmlon requestOff by default
openingText~100%The opening paragraph on its own
requirementListson requestStructured bullet lists, see below
salaryMin / salaryMax / salaryText64.3%Parsed from text, see below

Two URLs, not one

Lever is one of the few ATSs where the posting URL and the apply URL genuinely differ:

  • jobUrlhttps://jobs.lever.co/palantir/ac978161-... — the posting page
  • applyUrlhttps://jobs.lever.co/palantir/ac978161-.../apply — straight into the form

Both are returned on 100% of rows. Use applyUrl for anything automated.

Requirement lists: structure other scrapers throw away

Lever stores the "What We Require" / "What We Value" bullet sections as structured data, not prose. Set includeRequirementLists: true and you get:

"requirementLists": [
{ "heading": "What We Require",
"items": ["At least three years of previous administrative experience", "..."] },
{ "heading": "What We Value",
"items": ["Ability to adjust quickly and anticipate needs", "..."] }
]

That is the raw material for requirement extraction, skills tagging or seniority classification, and you do not have to run an LLM over a wall of HTML to get it. Off by default because it adds weight.

Salary: 64.3%, and it is parsed

Lever's schema has a salaryRange field, but it is opt-in per company and was empty on all 454 postings we measured — 0% fill. Anyone advertising a structured Lever salary field is describing a field that exists but nobody populates.

So we parse the description text, which gets a credible range on 64.3% of postings — the highest text-parse rate of any ATS in this fleet, because Lever's customer base skews toward jurisdictions with pay-transparency rules. Every hit is marked salarySource: "description" and keeps the original snippet in salaryText. If a company ever does populate salaryRange, we prefer it and mark it ats_structured.

Ranges are sanity-checked: a "range" whose max is more than 30× its min is discarded rather than reported. European decimal formatting (€92.300 — €130.000) is read correctly as 92300–130000.


Input

{
"companies": ["spotify", "palantir", "ro"],
"maxItems": 1000,
"teamKeywords": ["Engineering"],
"remoteOnly": false,
"includeRequirementLists": true
}

Accepted company formats

spotify
https://jobs.lever.co/spotify
https://jobs.lever.co/spotify/ac978161-6f46-4f6b-ad9e-a258e642751c
https://jobs.eu.lever.co/spotify
https://api.lever.co/v0/postings/spotify

Input aliases

  • companies: companies, company, boards, sites, companyUrls, startUrls
  • limit: maxItems, maxResults, limit, maxJobs
  • keywords: titleKeywords, keywords, searchTitle
  • locations: locationKeywords, locations, location
  • teams: teamKeywords, teams, team, departments, department
  • commitment: commitments, commitment, employmentTypes, jobTypes
  • descriptions: includeDescription, includeContent, fullDescription

Filters

OptionWhat it does
maxItemsHard ceiling on rows written. This is your spend cap.
maxJobsPerCompanyStops a 308-posting site from eating the budget
titleKeywordsSubstring match on the title
locationKeywordsMatches location and every entry in locations[]
teamKeywordsMatches Lever's team and department
commitmentsFull-time, Part-time, Intern, Contract
remoteOnlyOnly isRemote: true
postedAfterISO date
includeRequirementListsAdds the structured bullet lists
dedupeDrops repeat ids and repeat company+title+location
concurrencySites in parallel, 1–15, default 5

Output sample

{
"source": "lever",
"companyToken": "ro",
"companyName": "ro",
"jobId": "f25a6c49-5ed4-4aa0-a5bb-b30e9790f90c",
"title": "Compounding Pharmacy Technician - Romeoville, IL",
"department": "Pharmacy",
"team": "Pharmacy",
"employmentType": "FULL_TIME",
"location": "Romeoville, IL",
"locations": ["Romeoville, IL"],
"country": "US",
"isRemote": false,
"workplaceType": "ONSITE",
"remoteSource": "ats_field",
"salaryMin": 23,
"salaryMax": 27,
"salaryCurrency": "USD",
"salaryInterval": "HOUR",
"salaryText": "$23 - $27",
"salarySource": "description",
"postedAt": "2025-06-17T00:24:42.479Z",
"jobUrl": "https://jobs.lever.co/ro/f25a6c49-5ed4-4aa0-a5bb-b30e9790f90c",
"applyUrl": "https://jobs.lever.co/ro/f25a6c49-5ed4-4aa0-a5bb-b30e9790f90c/apply",
"scrapedAt": "2026-08-22T04:13:58.220Z"
}

Four saved dataset views ship with the Actor: Job overview, Remote & locations, Compensation and Apply links.


Employment types are passed through honestly

Lever lets companies write their own commitment labels, and they do. Across 454 postings we saw FULL_TIME (308), PERMANENT (86), INTERNSHIP (38), FIXED_TERM (4), PART_TIME (4), CONTRACT (4), SHORT_TERM (3) and SCHOLARSHIP (1).

We normalise the ones with a standard meaning and pass the rest through uppercased rather than forcing them into a bucket they do not belong in. PERMANENT is not silently rewritten to FULL_TIME, because in the country where that posting was written they are not the same thing.


How errors are handled

Errors never enter your dataset. They go to the FAILURES record in the run's key-value store, which for this Actor includes a dedicated notOnLever array listing exactly which of your slugs returned 404:

{
"runFailed": false,
"sitesRequested": 3,
"sitesWithJobs": 1,
"notOnLever": ["figma"],
"jobsDelivered": 10,
"duplicatesDropped": 0,
"byReason": { "company_not_on_lever": 1, "no_open_roles": 1 }
}

If nothing was delivered, the run ends FAILED with the reason breakdown. An empty dataset is never reported as success.


Pricing and the free tier

Pay per event:

  • Actor start — one small charge per gigabyte of memory
  • Job scraped — charged after the row is written

Rows are pushed in batches and only rows that landed are billed. Filtered-out postings, deduplicated repeats and every kind of failure cost you nothing. Given how often Lever slugs 404, that matters here more than anywhere else in the fleet: a company that turns out not to be on Lever costs you nothing at all.

The free tier returns real data. No API key, no proxy, no credentials. {"companies": ["spotify"], "maxItems": 10} on a free account returns ten real jobs.


Speed

One HTTP request per site, gzip-compressed. Boards can be around 1 MB, which is exactly why compression is requested on every call. Measured: 454 postings across 3 sites in under 10 seconds. Retries use exponential backoff on 429/5xx and never fire on 404 — a 404 is an answer, not a failure.


Common questions

Do I need a Lever API key? No. api.lever.co/v0/postings/<slug>?mode=json is the public postings feed. The authenticated Lever API is a different product.

How do I find a company's slug? It is the path segment in their Lever URL: jobs.lever.co/spotify means spotify. If their careers page is on their own domain, check the page source for a jobs.lever.co link.

Why is the title in a field called text? That is Lever's schema, not ours. We map it to title for you, which is precisely the bug that breaks naive scrapers.

Does the EU host work? Yes, jobs.eu.lever.co/<slug> URLs are parsed correctly.

Why is postedAt the same as updatedAt? Lever's public feed exposes only createdAt. We surface it in both rather than inventing a modification date we do not have.

How fresh is the data? Live on every run.


  • Greenhouse Jobs Scraper — the largest board population
  • Ashby Jobs Scraper — structured salary numbers on ~72% of postings
  • Workday Jobs Scraper — enterprise career sites by URL
  • Startup Jobs Aggregator — company handles in, one deduplicated schema out across Greenhouse, Ashby and Lever, so you stop guessing which ATS a company uses

This Actor reads a public, unauthenticated JSON endpoint that Lever publishes so job boards and aggregators can syndicate postings. It sends no credentials, solves no challenges and bypasses no access control. You are responsible for how you use the data, including any applicable data-protection rules.