# Levels.fyi Salary Scraper (`ninja.dev/levels-fyi-salary-scraper`) Actor

Get tech salary and total compensation data from Levels.fyi for a company and role. Returns pay by career level (base, stock, bonus, total) plus individual offers with title, level, years of experience, location and date. Flags offers new since your last run. Company and role are URL slugs.

- **URL**: https://apify.com/ninja.dev/levels-fyi-salary-scraper.md
- **Developed by:** [Matheus Coelho](https://apify.com/ninja.dev) (community)
- **Categories:** Developer tools, Lead generation, Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.28 / 1,000 salary sample scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Levels.fyi Salary Scraper — Tech Compensation Data by Company & Role

Need to know **what a company actually pays**? This actor pulls tech
**salary and total-compensation data from Levels.fyi** for any company and
role — the base, stock, bonus, and total comp **broken down by level**, plus
individual offer samples with years of experience, location, and offer date.

Give it a list of companies (`google`, `amazon`, `meta`, ...) and a role
(`software-engineer`, `product-manager`, ...) and get back clean, structured,
exportable compensation data — ready for benchmarking, recruiting, or
negotiation research.

### Why this scraper

- **Per-level pay breakdown, ready-made** — every run returns a compensation
  summary for each level (base, stock, bonus, total comp, sample count, and a
  link to the level page). Most scrapers just dump raw rows; this one hands you
  the intelligence layer buyers actually want.
- **Compensation monitoring built in** — with **Detect new offers** on (it is
  by default), every run remembers the offers it has already seen per
  company/role and flags brand-new ones with `isNew: true`, plus a count of new
  offers. Run it on a schedule and you'll see the day pay shifts at a target
  company. No other Levels.fyi scraper tracks this across runs.
- **Fast & cheap** — reads the data straight from the page instead of driving a
  browser, so runs finish in seconds.
- **Rich, granular data** — title, level, focus area, years of experience,
  years at company, location, base / stock / bonus / total comp, and offer date
  for every sample.
- **Country filter** — restrict results to a single country when you need
  local benchmarks.

### How to use it (30 seconds)

1. Enter one or more **companies** (Levels.fyi URL slugs, e.g. `google`).
2. Set the **role** (default `software-engineer`) and press **Start**.
3. Download the results as JSON, CSV, or Excel — or pipe them into Make,
   Zapier, n8n, Google Sheets, or your own webhook via Apify integrations.

To track pay over time, save your input as a task and add a **schedule** (e.g.
weekly). Each run reports how many offers are new since the last one.

### Input

| Field | Type | Description |
|---|---|---|
| `companies` | array | Company slugs from the Levels.fyi URL (e.g. `google`, `amazon`). |
| `jobFamily` | string | Role slug (default `software-engineer`). |
| `country` | string | Optional Levels.fyi numeric country id (e.g. `254` = US, `43` = Canada). |
| `maxSamplesPerCompany` | integer | Max individual samples per company (default 200). |
| `includeSamples` | boolean | Return individual offers, not just aggregates (default true). |
| `detectNewOffers` | boolean | Flag new offers vs. last run (default true). |

### Output

Two record types. A **per-level summary** (returned in full regardless of the
sample cap):

```json
{
  "recordType": "levelSummary",
  "company": "google",
  "role": "software-engineer",
  "level": "l3",
  "levelName": "SWE II",
  "sampleCount": 33,
  "base": 161788,
  "stock": 34280,
  "bonus": 8702,
  "totalCompensation": 204770,
  "levelPageUrl": "https://www.levels.fyi/companies/google/salaries/software-engineer/levels/l3"
}
```

And individual **offer samples**:

```json
{
  "recordType": "sample",
  "company": "google",
  "role": "software-engineer",
  "title": "Software Engineer",
  "level": "L3",
  "yearsOfExperience": 1,
  "location": "Los Angeles, CA",
  "offerDate": "2026-07-06T16:12:08.865+00:00",
  "baseSalary": 140000,
  "stock": 20000,
  "bonus": 0,
  "totalCompensation": 160000,
  "isNew": true
}
```

Each run also saves a compact summary (levels, samples, and new offers per
company) as the run's `OUTPUT` — handy when an integration only needs to know
*"did pay change?"* without reading the whole dataset.

### What people use it for

#### Benchmark compensation across companies

Feed in a list of competitors and one role to compare total comp level-by-level
— exactly what you need to set or defend a pay band.

#### Get alerted when pay shifts at a target company

Schedule a run with **Detect new offers** on. When `totalNewOffers > 0`,
trigger a Slack/email alert through an Apify integration and see fresh offers
as they land.

#### Recruiting & talent-market intelligence

Recruiters and staffing teams: know what candidates are really being offered at
each level before making an offer, and spot where the market is moving.

#### Negotiation research

Going into an offer conversation? Pull the level breakdown and recent samples
for the company and role so you walk in with real numbers.

#### Comp & HR analytics at scale

Build your own compensation dataset across dozens of companies and roles for
dashboards, reports, or models — exported straight to CSV or your warehouse.

### FAQ

#### Which companies and roles can I scrape?

Any company and role that exists on Levels.fyi. Use the exact slugs from the
URL: `levels.fyi/companies/<company>/salaries/<role>` — e.g. company `amazon`,
role `product-manager`.

#### What's the difference between the level summary and the samples?

The **level summary** is the aggregate pay for each level (average base, stock,
bonus, total, and how many data points it's based on). The **samples** are the
individual anonymized offers that make up those levels, with per-offer detail.

#### How is this better than browsing Levels.fyi myself?

Manually you look at one company at a time. The actor pulls dozens of companies
in one run, exports everything to JSON/CSV, runs on a schedule, and — the part
the website can't do — remembers previous runs so it can tell you **which
offers are new**.

#### Do I need a Levels.fyi account, API key, or proxies?

No. Everything runs inside the actor — no login, no API key, no proxy setup.

#### Can I filter by country?

Yes. Set the `country` input to a Levels.fyi numeric country id to restrict
results to that country (leave it empty for worldwide).

#### Can it send alerts automatically?

Yes. Combine an Apify **schedule** with an **integration** (Slack, email, Make,
Zapier, n8n, or webhook) that fires when the run summary shows new offers.

### Support & feedback

Found a bug or want another role/field? Open a ticket in the **Issues** tab — I
usually respond within a few hours and actor updates ship fast.

If this actor saves you time, please leave a ⭐ **review** on the Store page.
It takes 10 seconds, genuinely helps others find it, and tells me what to build
next.

### Legal & ethical use

This actor extracts only publicly available, anonymized compensation data that
Levels.fyi already publishes — no logins, no private data, no personal
identities. You are responsible for using the data in compliance with
applicable laws and the terms of service that apply to you.

# Actor input Schema

## `companies` (type: `array`):

Company slugs as they appear in a Levels.fyi URL (levels.fyi/companies/<slug>). E.g. "google", "amazon", "meta", "microsoft".

## `jobFamily` (type: `string`):

Role slug as it appears in a Levels.fyi URL (levels.fyi/companies/<company>/salaries/<role>). E.g. "software-engineer", "product-manager", "data-scientist", "engineering-manager".

## `country` (type: `string`):

Optional Levels.fyi numeric country id to restrict results to one country (e.g. "254" = United States, "43" = Canada). Leave empty for worldwide (default).

## `maxSamplesPerCompany` (type: `integer`):

Maximum individual salary samples to scrape per company/role. Per-level aggregates are always returned in full regardless of this cap.

## `includeSamples` (type: `boolean`):

Return individual offer records (title, level, years of experience, location, base/stock/bonus/total, offer date). Turn off to return only the per-level aggregate breakdown.

## `detectNewOffers` (type: `boolean`):

Remember offers seen in previous runs and flag brand-new ones with isNew=true, plus a summary of how many are new since last run. Ideal for tracking when pay shifts at a target company. Uses a persistent named store.

## Actor input object example

```json
{
  "companies": [
    "google",
    "amazon"
  ],
  "jobFamily": "software-engineer",
  "maxSamplesPerCompany": 200,
  "includeSamples": true,
  "detectNewOffers": true
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "companies": [
        "google",
        "amazon"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ninja.dev/levels-fyi-salary-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "companies": [
        "google",
        "amazon",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("ninja.dev/levels-fyi-salary-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "companies": [
    "google",
    "amazon"
  ]
}' |
apify call ninja.dev/levels-fyi-salary-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=ninja.dev/levels-fyi-salary-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/eqwew6hAFg3VF7Nfq/builds/5niOvRHKUrTqYiTTP/openapi.json
