Lever Hiring Intelligence Scraper avatar

Lever Hiring Intelligence Scraper

Pricing

from $1.80 / 1,000 job-results

Go to Apify Store
Lever Hiring Intelligence Scraper

Lever Hiring Intelligence Scraper

Scrape public job postings from Lever-hosted career boards (global + EU) into clean, CSV-ready hiring-intelligence rows - no login, cookies, or paid APIs.

Pricing

from $1.80 / 1,000 job-results

Rating

0.0

(0)

Developer

Delowar Munna

Delowar Munna

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

Lever Hiring Intelligence Scraper

Scrape public job postings from Lever-hosted career boards — by board URL or by site slug — and turn them into clean, flat, CSV-ready rows, plus lightweight hiring-intelligence fields (team/department, derived seniority & workplace type, salary visibility, detected skills, and a transparent hiring-signal score + reason tags). Built for recruiters, sales teams, staffing agencies, job-board operators, and market researchers.

No login, no cookies, no API keys. The actor uses Lever's public Postings API (?mode=json) over HTTP — one request returns every published posting for a board — so it stays fast and cost-predictable. You pay one flat event per unique job row that passes your filters.

✨ Why this scraper

  • Lever-focused hiring intelligence — not a generic multi-ATS crawler. Every row carries derived signals useful for sales, recruiting, and market research.
  • Global + EU boardsjobs.lever.co / api.lever.co and jobs.eu.lever.co / api.eu.lever.co, with automatic region fallback.
  • Two input modes — paste Lever board/API URLs, or just list site slugs (netflix, benchling, figma).
  • 31 flat fields — job identity, company, categories, dates, description, salary, and hiring signals. No nested objects; drops straight into Sheets/Excel/CRMs.
  • Pay-Per-Event — one flat job-result event per saved unique job. Duplicates and filtered rows are never charged.
  • No browser — pure HTTP + JSON, so it is fast and light.

🚀 Quick start — sample inputs

Example 1 — site slugs + filters

{
"siteSlugs": ["netflix", "benchling"],
"region": "auto",
"maxResults": 500,
"query": "data",
"teams": ["Engineering", "Data"],
"commitments": ["Full-time"],
"workplaceTypes": ["remote", "hybrid"],
"seniorityLevels": ["senior", "manager", "director"],
"postedAfter": "2026-01-01",
"includeDescriptionText": true,
"deduplicate": true,
"proxyConfiguration": { "useApifyProxy": true }
}

Example 2 — board URLs + remote-only + custom residential proxy via your own provider

{
"startUrls": [{ "url": "https://jobs.lever.co/figma" }, { "url": "https://jobs.eu.lever.co/spotify" }],
"maxResults": 250,
"remoteOnly": true,
"includeDescriptionText": true,
"includeRawHtml": true,
"deduplicate": true,
"proxyConfiguration": {
"useApifyProxy": false,
"proxyUrls": ["http://user:pass@proxy.iproyal.com:12321"]
}
}

Provide at least one of startUrls or siteSlugs. URLs always use their own host's region; bare slugs use the region setting (auto tries global first, then EU).

The actor blocks Apify Residential proxy; if you need residential routing, supply your own provider via proxyConfiguration.proxyUrls. See 🚦 Proxy policy below.


📦 Output

The dataset has one view: Jobs & hiring signals — a 31-column flat table.

Lever Hiring Intelligence Scraper — all-fields table view

Output fields (31)

job_id, job_title, company_slug, company_name, team, department, location, commitment, workplace_type, seniority_level, posted_at, updated_at, hosted_url, apply_url, job_description_text, job_description_html, requirements_text, salary_text, salary_min, salary_max, salary_currency, has_salary, skills_keywords, hiring_signal_score, hiring_signal_label, reason_tags, source_platform, source_region, source_input, source_api_url, scraped_at.

Sample record — Jobs & hiring signals

