Levels.fyi Compensation Scraper
Pricing
from $1.80 / 1,000 results
Levels.fyi Compensation Scraper
Scrape verified tech compensation data from Levels.fyi by company — total comp, base salary, stock, bonus, and level breakdowns by job family, normalized into one row per data point for CSV, JSON, or API export.
Pricing
from $1.80 / 1,000 results
Rating
0.0
(0)
Developer
DevilScrapes
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
🎯 What this scrapes
Levels.fyi crowdsources tech-industry compensation reports and normalizes them into levels, total comp, base, stock, and bonus per company and job family — the closest thing to a public pay ladder for tech roles. This Actor parses that data straight out of the page's own embedded JSON: point it at one or more companies and it writes one structured row per individual submission (base, stock, and bonus kept separate — the differentiator most compensation scrapers flatten away) or one row per title in a lightweight company-wide overview, ready for comp-benchmarking spreadsheets, recruiting tools, or internal pay-band research.
🔥 What we handle for you
- 🎯 Two granularities, your call — component-separated individual submissions (base/stock/bonus kept apart) or lightweight company-wide aggregates.
- 🔁 We retry with exponential backoff on
408 / 429 / 503and honourRetry-After— up to 5 attempts per page. - 🌐 We route every request through Apify Proxy, residential preferred and pinned to the US, so your dataset isn't tied to one exit IP.
- 🧊 Clean, typed dataset rows — Pydantic-validated, ISO-8601 timestamps, deduped by submission ID, JSON / CSV / Excel export straight from the Apify Console.
- 🔍 Every row carries its submission-count context — so you always know how much of the underlying sample you're looking at, never presented as more complete than it is.
- 💰 Pay-Per-Event pricing — you only pay for rows that hit your dataset. No data, no charge.
💡 Use cases
- Comp benchmarking — pull Levels.fyi's per-level total comp, base, stock, and bonus for target companies into a spreadsheet or BI tool.
- Offer negotiation research — compare a candidate's offer against Levels.fyi's published bands for the same company and job family.
- Recruiting + TA analytics — feed normalized, component-separated compensation rows into a sourcing or comp-modeling pipeline.
- Internal pay-band research — track how a peer company's published levels and comp move over time.
⚙️ How to use it
- Click Try for free at the top of the page.
- Fill in the input form — most fields have sensible defaults.
- Click Start. Output streams into the run's dataset.
- Export from Storage → Dataset as JSON, CSV, or Excel — or fetch via the API.
📥 Input
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
mode | string | no | 'company_job_family' | 'Company + job family' pulls per-submission compensation rows (base/stock/bonus split) for one or more job families at… |
companies | array | yes | ['google'] | Levels.fyi company URL slugs, e.g. 'google', 'meta', 'apple' — not arbitrary display names. |
jobFamilies | array | no | None | Levels.fyi job-family URL slugs, e.g. 'software-engineer', 'product-manager'. Required (non-empty) when Mode is… |
maxResults | integer | no | 200 | Hard cap on dataset rows for this run. |
proxyConfiguration | object | no | {'useApifyProxy': True} | Apify Proxy configuration. We resolve RESIDENTIAL pinned to the US automatically at runtime, falling back to our… |
Example input
{"mode": "company_job_family","companies": ["google"],"jobFamilies": ["software-engineer"],"maxResults": 5,"proxyConfiguration": {"useApifyProxy": true}}
📤 Output
Every row is one dataset item.
| Field | Type | Notes |
|---|---|---|
granularity | string | Which mode produced this row — 'individual_submission' or 'aggregate_title'. |
company | string | Company display name. |
company_slug | string | Input companies entry (levels.fyi URL slug). |
job_family | string | Job family display name. |
job_family_slug | string | Job family URL slug. |
title | string | Job title. |
level | string | Level code, e.g. 'L3'. Null in overview mode. |
track | string | Focus tag / track, e.g. 'ML / AI'. |
location | string | Location string. Null in overview mode. |
years_of_experience | number | Years of experience. |
years_at_company | number | Years at the company. |
base_salary | number | Base salary. Null in overview mode — no base/stock/bonus split available at that granularity. |
stock_annual_value | number | Average annual stock grant value. |
bonus_annual_value | number | Average annual bonus value. |
total_compensation | number | Total compensation — per-submission in company_job_family mode, median in company_overview mode. |
currency_code | string | ISO currency code. |
offer_date | string | ISO 8601 offer date. Null in overview mode. |
level_submission_count | integer | The level/title bucket's total submission count. |
level_submission_count_last_12_months | integer | The level bucket's trailing-12-month submission count (company_job_family mode only) — compare against the rows you… |
source_url | string | The fetched page URL this row was parsed from. |
scraped_at | string | ISO-8601 UTC row creation timestamp. |
Example output
{"granularity": "individual_submission","company": "Google","company_slug": "google","job_family": "Software Engineer","job_family_slug": "software-engineer","title": "Software Engineer","level": "L3","track": "ML / AI","location": "New York, NY","years_of_experience": 0.0,"years_at_company": 0.0,"base_salary": 140000.0,"stock_annual_value": 2500.0,"bonus_annual_value": 0.0,"total_compensation": 142500.0,"currency_code": "USD","offer_date": "2026-07-09T17:59:59.627+00:00","level_submission_count": 46,"level_submission_count_last_12_months": 1134,"source_url": "https://www.levels.fyi/companies/google/salaries/software-engineer","scraped_at": "2026-08-06T09:00:00+00:00"}
💰 Pricing
Pay-Per-Event — you pay only when these events fire:
| Event | USD | What it is |
|---|---|---|
actor-start | $0.02 | One-off warm-up charge per run |
result-row | $0.0018 | Per unique dataset item |
Example: 1 000 results at the rates above ≈ $1.82. No subscription, no minimum, no card to start — Apify gives every new account $5 of free credit.
🚧 Limitations
Individual-submission rows (company_job_family mode) reflect the bounded preview of samples Levels.fyi embeds per level bucket, not its full submission dataset — a bucket with a trailing-12-month count in the thousands might only surface a few dozen sample rows on the page. Every row carries level_submission_count and level_submission_count_last_12_months so you always know how much of the underlying population a given row-set represents. company_overview mode covers only companies and job families Levels.fyi has published; small or under-reported companies may return nothing. This version confirms the default US-locale route only — non-US Levels.fyi pages and non-USD currencies aren't covered yet.
❓ FAQ
Do I need a Levels.fyi account or API key?
No. This Actor scrapes Levels.fyi's own publicly published compensation pages — no login, no API key.
What's the difference between the two modes?
'Company + job family' returns individual-submission rows with base salary, stock, and bonus broken out separately — one row per sample in each level bucket. 'Company overview' returns one aggregate row per title (median total comp + submission count), with no base/stock/bonus split.
Are the individual-submission rows the complete Levels.fyi dataset?
No — each level bucket embeds a bounded preview of its submissions, not every one on file. Every row carries level_submission_count and level_submission_count_last_12_months so you can see exactly how much of the underlying sample you're getting, instead of mistaking a preview for the full population.
What format do company and job-family slugs need to be in?
Use Levels.fyi's own URL slugs — e.g. 'google', not 'Google Inc'; 'software-engineer', not 'Software Engineer'. We lowercase and hyphenate spaces as a convenience, but you're responsible for supplying a slug that matches a real Levels.fyi URL.
What happens if I request a company or job family that doesn't exist?
That pair returns zero rows and is logged as a failed pair — it never crashes the run. Only if every requested pair comes back empty does the run fail loudly, so you know to double-check your slugs.
💬 Your feedback
Spotted a bug, hit a weird edge case, or need a new field? Open an issue on the Actor's Issues tab on Apify Console — we ship fixes weekly and we read every report.