# Wellfound Jobs Scraper, Startup Jobs by Role and Location (`george.the.developer/wellfound-jobs-scraper`) Actor

Scrape Wellfound startup jobs by role, location or remote. Each job comes with company, size, badges, location, salary, equity, job type, post date and the full description. Optional detail pages add the company website and industry. No login.

- **URL**: https://apify.com/george.the.developer/wellfound-jobs-scraper.md
- **Developed by:** [George Kioko](https://apify.com/george.the.developer) (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.00 / 1,000 job delivereds

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, Startup Jobs by Role and Location

Wellfound Jobs Scraper is an Apify Actor that collects startup job listings from Wellfound, the job board formerly known as AngelList Talent.

**No login. No account. No proxy.** Every job comes with the company, its size and badges, location, remote status, salary, equity, job type, post date and the full job description.

Search by role, by role and city, or remote only. Paste any public Wellfound role, location or job URL. Turn on job details to also get the company website, industry and exact salary numbers.

### Pricing

You pay for each distinct job saved to the dataset. Blocked pages, failed loads and duplicate jobs are never charged.

| Event | Price | You pay when |
| --- | --- | --- |
| `apify-actor-start` | $0.00005 | The platform records its start event |
| `job-result` | $0.003 per job | A distinct job is saved to the dataset |
| `job-detail` | $0.002 per job | `includeDetails` is on and the job page added detail data |

**The price is $3 per 1,000 jobs, or $5 per 1,000 jobs with details.** A run of 100 jobs without details has $0.30 in job charges plus the platform start event.

The Actor checks your remaining budget before each job and before each optional detail page. It stops cleanly when the next job would pass your maximum charge limit.

### Search startup jobs without login

Give a role. Add a city, or switch on remote only.

```json
{
  "role": "data-engineer",
  "location": "san-francisco",
  "maxJobs": 50
}
```

### How it works

1. Build the Wellfound search URL from your role, location or remote choice, or take your own URLs.
2. Open each search page in a real Chromium browser (Clearcote) with a fresh browser fingerprint.
3. Read the job and company records that Wellfound embeds in the page.
4. With `includeDetails`, open each job page and add company website, industry, country, exact salary and HTML description.
5. Save each distinct job and charge it on paid runs.
6. Stop at `maxJobs`, at the last page, at a blocked page, at your charge limit or 90 seconds before the run timeout.

```text
Role, city or URL --> Wellfound search page (real browser)
                               |
                               v
                  Embedded job and company records
                               |
              includeDetails? --+--> Job page --> website, industry, exact salary
                               |
                               v
                  Deduplicate by job ID --> Dataset --> Job event
```

Wellfound rejects plain HTTP requests, so pages are rendered in a real browser. That is slower and uses more compute than feed based scrapers, which is why the price per job is higher than on job boards with an open feed.

### What data does it extract?

Every job row has `jobId`, `title`, `role`, `company`, `companySlug`, `companyUrl`, `companyTagline`, `companySize`, `companyLogo`, `companyBadges`, `location`, `remote`, `remoteKind`, `remoteLocations`, `salary`, `equity`, `jobType`, `experienceYearsMin`, `experienceYearsMax`, `postedAt`, `description`, `jobUrl`, `source`, `searchUrl` and `scrapedAt`.

With `includeDetails` a row also gets `companyWebsite`, `industry`, `country`, `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod` and `descriptionHtml`.

`salary` and `equity` are the labels Wellfound shows, for example a dollar range and a percent range. `companyBadges` are the labels on the company card, such as Actively Hiring, YC Funded or Responds within a day. `description` is the full job text in the markdown form Wellfound stores. `remoteLocations` lists the countries a remote role accepts. Missing values are null and missing lists are empty arrays.

### Output

This row comes from a live run on Apify on October 6, 2026. The description is shortened here.

```json
{
  "jobId": "4785308",
  "title": "Senior Data Engineer",
  "role": "Data Engineer",
  "company": "Benchmark",
  "companySlug": "benchmark-14",
  "companyUrl": "https://wellfound.com/company/benchmark-14",
  "companyTagline": "College athletics intelligence, on demand",
  "companySize": "1-10",
  "companyLogo": "https://photos.wellfound.com/startups/i/11253989-cd9c62a85577132a23b83725295b725d-medium_jpg.jpg?buster=1790732845",
  "companyBadges": ["Actively Hiring", "Top 5% of responders", "Responds within a day"],
  "location": ["South Bend"],
  "remote": false,
  "remoteKind": "ONSITE",
  "remoteLocations": [],
  "salary": "$80k – $140k",
  "equity": "0.0% – 1.0%",
  "jobType": "full-time",
  "experienceYearsMin": 4,
  "experienceYearsMax": null,
  "postedAt": "2026-09-30T01:35:37.000Z",
  "description": "Benchmark is an AI-powered intelligence platform serving more than 30 universities and conferences across college athletics. ...",
  "jobUrl": "https://wellfound.com/jobs/4785308-senior-data-engineer",
  "source": "wellfound",
  "searchUrl": "https://wellfound.com/role/data-engineer",
  "scrapedAt": "2026-10-06T22:58:46.447Z"
}
```

With `includeDetails` the same kind of row also carries fields like these.

```json
{
  "companyWebsite": "https://www.tennr.com",
  "industry": "Healthcare",
  "country": "United States",
  "salaryMin": 160000,
  "salaryMax": 190000,
  "salaryCurrency": "USD",
  "salaryPeriod": "YEAR",
  "descriptionHtml": "<h3><strong>Company Description</strong></h3> ..."
}
```

### Input

| Field | Type | Default | Meaning |
| --- | --- | --- | --- |
| `role` | string | `data-engineer` | Role slug or plain words, for example `software engineer` or `product-manager` |
| `location` | string | None | City slug, for example `san-francisco`, `new-york` or `london` |
| `remoteOnly` | boolean | false | Search remote jobs for the role, takes priority over location |
| `searchUrls` | string array | None | Public wellfound.com role, location or job URLs, used as given |
| `maxJobs` | integer | 100, prefill 20 | Total distinct jobs across the run, from 1 to 2,000 |
| `includeDetails` | boolean | false | Also open each job page for website, industry and exact salary |

Search URLs follow the shapes Wellfound uses.

```json
{
  "searchUrls": [
    "https://wellfound.com/role/l/software-engineer/london",
    "https://wellfound.com/role/r/product-manager",
    "https://wellfound.com/jobs/4785308-senior-data-engineer"
  ],
  "maxJobs": 100
}
```

A `/jobs/` URL returns that one job read from its job page, with the detail fields included, and is billed as one job result.

### Start a run

1. Enter a role, and a city or remote only if you want.
2. Set the maximum number of jobs.
3. Turn on job details if you need company websites or exact salary numbers.
4. Run the Actor and export the dataset as JSON, CSV or Excel.

The prefilled input asks for 20 data engineer jobs. On Apify it finished in 57 seconds with 2 GB of memory, all 20 jobs with company and description. The first seconds of every run download the browser, about 6 seconds.

### Use from MCP agents and API clients

Add the Actor through the Apify MCP server to let an agent search startup jobs.

```text
https://mcp.apify.com/?tools=george.the.developer/wellfound-jobs-scraper
```

From Node.js with the Apify client and an Apify token.

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('george.the.developer/wellfound-jobs-scraper').call({
  role: 'data-engineer', location: 'san-francisco', maxJobs: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

With curl, wait for the run and return the jobs.

```bash
curl -X POST "https://api.apify.com/v2/acts/george.the.developer~wellfound-jobs-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"role":"data-engineer","remoteOnly":true,"maxJobs":20}'
```

### Integrations

**Clay.** Use the dataset items API as a data source and map company, companyWebsite, title and jobUrl to columns.

**n8n and Make.** Pick the Actor in the Apify node, pass the input JSON and read the dataset in the next step.

**Google Sheets.** Export rows as CSV or use the Apify Google Sheets integration.

### Use cases

- **Sales and lead generation.** Startups that are hiring are buying. Get company name, size, badges and website for every open role.
- **Recruiters.** Track which startups hire for a role in a city and what they pay.
- **Job seekers.** Collect remote roles with salary and equity in one table.
- **Market research.** Compare salary and equity ranges by role, city and company stage.

### Limits

Pages are rendered in a real browser because Wellfound blocks plain requests. If Wellfound changes its bot protection, pages can start to fail. A blocked page is retried once with a new browser fingerprint. If it is still blocked the run stops cleanly with the jobs it already saved, and blocked pages are never charged.

A search page holds about 40 to 50 jobs. The Actor moves to the next page until no new job IDs appear.

Company website, industry and exact salary numbers come only from job pages, so they need `includeDetails`, which adds about 7 seconds per job.

Only public listings are returned. No applicant data, no application forms and no recruiter contact details.

### FAQ

#### Do I need a Wellfound account or a proxy?

No. The Actor opens public pages in a real browser without logging in and without a proxy.

#### Why is it slower than other job scrapers?

Wellfound blocks plain HTTP requests. A real browser renders each page, which takes about 20 seconds per search page and 7 seconds per job page.

#### Are duplicate jobs charged twice?

No. A job ID is saved once per run, even when it shows up on several pages or searches.

#### What happens when a search has no jobs?

The run succeeds with an empty dataset and no job charges.

#### Can I run it locally?

Yes on Linux. Install Node 22 or newer, run `npm install`, put your input in `storage/key_value_stores/default/INPUT.json` and run `npm start`. The browser downloads itself on first launch. Offline tests run with `npm test`.

# Actor input Schema

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

Role slug or free text, normalized to lowercase with spaces replaced by hyphens.

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

Optional location slug such as san-francisco or london for the role plus location route.

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

Use the public remote role route. Takes precedence over location.

## `searchUrls` (type: `array`):

Public wellfound.com role, location or job URLs, used as given, for example https://wellfound.com/role/l/software-engineer/london. A /jobs/ URL returns that one job with full detail. Overrides role and location.

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

Total distinct job rows across the run.

## `includeDetails` (type: `boolean`):

Also open each job page to add the company website, industry, country, exact salary numbers and the HTML description. Adds one detail event per job that gained detail data. Slower, about 7 seconds per job.

## Actor input object example

```json
{
  "role": "data-engineer",
  "remoteOnly": false,
  "maxJobs": 20,
  "includeDetails": false
}
```

# Actor output Schema

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

Distinct Wellfound startup jobs with company details, salary, equity and full descriptions.

# 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": "data-engineer",
    "maxJobs": 20,
    "includeDetails": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("george.the.developer/wellfound-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": "data-engineer",
    "maxJobs": 20,
    "includeDetails": False,
}

# Run the Actor and wait for it to finish
run = client.actor("george.the.developer/wellfound-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": "data-engineer",
  "maxJobs": 20,
  "includeDetails": false
}' |
apify call george.the.developer/wellfound-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,george.the.developer/wellfound-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/2nENxStgeINajiz5k/builds/31nxwf8SqRjLpqHgh/openapi.json
