# Wellfound Startup Salary Benchmarks by Role and City (`gubidonius/wellfound-salaries`) Actor

Startup salary percentiles from Wellfound's hiring data, by role, city, industry, skill and seniority, plus the quarterly series. Figures come out in full dollars, not the thousands Wellfound stores. A role slug it does not know returns the overall market figures under that role's name.

- **URL**: https://apify.com/gubidonius/wellfound-salaries.md
- **Developed by:** [Gregory Bolshakov](https://apify.com/gubidonius) (community)
- **Categories:** Business, Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

## Wellfound Startup Salary Benchmarks by Role and City

Reads Wellfound's own startup hiring data. Salary percentiles by role, by city, by industry,
by skill and by seniority, plus the quarterly series behind them. No key and no login.

### The numbers are thousands and this Actor expands them

Wellfound stores a median of 125 and prints it as "$125k". Read the stored value and you get
125, which looks like a salary of a hundred and twenty-five dollars and sorts like one.

Every figure here comes out in full dollars. The columns are `salaryP25Usd`, `salaryP50Usd`
and `salaryP90Usd`. Industry percentiles have halves in them, so 287.5 becomes 287500 and is
not rounded to the nearest thousand.

Wellfound quotes every location in US dollars, London included.

### The second line on the chart is not your role

Every role page carries two quarterly series. One is the role you asked for. The other is
Wellfound's market-wide line, and its query carries your role while its numbers ignore it. The
same figures come back on the overall page, on a role page and on a city page.

Those rows are marked `isBaseline` true and their `scopeKind` is `all`. Drop them unless you
want the comparison line.

The same applies to the tables. On a city page the by-location table is the global one, not a
breakdown of that city. Every row carries the scope its own table was computed for, read from
the query rather than from the page it sat on, so `scopeSlug` and `requestedScopeSlug` can
differ and both are on the row.

### A role slug it does not know

Ask for `/hiring-data/r/not-a-role` and Wellfound answers with HTTP 200 and its overall
figures, with no roleId anywhere in the query. Nothing looks wrong. You would be reading the
whole market's pay as one role's pay.

This Actor checks the query for the role or city id, drops the page when it is missing, says
so in the run summary, and charges you nothing for it.

### How old the data is

Wellfound titles these pages with the current year. The quarterly series does not reach it.
Read the run summary for `earliestQuarter` and `latestQuarter`, and every row carries
`periodStart` and `observedAt` so you can see the gap yourself.

Wellfound publishes no sample size, so a thin market can produce a strange figure. A data
scientist median of 205,000 in New York sits in the same table as 10,000 in Vancouver. Both
are what the source says.

### Equity

There is none here. The page title says salary and equity. The data behind it carries salary
percentiles only, so this Actor returns salary.

### Input

| Field | What it does |
|---|---|
| `roles` | Role slugs from the Select role dropdown on wellfound.com/hiring-data |
| `locations` | City slugs, for example new-york, london, remote-friendly |
| `includeOverall` | Also read the overall page, every role and every city together |
| `breakdowns` | Keep only some tables. Empty means all of them |
| `maxResults` | Upper bound for the whole run |

### Output

One row per figure. A role page gives about 62 rows: 12 quarters for the role, 12 for the
baseline, and the city, industry, skill and seniority tables.

`RUN_SUMMARY` in the key value store holds the pages read, how many figures each gave, the
earliest and latest quarter, and whether any role or city was not recognised.

### Price

0.002 dollars per run and 0.002 dollars per figure. Both are charged after the rows exist, so
a run that finds nothing costs nothing.

# Actor input Schema

## `roles` (type: `array`):

Wellfound role slugs from the Select role dropdown on wellfound.com/hiring-data, for example data-scientist-1, backend-developer, product\_manager. A slug Wellfound does not know is skipped and reported, never returned as the overall figures under that role's name.

## `locations` (type: `array`):

Wellfound location slugs, for example new-york, london, remote-friendly. Each one is a separate page. Wellfound has no page combining a role with a location.

## `includeOverall` (type: `boolean`):

Also read wellfound.com/hiring-data, which is every role and every location together.

## `breakdowns` (type: `array`):

Leave empty for all of them. Otherwise any of over-time, by-location, by-industry, by-skill, by-seniority.

## `maxResults` (type: `integer`):

Upper bound on figures for the WHOLE run, across every page. You are never charged for more than this.

## Actor input object example

```json
{
  "roles": [
    "data-scientist-1"
  ],
  "locations": [],
  "includeOverall": false,
  "breakdowns": [],
  "maxResults": 200
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {
    "roles": [
        "data-scientist-1"
    ],
    "locations": [],
    "breakdowns": [],
    "maxResults": 200
};

// Run the Actor and wait for it to finish
const run = await client.actor("gubidonius/wellfound-salaries").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 = {
    "roles": ["data-scientist-1"],
    "locations": [],
    "breakdowns": [],
    "maxResults": 200,
}

# Run the Actor and wait for it to finish
run = client.actor("gubidonius/wellfound-salaries").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "roles": [
    "data-scientist-1"
  ],
  "locations": [],
  "breakdowns": [],
  "maxResults": 200
}' |
apify call gubidonius/wellfound-salaries --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,gubidonius/wellfound-salaries"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/kqc3Xv7y4KdxxX1h0/builds/jBGz3B3WUmRPX4afk/openapi.json
