# Wellfound Startup Jobs Scraper - Salary & Equity (`usestring/wellfound-jobs`) Actor

Collects startup jobs from Wellfound (formerly AngelList Talent) by role and location, with the salary range and the equity range as numbers rather than strings. Each row carries the company, its headcount bucket, the Wellfound handle, the location, a remote flag and a link to the posting.

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

## Pricing

from $3.25 / 1,000 results

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

### What does Wellfound Startup Jobs Scraper do?

It searches Wellfound (formerly AngelList Talent) by role and location and returns startup job
listings with the salary range **and the equity range** as numbers. Equity is the reason this Actor
exists. Almost no other job board publishes an equity grant at all, and on Wellfound it sits in the
same display string as the pay, which means it has to be parsed out rather than read from a field.

Give it one or more role keywords in `queries` and a `location` that is either a city or `Remote`.
Each pair addresses one Wellfound role landing page, and every startup listed there is written out
with its compensation, headcount bucket, location, remote flag and a link to the posting.

- `salaryMin`, `salaryMax`, `equityMin` and `equityMax` come back as numbers, not as
  `"$135k – $175k • 0.05% – 0.25%"`.
- `No equity` is recorded as a `0`–`0` range, which is a different fact from a listing that never
  mentions equity and comes back `null`.
- The run verifies that Wellfound actually served the role you asked for. It quietly substitutes its
  generic board for an unknown role rather than returning a 404, and that would otherwise look like a
  successful run full of off-topic jobs.
- No Wellfound or AngelList account, cookie or API key. Only public role landing pages are read.

A measured run averaged around 37 listings per role, at a median of 0.7 seconds per request.

### What data does it extract?

| Field | Type | Description |
| --- | --- | --- |
| `jobId` | string | Wellfound's listing id. Stable, so use it to de-duplicate and to diff between runs |
| `title` | string | The role title as the startup wrote it |
| `company` | string | The startup's name |
| `companySlug` | string | Its Wellfound handle, for example `stepsecurity`. The key to join listings from the same company |
| `salaryMin` | number | Lower bound of the advertised pay, for example `135000` |
| `salaryMax` | number | Upper bound. `null` when the listing quotes a single figure or says `Up to $215k` |
| `currency` | string | ISO code read from the listing's own figure: `USD`, `GBP`, `EUR`, `INR`, `JPY` |
| `equityMin` | number | Lower bound of the equity percentage, for example `0.05` |
| `equityMax` | number | Upper bound, for example `0.25`. Both are `0` when the listing says `No equity` |
| `location` | string | The listing's stated locations, or its accepted remote locations when it names no office |
| `isRemote` | boolean | Wellfound's own remote flag on the listing |
| `companySize` | string | Headcount bucket, for example `11-50`, `1001-5000` |
| `jobUrl` | string | Direct link to the Wellfound posting |
| `query` | string | The role keyword this row came from, so a multi-role run stays attributable |
| `sourceUrl` | string | The role landing page the row was read from |
| `collectedAt` | string | ISO 8601 timestamp of the run |

#### How compensation is parsed

Wellfound publishes pay as one display string with the two halves separated by a bullet. Both halves
are read, and the awkward cases are handled explicitly rather than flattened:

`Up to $215k` sets `salaryMax` and leaves `salaryMin` empty, because those are opposite bounds and
repeating one figure as both would be wrong. A single figure with no `up to` sets the minimum instead.
Indian listings written in lakh and crore are converted to plain numbers, so `₹18L – ₹25L` becomes
`1800000` and `2500000`. An explicit three-letter code beats the symbol, which matters because
Wellfound uses `$` for several different dollars.

### Why scrape Wellfound?

Wellfound is the startup end of the job market, and it is the only sizeable board where equity is part
of the public listing. That makes it a compensation dataset as much as a jobs dataset.

- Benchmark startup offers on salary and equity together, which you cannot do from any board that
  publishes only cash.
