# Wellfound Startup Jobs Scraper & Hiring Signals (`scrapebench/wellfound-startup-jobs-scraper`) Actor

Startup jobs from Wellfound with the pay range parsed, the full job description, and the hiring company's size, tagline and badges on every row — in one fetch.

- **URL**: https://apify.com/scrapebench/wellfound-startup-jobs-scraper.md
- **Developed by:** [ScrapeBench](https://apify.com/scrapebench) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.00175 / job listing

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 Jobs Scraper & Hiring Signals

### Pain points

- Wellfound publishes no API, so every job has to be read out of the page's embedded application cache rather than requested.
- That cache is nested one level deeper than it looks — pageProps.apolloState holds a single 'data' key, and reading the level above it returns one useless entry that looks exactly like an empty result.
- Jobs and companies are stored as separate normalised entries linked by reference, so a scraper that does not resolve those links returns jobs with no employer attached.
- Wellfound keeps three different search indexes — role, city, and role-plus-city — and they answer very different questions: 'data scientist' nationwide is 4,981 jobs where 'data scientist in San Francisco' is 396.
- Typing 'remote' as the location silently redirects to the nationwide role page, so the run answers a far broader question than the one that was asked, and nothing in the response says so.
- Pay is published as one display string ('$150k – $176k • No equity'), so it cannot be sorted or filtered on until someone parses it.
- Wellfound serves at most 15 pages of search results however many matches it reports, so a total on screen is not a total you can download.

### What we solve

- Job, employer, pay, description and hiring badges all come from one fetch per page, because they are all already in the page cache.
- The salary range is parsed into salary\_min and salary\_max, and left null rather than guessed when the string is not two dollar figures.
- 'remote' as a location is refused with an explanation pointing at the remoteOnly filter, instead of quietly widening the search.
- Every row says which index answered it in matched\_by, and echoes the role and city that were requested.
- Wellfound's own stated match count is read and logged, so a capped run can be compared against the source's figure.
- A refusal, a source change and a genuinely empty search each return a distinct free marker row — never zero rows on a successful-looking run.
- The proxy is off by default because measurement says that is the working path: Wellfound answers Apify's plain egress and serves the datacenter proxy pool a Cloudflare 403.

### Summary

Ask for a role ('software engineer'), a city ('san francisco') or both, and get one row per job: title, the pay range both as Wellfound displays it and parsed into salary\_min/salary\_max, job type, years of experience, remote flag, posting date and the complete job description — joined to the startup that posted it, with its size, one-line tagline, logo and hiring badges (actively hiring, quick responder, YC, top investors, valuation). Wellfound ships its entire page cache in the HTML, so the employer half of every row costs no extra request and no extra fee. Roles and cities combine as a product, so three roles across four cities is twelve searches in one run, each with its own result cap. Built for recruiters sourcing startup talent, job boards and aggregators, VC talent teams tracking portfolio hiring, and anyone who needs the rows rather than a dashboard.

### Who it's for

- Recruiters and sourcers hiring into startups
- Job boards and aggregators that need structured startup listings
- VC talent teams tracking which portfolio companies are hiring
- Market and compensation researchers building startup pay datasets

### How to use

Set the input, run the actor, and collect results from the run's dataset (export to JSON/CSV/Excel, or pull via the Apify API). Example input:

```json
{
  "role": "software engineer",
  "location": "san francisco",
  "maxResults": 100
}
```

See **Inputs** below for every available field.

### What you get

One row per record:

| Field | Description |
|---|---|
| `title` | The job title as posted |
| `role` | Wellfound's normalised primary role for the posting |
| `job_type` | full-time, contract, internship, and so on |
| `compensation` | Wellfound's own pay string, e.g. '$150k – $176k • No equity' |
| `salary_min` | Low end of the pay range in dollars, parsed; null when the string is not two dollar figures |
| `salary_max` | High end of the pay range in dollars, parsed |
| `has_equity` | True when equity is offered, false when the posting says none, null when unstated |
| `remote` | Wellfound's remote flag for the posting |
| `locations` | Every city the job is listed under |
| `remote_locations` | Locations the employer accepts remote candidates from |
| `posted_date` | Date the listing went live, as an ISO date |
| `description` | The complete job description as posted |
| `years_experience_min` | Minimum years of experience where the posting states one |
| `company_name` | The startup that posted the job |
| `company_size` | Wellfound's headcount bucket, e.g. SIZE\_501\_1000 |
| `company_tagline` | The company's one-line description of itself |
| `company_logo_url` | The company's logo as hosted by Wellfound |
| `company_url` | The company's Wellfound profile |
| `hiring_badges` | Signals Wellfound awards the company — ACTIVELY\_HIRING, QUICK\_RESPONDER, YC, TOP\_INVESTORS, VALUATION\_1B and others |
| `actively_hiring` | True when the company carries Wellfound's actively-hiring badge |
| `matched_by` | Which index answered — role\_and\_location, role, location or all\_jobs |
| `requested_role` | The role that was asked for, echoed back |
| `requested_location` | The city that was asked for, echoed back |
| `source_url` | The job's own page on Wellfound |

Sample:

```json
{
  "source_url": "https://wellfound.com/jobs/4639821-software-engineer",
  "title": "Software Engineer",
  "role": "Software Engineer",
  "job_type": "full-time",
  "compensation": "$150k \u2013 $176k",
  "salary_min": 150000,
  "salary_max": 176000,
  "has_equity": null,
  "remote": false,
  "locations": [
    "Denver",
    "San Francisco"
  ],
  "remote_locations": null,
  "posted_date": "2026-06-23",
  "years_experience_min": null,
  "company_name": "Checkr",
  "company_size": "SIZE_501_1000",
  "company_tagline": "The only background check company using artificial intelligence and machine learning",
  "company_url": "https://wellfound.com/company/checkr",
  "hiring_badges": [
    "ACTIVELY_HIRING",
    "B2B",
    "HIGHLY_RATED",
    "QUICK_RESPONDER",
    "TOP_INVESTORS",
    "VALUATION_1B",
    "YC"
  ],
  "actively_hiring": true,
  "matched_by": "role_and_location",
  "requested_role": "software engineer",
  "requested_location": "san francisco"
}
```

### Inputs

| Field | Required | Type | Default | Description |
|---|---|---|---|---|
| `role` | no | string | `"software engineer"` | A job role, e.g. 'software engineer', 'product designer', 'data scientist'. Type it normally — spacing and capitals do not matter. Kept forever alongside 'Roles' because saved tasks and API callers send it. |
| `roles` | no | array | `[]` | Pull several roles in ONE run, e.g. software engineer and product designer. Combined with 'Role' if you fill both. Every role is searched in every location, and 'Maximum results' applies to each role+location pair, so adding one can never truncate the others. |
| `location` | no | string | `"san francisco"` | A city, e.g. 'san francisco', 'new york', 'london'. Leave it out to search the role nationwide. Do NOT type 'remote' — Wellfound redirects that to the nationwide page and silently widens the search; use 'Remote jobs only' below instead. |
| `locations` | no | array | `[]` | Pull several cities in ONE run. Combined with 'Location' if you fill both. Roles and locations combine as a product: 3 roles across 4 cities is 12 searches in one run. |
| `remoteOnly` | no | boolean | `false` | Keep only jobs Wellfound flags as remote. This filters the search results rather than changing the search, because Wellfound has no remote-only index. |
| `maxResults` | no | integer | `100` | Cap on the number of jobs returned PER role+location pair, not per run — so adding a city cannot silently truncate the ones before it. Wellfound serves at most 15 pages of search results (roughly 500-600 jobs) per search whatever total it reports; the run says so on the row when you ask for more than it can reach. |
| `proxyConfiguration` | no | object | `{"useApifyProxy": false}` | Leave OFF. Measured 2026-09-08: Wellfound answers Apify's plain egress normally and serves the datacenter proxy pool a Cloudflare 403, so switching a proxy on is what breaks this actor. Residential also works if your own runs ever start getting refused. |

### Pricing (Pay Per Event)

You pay per result (`job`) — **no charge for empty runs**. Example: **1000 job listings** at *$0.00175/result* ≈ **$1.75**.

The default input returns up to 100 jobs for one role and city, so a default run costs about $0.18. You are charged per job returned, not per role or city submitted. Apify platform usage (compute) is billed separately per your plan.

### Use cases

- Pull every software engineering job in San Francisco with its pay range, and sort by salary\_max.
- Track which startups carry the 'actively hiring' badge across a set of roles, week over week.
- Build a compensation dataset for a role across four cities in one run.
- Feed a job board with fresh startup listings that already include the full description.
- Find companies at a given stage or size that are hiring for a role you place.

### Why this actor

- $1.75 per 1,000 jobs, against $0.99 to $5 across this category on the Store (2026-09-08).
- The full job description, job type, role title, company size and company tagline are on every row from the base fetch — no enrichment pass, no extra fee.
- Hiring badges (actively hiring, quick responder, YC, top investors, valuation, work-life balance) come through decoded.
- salary\_min and salary\_max are parsed from Wellfound's display string, so pay is sortable.
- Roles and cities combine in one run, with the result cap applied per pair so adding a city never truncates the others.
- 'remote' as a location is caught rather than silently answered with nationwide results.

### Limitations & updates

Wellfound serves at most 15 pages per search, so one search reaches roughly 500-600 jobs regardless of the total it reports. Jobs come from Wellfound's search indexes; a listing that is not surfaced by a role or city search will not appear. Company size is Wellfound's own bucket (SIZE\_501\_1000), not an exact headcount. Funding stage, total raised, founders and company social profiles are not returned — they are not in the search page's payload. salary\_min and salary\_max are left null where the pay string is not two dollar amounts, for example equity-only or hourly postings.

### FAQ

**Why does it return the full job description when other Wellfound scrapers need an extra enrichment step?**

Because of where the data is read from, not because of any trick. Wellfound is a Next.js site and every search page embeds its entire Apollo cache in the HTML — the job description, job type, normalised role, the employer's headcount bucket, tagline, logo and badges are all sitting in that blob already. This Actor parses the blob rather than the rendered page, so those fields cost no extra request. Scrapers that read the visible listing cards instead have to fetch each job's detail page to fill them in, which is why they expose it as a separate, extra-cost option. Measured 2026-09-08 against the category leader on the same query: description, job type, role title, company size and company tagline were empty on its default run and populated on all of ours.

**Can I search for remote jobs?**

Yes — with the 'Remote jobs only' switch, not by typing 'remote' as the location. Wellfound has no remote index: the URL /role/l/<role>/remote redirects to the plain nationwide role page, which is a much broader search than the one you asked for and nothing in the response tells you it happened. For 'data scientist' that is the difference between 396 jobs and 4,981. This Actor refuses 'remote' as a location and says why, then filters on Wellfound's own remote flag when you use the switch.

**How many jobs can I actually get for one search?**

Wellfound serves at most 15 pages of search results per search — roughly 500 to 600 jobs — however many matches it reports on the page. If you ask for more than a search can reach, the run returns everything it can and adds one free row saying so, with Wellfound's own stated total. To go deeper, narrow the search: a role plus a city reaches a different, smaller set than the role alone, and running several cities in one run is the intended way to cover more ground.

**Should I turn the proxy on?**

No, and switching one on is the most likely way to break a run. Measured from inside an Apify run on 2026-09-08: the container's own address answered 200 with the full page, and Apify's datacenter proxy pool was served a Cloudflare 403 on the same request in the same run. Residential also works but buys nothing today. The input is left available in case your own runs are ever refused, and it defaults to off.

**Does it return candidate or applicant data?**

No. Everything here comes from public job postings and public company profiles — the job, its pay range, its description, and the hiring company. No candidate profiles, no applicant information and no personal contact details are collected.

**What happens when a search returns nothing, or Wellfound refuses the request?**

You get a free, unbilled row that says which. A search that genuinely matched nothing returns a 'no\_results' marker; a refusal returns 'blocked'; a page whose structure no longer parses returns 'source\_changed'. That distinction matters on a jobs feed, because zero rows otherwise reads as 'nobody is hiring' when the real answer may be that the source did not answer.

### Which actor to choose

Other Actors that pair with this one:

- **Google Ads Transparency Center & Competitor Ad Scraper** — You want to see which of these startups are spending on ads, not just hiring.
- **Business Email & Phone Contact Details Scraper** — You have the hiring companies and now need contact details for outreach.

### Works with AI assistants (MCP)

Callable as an MCP tool, so Claude, Cursor, VS Code Copilot and other MCP clients can run it directly. Grab the config from the [MCP tab](https://apify.com/scrapebench/wellfound-startup-jobs-scraper/api/mcp) on this page — Apify hosts the server and keeps that snippet current, and OAuth signs you in on first connect, so no API token goes in your config file.

Then just ask:

> "Find software engineering jobs in San Francisco on Wellfound paying over $150k, and tell me which of those companies are actively hiring."

Role and location are separate inputs and combine as a product, so several roles across several cities is one run. Do not pass 'remote' as the location — use the remoteOnly flag, or Wellfound answers with nationwide results instead. Runs started this way bill exactly like any other run.

# Actor input Schema

## `role` (type: `string`):

A job role, e.g. 'software engineer', 'product designer', 'data scientist'. Type it normally — spacing and capitals do not matter. Kept forever alongside 'Roles' because saved tasks and API callers send it.

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

Pull several roles in ONE run, e.g. software engineer and product designer. Combined with 'Role' if you fill both. Every role is searched in every location, and 'Maximum results' applies to each role+location pair, so adding one can never truncate the others.

## `location` (type: `string`):

A city, e.g. 'san francisco', 'new york', 'london'. Leave it out to search the role nationwide. Do NOT type 'remote' — Wellfound redirects that to the nationwide page and silently widens the search; use 'Remote jobs only' below instead.

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

Pull several cities in ONE run. Combined with 'Location' if you fill both. Roles and locations combine as a product: 3 roles across 4 cities is 12 searches in one run.

## `remoteOnly` (type: `boolean`):

Keep only jobs Wellfound flags as remote. This filters the search results rather than changing the search, because Wellfound has no remote-only index.

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

Cap on the number of jobs returned PER role+location pair, not per run — so adding a city cannot silently truncate the ones before it. Wellfound serves at most 15 pages of search results (roughly 500-600 jobs) per search whatever total it reports; the run says so on the row when you ask for more than it can reach.

## `proxyConfiguration` (type: `object`):

Leave OFF. Measured 2026-09-08: Wellfound answers Apify's plain egress normally and serves the datacenter proxy pool a Cloudflare 403, so switching a proxy on is what breaks this actor. Residential also works if your own runs ever start getting refused.

## Actor input object example

```json
{
  "role": "software engineer",
  "roles": [],
  "location": "san francisco",
  "locations": [],
  "remoteOnly": false,
  "maxResults": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Every job matching your role and city: pay range, description, company size and hiring badges.

# 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 = {
    "role": "software engineer",
    "location": "san francisco"
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapebench/wellfound-startup-jobs-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 = {
    "role": "software engineer",
    "location": "san francisco",
}

# Run the Actor and wait for it to finish
run = client.actor("scrapebench/wellfound-startup-jobs-scraper").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 '{
  "role": "software engineer",
  "location": "san francisco"
}' |
apify call scrapebench/wellfound-startup-jobs-scraper --silent --output-dataset

```

## MCP server setup

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

```

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/DurQ5JPbQvXCwTM1A/builds/nZTGChaKXwety5n8D/openapi.json
