# Wellfound Jobs Scraper — Salary, Equity & ATS Data (`kaankaan2635/wellfound-scraper`) Actor

Wellfound (AngelList) startup job listings with salary and equity ranges parsed into numbers, plus the applicant tracking system each company runs.

- **URL**: https://apify.com/kaankaan2635/wellfound-scraper.md
- **Developed by:** [Kaan Salgır](https://apify.com/kaankaan2635) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 job listing scrapeds

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Wellfound Jobs Scraper — Salary, Equity & ATS Data

This **Wellfound scraper** (formerly AngelList Talent) exports startup job listings with **salary and equity ranges parsed into numbers**, plus the **applicant tracking system** each company runs.

No account, no API key.

### Wellfound salary data you can actually sort

Wellfound publishes compensation as one display string:

```
$130k – $210k • 0.05% – 0.2%
```

A scraper that hands that back untouched has given you a string you cannot sort, filter or average. This one splits it:

| Field | Value |
| --- | --- |
| `salaryMin` | `130000` |
| `salaryMax` | `210000` |
| `salaryCurrency` | `USD` |
| `equityMin` | `0.05` |
| `equityMax` | `0.2` |
| `offersEquity` | `true` |

`• No equity` sets `offersEquity: false` — a stated fact, kept distinct from a listing that simply says nothing. USD, EUR, GBP, INR and JPY are recognised, and inverted ranges are corrected.

On a single San Francisco engineering search that yields a median base of **$160,000** across a range of $80k–$500k.

### Startup jobs data: which ATS each company uses

Every listing carries `atsSource`: `Greenhouse`, `Ashby`, `Lever` and so on, normalised from Wellfound's internal identifier. On one San Francisco engineering search that split 26 Ashby to 19 Greenhouse.

If you sell into recruiting, that is a qualified lead list. If you are studying the market, it is adoption data nobody publishes.

### What you get

**Per listing:** `title` · `url` · `jobType` · `remote` · `locationNames` · `remoteLocationNames` · `primaryRoleTitle` · `compensationRaw` · `salaryMin` · `salaryMax` · `salaryCurrency` · `equityMin` · `equityMax` · `offersEquity` · `yearsExperienceMin` · `yearsExperienceMax` · `atsSource` · `autoPosted` · `postedAt` · `description`

**Company fields on every job row**, with no second request: `companyName` · `companySlug` · `companySize` · `companyTagline` · `companyId`

Turn on **Also emit company rows** for one deduplicated row per company, including `companyBadges` and `companyLogoUrl`.

### How to use this Wellfound scraper

```json
{
  "roles": ["software-engineer", "product-manager"],
  "locations": ["san-francisco", "new-york", "remote"],
  "maxJobs": 2000,
  "maxPagesPerSearch": 10
}
```

Roles and locations are crossed: 2 roles across 3 locations is 6 searches. Leave `locations` empty to search each role worldwide. Plain titles (`Software Engineer`) are slugified for you, and you can pass Wellfound role URLs directly as `startUrls`.

Listings that appear in more than one search are returned once — `maxJobs` counts unique listings, not requests.

### FAQ

**Do I need a Wellfound or AngelList account?**
No. This reads public role landing pages.

**Can it scrape recruiter or candidate contact details?**
No. Wellfound's robots.txt disallows `/u/` — the member profile space — and `/search`, and this scraper requests neither. No candidate or recruiter names, emails or profiles are collected. Job descriptions pass through as the employer published them.

**How many listings does a search return?**
Roughly 35–50 per page, and it pages until it hits your `maxJobs` or `maxPagesPerSearch` cap.

**Why do some listings have no salary?**
Because the employer did not publish one. About 3 in 100 listings omit compensation entirely; those come back with null salary fields and the raw string preserved in `compensationRaw`.

**Does it scrape company detail pages?**
No — `/company/*` sits behind bot protection. Everything reported about a company comes from the listing feed itself, which is why company rows cost no extra requests.

**Which locations can I use?**
Any slug Wellfound uses, for example `san-francisco`, `new-york`, `london`, `remote`, `berlin`.

**Is scraping Wellfound legal?**
It reads publicly accessible listing pages, honours robots.txt, and collects no personal data. How you use the output is your responsibility.

### Notes on reliability

Wellfound returns 403 to unproxied bulk traffic. Use Apify Proxy, which is the default, and leave the conservative request rate alone unless you see clean results at a higher one. Blocked requests are retried on a fresh session automatically.

### Pricing

Pay per event: one charge per job listing, one per company row (only when you ask for company rows). Nothing is charged for compute time, retries or failed requests.

### Development

```bash
npm install
npm test          # offline regression tests against a saved page
npm start         # local run; put an INPUT.json in storage/key_value_stores/default/
```

# Actor input Schema

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

Role slugs as they appear in Wellfound URLs, for example <code>software-engineer</code>, <code>product-manager</code>, <code>designer</code>, <code>data-scientist</code>. Plain titles like <code>Software Engineer</code> also work.

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

Optional. Every role is crawled in every location, so 2 roles and 3 locations means 6 searches. Examples: <code>san-francisco</code>, <code>new-york</code>, <code>remote</code>, <code>london</code>. Leave empty to search each role worldwide.

## `startUrls` (type: `array`):

Wellfound role landing pages to crawl directly, for example <code>https://wellfound.com/role/l/software-engineer/san-francisco</code>.

## `maxJobs` (type: `integer`):

Hard cap on listings across the whole run. Duplicates across searches are counted once.

## `maxPagesPerSearch` (type: `integer`):

Each page returns roughly 35-50 listings.

## `includeCompanyRows` (type: `boolean`):

Every job row already carries its company name, size and tagline. Turn this on to additionally get one deduplicated row per company.

## `maxConcurrency` (type: `integer`):

How many pages to fetch in parallel. Lower this if listings start coming back empty or blocked.

## `maxRequestsPerMinute` (type: `integer`):

Wellfound blocks aggressive crawling. The default is deliberately conservative.

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

Apify Proxy is strongly recommended — Wellfound returns 403 to unproxied bulk traffic.

## Actor input object example

```json
{
  "roles": [
    "software-engineer"
  ],
  "locations": [],
  "startUrls": [],
  "maxJobs": 500,
  "maxPagesPerSearch": 10,
  "includeCompanyRows": false,
  "maxConcurrency": 5,
  "maxRequestsPerMinute": 60,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `jobs` (type: `string`):

One row per listing, with company name, size and tagline included. Company rows are added when that option is on.

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

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

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kaankaan2635/wellfound-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/dxVUB6YXfSepewMXu/builds/fLFvL7RAfnSYBoPRi/openapi.json