- See how equity ranges move with `companySize`, from seed-stage grants down to late-stage slivers.
- Source candidates or competitors by role across the early-stage market, filtered on `isRemote`.
- Track which startups in a headcount bucket are hiring, joined on `companySlug`.
- Watch a role market over time by running on a schedule and diffing `jobId` sets.
- Build a startup lead list from `company`, `companySize` and `location` for anyone selling to
  early-stage teams.

### How to use it

1. Put role names in **Search terms**. These address landing pages, so they should read as roles
   (`software engineer`, `product designer`, `data scientist`) rather than as boolean searches.
2. Set **Location** to a city, or leave it as `Remote`. One location per run, applied to every query.
3. Set **Maximum results** if you want a ceiling. The default is 1000.
4. Start the run, then export as JSON, CSV, Excel or XML, or read the dataset over the API.
5. To widen coverage, add more role keywords rather than raising `maxItems`. Each landing page holds
   what it holds.

### Input

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `queries` | array of strings | required | Role keywords. Between 1 and 50. Duplicates collapse to one fetch |
| `location` | string | `Remote` | A city, or `Remote`. One per run |
| `maxItems` | integer | `1000` | Cap on dataset rows, up to 50,000 |
| `concurrency` | integer | `2` | Roles fetched in parallel, up to 5 |

```json
{
  "queries": ["software engineer", "product designer", "growth marketer"],
  "location": "Remote",
  "maxItems": 1000,
  "concurrency": 2
}
```

The role and location are slugged into the landing-page URL: `wellfound.com/role/r/software-engineer`
for remote, `wellfound.com/role/l/software-engineer/san-francisco` for a city. `Remote`, `Anywhere` and
`Work from home` all mean the remote form.

### Output

One row per listing. Illustrative shape:

```json
{
  "jobId": "3129476",
  "title": "Senior Backend Engineer",
  "company": "StepSecurity",
  "companySlug": "stepsecurity",
  "salaryMin": 135000,
  "salaryMax": 175000,
  "currency": "USD",
  "equityMin": 0.05,
  "equityMax": 0.25,
  "location": "San Francisco",
  "isRemote": true,
  "companySize": "11-50",
  "jobUrl": "https://wellfound.com/jobs/3129476-senior-backend-engineer",
  "query": "backend engineer",
  "sourceUrl": "https://wellfound.com/role/r/backend-engineer",
  "collectedAt": "2026-08-20T09:14:02.118Z"
}
```

A listing with no equity mentioned returns `equityMin: null` and `equityMax: null`. One that states
`No equity` returns `0` and `0`. Keeping those apart is deliberate, because collapsing them would make
any equity average you compute quietly wrong.

Each run also writes a `SUMMARY` record with the item count, the failure count and every role that
could not be read, with its reason.

### How much does it cost?

Pay per event, charged once per result row written to the dataset. The current rate is on this Actor's
pricing tab. A role that has no landing page produces no rows and therefore costs nothing.

One role is one page fetch, so the cost of a run is roughly the number of role keywords you supply.

Runs started from an Apify **free plan** stop at **250 requests and 250 results**, and the run status
says so. Any paid plan runs the full input and your `maxItems`. The cap covers requests as well as rows
because these fetches go through our own infrastructure rather than Apify's.

### Using it with the Apify API

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")

run = client.actor("usestring/wellfound-jobs").call(run_input={
    "queries": ["software engineer", "product designer"],
    "location": "Remote",
})