Real actor output (from a run against Lever's public leverdemo board; the long text fields are truncated here with for readability):

{
"job_id": "317078f5-1943-44f4-9231-92f80dbdeb69",
"job_title": "Marketing Automation and Analytics Manager",
"company_slug": "leverdemo",
"company_name": "Leverdemo",
"team": "Product Marketing",
"department": "Marketing",
"location": "Minneapolis, MN",
"commitment": null,
"workplace_type": "unknown",
"seniority_level": "manager",
"posted_at": "2014-01-17T16:33:32.235Z",
"updated_at": null,
"hosted_url": "https://jobs.lever.co/leverdemo/317078f5-1943-44f4-9231-92f80dbdeb69",
"apply_url": "https://jobs.lever.co/leverdemo/317078f5-1943-44f4-9231-92f80dbdeb69/apply",
"job_description_text": "Welcome to the Demo Job Listing for Lever! This is a fictional job created solely for demonstration purposes…",
"job_description_html": null,
"requirements_text": "WHAT YOU'LL BE DOING (AND LOVING IT!): Lead the research, selection and implementation of marketing automation toolset for capturing, scoring, nurturing…",
"salary_text": null,
"salary_min": null,
"salary_max": null,
"salary_currency": null,
"has_salary": false,
"skills_keywords": "javascript, data modeling, salesforce, hubspot, marketo",
"hiring_signal_score": 50,
"hiring_signal_label": "medium",
"reason_tags": "high_value_department,senior_role,skills_detected,company_hiring_multiple_roles",
"source_platform": "lever",
"source_region": "global",
"source_input": "https://jobs.lever.co/leverdemo",
"source_api_url": "https://api.lever.co/v0/postings/leverdemo?mode=json",
"scraped_at": "2026-06-03T06:17:45.714Z"
}

This sample is from Lever's public leverdemo board (demo data, so salary is empty and the description is placeholder text). On real company boards these fields populate from the live posting.


🎯 Hiring-signal score

Transparent rule-based score (0–100) computed from visible scraped fields — no AI, no external enrichment.

SignalPoints
Posted within the last 14 days+20
Posted within the last 30 days (but over 14 days)+15
High-value department / role¹+15
Seniority is manager / director / executive+15
Salary visible+10
Remote or hybrid+10
3+ detected skills / tools+10
Company has 5+ open jobs in this run+10
Full-time commitment+5

¹ sales, marketing, engineering, product, data, security, finance, operations, or customer success.

Score is capped at 100.

Labels: high (70–100) · medium (40–69) · low (0–39).

reason_tags is a comma-separated list explaining the score — e.g. recent_posting, high_value_department, senior_role, salary_visible, remote_or_hybrid, skills_detected, company_hiring_multiple_roles, full_time_role.


💰 Pricing

Pay-Per-Event. One flat event per saved row (final per-event price is configured on the Apify console):

EventCharged when
job-resultOnce per unique job row that passed all filters and was successfully written to the dataset.

So your bill is simply results_saved × price_per_event. The actor honors the user-configured per-run spending cap (Apify eventChargeLimitReached): it caps how many results it collects up-front to what the limit can pay for, and stops cleanly the moment the cap is reached during charging.

Not charged:

  • Duplicates (deduplicated by job_id+company_slug+source_region, then canonical hosted_url / apply_url).
  • Rows filtered out by query / location / team / commitment / workplace / seniority / date / remote-only filters.
  • Empty boards, failed inputs, and rows missing a valid identity (job_id/hosted_url + job_title + company_slug).

🚦 Proxy policy

Use Apify Datacenter proxy or no proxy for normal runs — both work reliably for Lever's public Postings API at this actor's conservative concurrency.

Apify Residential proxy is not supported. The actor will fail at startup if proxyConfiguration.apifyProxyGroups includes RESIDENTIAL. Reason: in pay-per-event actors, residential bandwidth (~/GB) is billed to the developer, not the run user, so a single bandwidth-heavy run could exceed the per-result event revenue.

If you genuinely need residential routing, supply your own residential provider via the proxy editor's Custom proxy URLs field — that traffic goes through your provider, not Apify, and is unaffected:

http://user:pass@proxy.iproyal.com:12321
http://user:pass@proxy.brightdata.com:22225
http://user:pass@proxy.oxylabs.io:7777

📊 Run summary

After each run, a RUN_SUMMARY entry is written to the key-value store:

{
"inputs_total": 2,
"successful_inputs": 2,
"failed_inputs": 0,
"raw_results_found": 612,
"results_saved": 500,
"duplicates_removed": 14,
"filtered_out": 98,
"charged_events": 500,
"blocked_requests": 0,
"retry_count": 0,
"empty_boards": 0,
"invalid_inputs": 0,
"runtime_seconds": 9,
"scraped_at": "2026-06-03T06:00:00.000Z"
}

charged_events equals the number of successfully saved unique rows.


⚙️ Filters

FilterEffect
queryCase-insensitive substring across title, team, department, location, commitment, and description.
locationsKeep jobs whose location matches any keyword.
teamsKeep jobs whose team or department matches any keyword.
commitmentsKeep jobs whose commitment matches any keyword (e.g. Full-time, Contract, Internship).
workplaceTypesremote / hybrid / onsite / unknown (derived).
seniorityLevelsintern / junior / mid / senior / lead / manager / director / executive / unknown.
postedAfterKeep jobs created on or after an ISO date (YYYY-MM-DD).
remoteOnlyKeep only remote roles.
deduplicateDrop duplicates across overlapping inputs (recommended ON); keeps the most complete row.

All filters are applied after extraction and before any dataset push or event charge.


🚧 Limitations (V1)

  • Public Postings API only: published public jobs, no login/cookies/private Data API. No candidate, applicant, interview, or pipeline data.
  • company_name is title-cased from the site slug (the public postings API does not expose a company display name).
  • seniority_level / workplace_type are derived from visible text (and Lever's workplaceType when present); treat them as best-effort labels.
  • salary_* comes from Lever's structured salaryRange when present, otherwise a best-effort parse of salary text in the description / requirements — no currency conversion. Most Lever boards do not publish salary, so these fields are often empty.
  • updated_at is always null: Lever's public Postings API exposes only a creation timestamp (createdAtposted_at), not a last-updated timestamp. The field is kept for schema stability.
  • No recruiter/contact extraction, email enrichment, company-website crawling, or AI scoring.
  • maxResults caps saved unique rows across the whole run (not per board).

❓ FAQ

Do I need a Lever account or API key? No. The actor only uses Lever's public Postings API (?mode=json).

What is a "site slug"? The company segment of a Lever board URL — e.g. for https://jobs.lever.co/netflix the slug is netflix. You can paste full URLs in startUrls or just slugs in siteSlugs.

Global vs EU boards? Both are supported. URLs use their own host's region; for bare slugs, region: "auto" tries the global API first and falls back to EU.

How is company_jobs_in_run reflected? The hiring-signal score adds points when a company has 5+ jobs in the same run — a cheap hiring-demand signal computed across the run's saved set (no extra requests).

Can I export to CSV? Yes — every field is flat (no nested objects). Use Apify's CSV / Excel export, or call the dataset API with format=csv.


🛠️ Technical notes

  • Stack: Node.js 22 · Apify SDK 3 · Crawlee HttpCrawler · native fetch · Cheerio (HTML→text only). No browser.
  • Endpoint: Lever public Postings API — https://api.lever.co/v0/postings/{slug}?mode=json (and EU api.eu.lever.co).
  • Concurrency: min=1, max=5 (conservative; tune after real runs).
  • Memory: 1 GB min · 2 GB default · 4 GB max.
  • Proxy: Apify Proxy enabled by default; Datacenter/no-proxy/custom URLs accepted; Apify Residential rejected at startup.