Levels.fyi Compensation Scraper avatar

Levels.fyi Compensation Scraper

Pricing

from $1.80 / 1,000 results

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

from $1.80 / 1,000 results

Rating

0.0

(0)

Developer

DevilScrapes

DevilScrapes

Maintained by Community

Actor 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 / 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.