Levels.fyi Compensation Scraper avatar

Levels.fyi Compensation Scraper

Pricing

Pay per event

Go to Apify Store
Levels.fyi Compensation Scraper

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

Pay per event

Rating

0.0

(0)

Developer

DevilScrapes

DevilScrapes

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 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 / 503 and honour Retry-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

  1. Click Try for free at the top of the page.
  2. Fill in the input form — most fields have sensible defaults.
  3. Click Start. Output streams into the run's dataset.
  4. Export from Storage → Dataset as JSON, CSV, or Excel — or fetch via the API.

📥 Input

FieldTypeRequiredDefaultNotes
modestringno'company_job_family''Company + job family' pulls per-submission compensation rows (base/stock/bonus split) for one or more job families at…
companiesarrayyes['google']Levels.fyi company URL slugs, e.g. 'google', 'meta', 'apple' — not arbitrary display names.
jobFamiliesarraynoNoneLevels.fyi job-family URL slugs, e.g. 'software-engineer', 'product-manager'. Required (non-empty) when Mode is…
maxResultsintegerno200Hard cap on dataset rows for this run.
proxyConfigurationobjectno{'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.

FieldTypeNotes
granularitystringWhich mode produced this row — 'individual_submission' or 'aggregate_title'.
companystringCompany display name.
company_slugstringInput companies entry (levels.fyi URL slug).
job_familystringJob family display name.
job_family_slugstringJob family URL slug.
titlestringJob title.
levelstringLevel code, e.g. 'L3'. Null in overview mode.
trackstringFocus tag / track, e.g. 'ML / AI'.
locationstringLocation string. Null in overview mode.
years_of_experiencenumberYears of experience.
years_at_companynumberYears at the company.
base_salarynumberBase salary. Null in overview mode — no base/stock/bonus split available at that granularity.
stock_annual_valuenumberAverage annual stock grant value.
bonus_annual_valuenumberAverage annual bonus value.
total_compensationnumberTotal compensation — per-submission in company_job_family mode, median in company_overview mode.
currency_codestringISO currency code.
offer_datestringISO 8601 offer date. Null in overview mode.
level_submission_countintegerThe level/title bucket's total submission count.
level_submission_count_last_12_monthsintegerThe level bucket's trailing-12-month submission count (company_job_family mode only) — compare against the rows you…
source_urlstringThe fetched page URL this row was parsed from.
scraped_atstringISO-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:

EventUSDWhat it is
actor-start$0.02One-off warm-up charge per run
result-row$0.0018Per 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.