with_equity = [
    job for job in client.dataset(run["defaultDatasetId"]).iterate_items()
    if job["equityMax"]
]
print(len(with_equity), "listings publish an equity range")
```

The JavaScript client and the REST API take the same input shape.

### Is it legal to scrape Wellfound?

Wellfound role landing pages are public. They exist so candidates and search engines can find startup
roles, and this Actor reads exactly what an anonymous visitor is served, with no login, no cookie and
no API key. Nothing behind Wellfound's authentication wall is touched.

The rows describe job listings and the companies that posted them. There are no candidate profiles, no
applicant data and no recruiter contact details in the output.

What you may do with the data depends on your jurisdiction and on the terms you have accepted. Treat
this as background, not legal advice.

### Related actors

- [Ashby Job Board Scraper](https://apify.com/usestring/ashby-jobs) reads the same kind of startup
  directly from its own board, once it has one.
- [Greenhouse Job Board Scraper](https://apify.com/usestring/greenhouse-jobs) covers the stage after
  that, when a startup's board has hundreds of roles on it.
- [Upwork Jobs Scraper](https://apify.com/usestring/upwork-jobs) covers the contract side of the same
  early-stage demand.
- [ZipRecruiter Jobs Scraper](https://apify.com/usestring/ziprecruiter-jobs) is the broader market
  comparison for the salary half of this dataset.
- [LinkedIn Profile Scraper](https://apify.com/usestring/linkedin-profiles) covers the people behind
  the companies you find here.

### FAQ

**Do I need a Wellfound or AngelList account?** No. No account, login, cookie or API key. Only public
role landing pages are read.

**Does it really return equity?** Yes, as numbers. `equityMin` and `equityMax` are the percentages the
listing publishes, so `0.05` and `0.25` mean 0.05% to 0.25%. A listing that says `No equity` returns
zeroes; one that says nothing at all returns nulls.

**Why did a search come back with nothing?** Wellfound serves results only for roles and locations it
has a landing page for. `software engineer` and `product designer` work. An invented or very narrow
role has no page, and the run records it under `failures` rather than returning Wellfound's generic
board and passing it off as your search.

**Can I search several locations in one run?** No. One run searches one `location` across all of its
`queries`. Start one run per city, or use `Remote`.

**Does it return the posted date or the description?** Neither. Wellfound's role landing pages publish
no posting date and no description text, so there is nothing to emit. Follow `jobUrl` for the full
posting.

**How many listings does one role return?** Around 37 in a measured run, which is what a landing page
carries. Ten role keywords come to roughly 370 listings. Adding keywords is how you widen coverage.

**How fresh is the data?** It is fetched live at run time. There is no cached index in front of it, so
the rows match the landing page at the moment the run executed.

### Feedback

If a role you expect to work comes back as a failure, or a compensation string parses oddly, open an
issue from this Actor's Store page and paste the role keyword and the listing text. Wellfound's pay
strings have long tails, and a real example is what it takes to cover one.

# Actor input Schema

## `queries` (type: `array`):

Role keywords to search for.

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

City or 'Remote'.

## `maxItems` (type: `integer`):

Global cap on dataset items. Runs started from an Apify free plan stop at 250 requests and 250 results; any paid plan runs the full amount.

## `concurrency` (type: `integer`):

Targets fetched in parallel.

## Actor input object example

```json
{
  "queries": [
    "software engineer"
  ],
  "location": "Remote",
  "maxItems": 1000,
  "concurrency": 2
}
```

# Actor output Schema

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

Collects startup jobs from Wellfound (formerly AngelList Talent) by role and location, with the salary range and the equity range as numbers rather than strings. Each row carries the company, its headcount bucket, the Wellfound handle, the location, a remote flag and a link to the posting.

## `summary` (type: `string`):

Item count, failure count and every target that failed, with its error.

# 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 = {
    "queries": [
        "software engineer"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("usestring/wellfound-jobs").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 = { "queries": ["software engineer"] }

# Run the Actor and wait for it to finish
run = client.actor("usestring/wellfound-jobs").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 '{
  "queries": [
    "software engineer"
  ]
}' |
apify call usestring/wellfound-jobs --silent --output-dataset

```

## MCP server setup

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

```

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/PZjb0HbTY41CydNrM/builds/ueMf8GevU2LkKxDsN/openapi.json
