levels.fyi Salary Scraper — Tech Compensation & Salary Data API
Pricing
from $4.00 / 1,000 salary records
levels.fyi Salary Scraper — Tech Compensation & Salary Data API
Scrape tech compensation data from levels.fyi: base salary, stock, bonus, and total compensation by company, job family, level, and location. Per-offer records or aggregated percentile bands.
Pricing
from $4.00 / 1,000 salary records
Rating
0.0
(0)
Developer
bootforge
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
levels.fyi Salary Scraper — Tech Compensation Data
levels.fyi Salary Scraper is an Apify actor that extracts tech compensation data from levels.fyi — per-offer salary records and per-level aggregate/percentile bands — by company, job family, and location.
Use it to benchmark comp bands before a negotiation, build a compensation-intelligence dashboard, track how a company's pay moves over time, or feed a recruiting/market-research pipeline — exported to JSON, CSV, or Excel.
Table of contents
- What the levels.fyi Salary Scraper does
- How to scrape levels.fyi salary data
- levels.fyi scraper input
- What data you get
- Pricing
- Recommended proxies for levels.fyi
- Why this levels.fyi scraper
- FAQ
- Rate this actor
- Related actors
What the levels.fyi Salary Scraper does
- 💰 Per-offer records — individual self-reported comp entries: base, stock, bonus, total compensation, title, years of experience, and location.
- 📊 Per-level aggregates — company/level rollups with percentile bands (p10–p90) for total compensation and base salary, plus sample count.
- 🏢 Company + job family targeting — pass explicit company slugs (
google,meta) and a job family (software-engineer,product-manager,data-scientist), or enable Discover all companies to enumerate the whole levels.fyi company index. - 🌍 Location filters — narrow to specific levels.fyi location slugs (
united-states,india), or leave empty for the default all-location view. - ⚡ HTTP-only, no anti-bot — no login, no CAPTCHA, no browser tier; runs are fast and proxy is optional.
How to scrape levels.fyi salary data
- Click Try for free and open the actor.
- Enter one or more
companies(slugs likegoogle,meta) or turn ondiscover_allto enumerate every company on levels.fyi. - Set
job_family(defaults tosoftware-engineer) and, optionally,locations. - Choose
mode— one per run:records(one row per individual offer, the default) oraggregates(one summary row per level: averages + percentile bands). Each mode yields a clean single-schema dataset; run twice if you want both. - Click Start and watch results stream into the dataset.
- Export as JSON, CSV, or Excel, or pull from the Apify API.
Individual salary records for two companies (the default):
{"companies": ["google", "meta"],"job_family": "software-engineer","mode": "records"}
Aggregated salary bands only, capped discovery run across the whole company index:
{"discover_all": true,"max_companies": 50,"mode": "aggregates"}
levels.fyi scraper input
| Field | Type | Default | Description |
|---|---|---|---|
companies | string[] | — | Company names or levels.fyi slugs (e.g. google, Meta — auto-slugified). Provide this or enable discover_all. |
job_family | string | software-engineer | levels.fyi job-family slug, e.g. software-engineer, product-manager, data-scientist. |
locations | string[] | — | Optional levels.fyi location slugs for metro-specific pay. Empty = nationwide. See Locations for common slugs. |
mode | enum | records | One per run. records = one row per individual offer; aggregates = one summary row per level (averages + percentile bands). Never mixed, so each run's dataset has a single clean schema. |
discover_all | boolean | false | Enumerate every company on levels.fyi (ignores companies). Use max_companies to cap. |
max_companies | int | — | Cap on how many companies to enumerate when discover_all is on. |
max_records | int | — | Cap on per-offer salary records per company/location. |
transport | enum | auto | HTTP engine: auto (curl_cffi), curl_cffi, httpx, or primp. |
proxy | object | — | Optional Apify Proxy configuration. Not required for correctness — see Recommended proxies. |
Locations
Compensation varies widely by metro (SF Bay Area vs. the rest of the US can differ by tens of thousands). Pass one or more locations slugs to scrape metro- or country-specific pay; each is scraped separately and the location_name output field tells you which one a row belongs to. Leave locations empty for nationwide numbers.
Common US metros: san-francisco-bay-area, greater-seattle-area, new-york-city-area, greater-los-angeles-area, greater-boston-area, greater-chicago-area, greater-austin-area, greater-dallas-area, greater-houston-area, atlanta-area, greater-san-diego-area, raleigh-durham-area, greater-detroit-area, philadelphia-area, phoenix-area
Countries: united-states, india, united-kingdom, canada, germany, netherlands, ireland, australia, singapore, israel, france, switzerland, poland, japan, brazil, mexico, spain, sweden
Any other location: open it on levels.fyi and copy the last path segment of the URL — …/salaries/software-engineer/locations/<slug>.
What data you get
Aggregated salary bands (mode: aggregates)
One summary row per company/level. Sample from a live run (Google, L3, software-engineer, United States):
{"company": "Google","level": "l3","job_family": "software-engineer","level_name": "L3","scraped_at": "2026-07-17T07:09:42.077676+00:00","count": 33,"base": 161788,"stock": 34280,"bonus": 8702,"total": 204770,"tc_p10": 176000,"tc_p25": 208000,"tc_p50": 293000,"tc_p75": 403000,"tc_p90": 486500,"base_p10": 151000,"base_p25": 168000,"base_p50": 200000,"base_p75": 218000,"base_p90": 242000,"location_name": "United States"}
| Field | Description |
|---|---|
company, level, job_family | Company name, level identifier, and job family the aggregate covers. |
count | Number of self-reported data points behind this rollup. |
base, stock, bonus, total | Average annual base salary, stock grant value, bonus, and total compensation (USD). |
tc_p10…tc_p90 | Total-compensation percentile bands where levels.fyi exposes them; unpublished percentiles are null. |
base_p10…base_p90 | Base-salary percentile bands, same null-if-unpublished rule. |
location_name, scraped_at | Location the aggregate covers and capture timestamp. |
Individual salary records (mode: records, default)
One row per self-reported offer. Sample from a live run (Google, L3):
{"company": "Google","level": "L3","uuid": "b6e2f5b0-7c9a-4b8e-9d1a-2f6a8c3d5e9f","scraped_at": "2026-07-17T09:12:44.118203+00:00","title": "Software Engineer","job_family": "software-engineer","focus_tag": "DevOps","years_of_experience": 1,"years_at_company": null,"offer_date": null,"location": "Los Angeles, CA","country_id": null,"dma_id": null,"base_salary": 140000,"avg_annual_stock_grant_value": 20000,"avg_annual_bonus_value": null,"total_compensation": 160000,"gender": null}
| Field | Description |
|---|---|
company, level, title, focus_tag | Company, level, job title, and specialization tag (e.g. DevOps) as self-reported. |
years_of_experience, years_at_company | Reporter's tenure, when disclosed. |
location | Free-text city/region as reported. |
base_salary, avg_annual_stock_grant_value, avg_annual_bonus_value, total_compensation | Annualized compensation components (USD). |
uuid, scraped_at | levels.fyi's own record identifier and capture timestamp. |
Pricing
This actor uses pay-per-event pricing — you pay for what you scrape, not for time. Pricing below is provisional until Console monetization is finalized (see the Monetization tab for current live pricing).
| Event | USD | Per 1,000 |
|---|---|---|
| Actor start (per run) | $0.001 | — |
Salary record scraped (salary-record) | $0.002 | $2 |
Salary aggregate scraped (salary-aggregate) | $0.001 | $1 |
| Typical run | Cost |
|---|---|
| 1 company, aggregates (~7 levels) | ~$0.008 |
| 1 company, records (~50 offers) | ~$0.101 |
| 10 companies, records (~500 offers) | ~$1.001 |
Recommended proxies for levels.fyi
Proxy is optional. levels.fyi's public salary pages are server-rendered and require no login or CAPTCHA, so a proxy is not required for correctness — only useful for scale (avoiding shared-IP rate limits on large discover_all runs).
If you run your own scrapers (inside or outside Apify) and need reliable proxies for scale, we use DataImpulse — pay-as-you-go IPs with per-country targeting and no monthly minimum:
👉 Get DataImpulse proxies (referral link)
Why this levels.fyi scraper
- No anti-bot tax — HTTP-only, no browser, no CAPTCHA solving; runs are fast and cheap because levels.fyi's public salary pages need none of that.
- Two granularities, one actor — per-offer records for the raw distribution, or per-level aggregates with percentile bands; pick one per run for a clean single-schema dataset.
- Company discovery built in —
discover_allenumerates the full levels.fyi company index instead of requiring you to hand-curate slugs. - Validated output — every row is Pydantic-validated before it's pushed; malformed entries are dropped, not shipped with garbage fields.
- Open source — the underlying
levels-fyi-scraperPython package ships a Typer CLI and a FastAPI server; the Apify wrapper is a thin layer.
FAQ
What's the difference between records and aggregates? Records are individual self-reported offers (one row per person) — pick this (the default) for the raw, granular data. Aggregates are per-level rollups levels.fyi computes from those same reports — one row per level with averages plus percentile bands — pick this for quick benchmarking. You choose one mode per run so each dataset stays a single clean schema; run the actor twice if you want both.
Do I need a proxy? No. levels.fyi's public salary pages have no known anti-bot layer, so a proxy is optional. It only helps at scale on large discover_all runs. For your own scrapers, we recommend DataImpulse.
Why are some percentile fields null? levels.fyi doesn't publish every percentile band (p10/p25/p75, etc.) for every company/level/location combination — only the bands it actually surfaces are populated; the rest are null rather than guessed.
What does discover_all do, and how do I limit it? It ignores companies and enumerates every company slug on levels.fyi's public index instead. Set max_companies to cap how many it processes — useful to control run cost and duration.
Can I scrape multiple job families or locations in one run? One job_family per run by design (it's part of the URL levels.fyi serves). locations accepts multiple slugs, and each is fetched per company.
Is scraping levels.fyi legal? This actor collects only publicly available, aggregated and self-reported compensation data. You are responsible for complying with levels.fyi's terms and applicable laws. Do not use this data to identify or target individual reporters.
Rate this actor ⭐
If the levels.fyi Salary Scraper saved you time, please leave a review on its Apify Store page — ratings help other people find it and tell us what to build next. Hit a bug or missing field? Open an issue or contact us through the actor's Issues tab and we'll fix it fast — recency and reliability are what keep this actor ranking.
Related actors
Building a compensation or hiring-intelligence pipeline? Pair this actor with our other scrapers — same proxy config format, same Pydantic-validated output, all open source.
- Indeed Job Scraper — cross-reference open roles at the same companies you're benchmarking here.
- LinkedIn Jobs Scraper — pull live job postings to pair against comp bands.
- Google Play App Search & Reviews Scraper — another HTTP-only, no-anti-bot actor if you're assembling a lightweight-scrape toolkit.