# Wellfound Startup Job Scraper (`superslowsloth/wellfound-jobs-scraper`) Actor

Scrape startup and tech jobs from Wellfound (formerly AngelList Talent) - title, company, salary band, equity, location, remote policy and the full job description.

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

## Pricing

from $1.04 / 1,000 job listings

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 Job Scraper

Returns startup and tech jobs from [Wellfound](https://wellfound.com) (formerly
AngelList Talent): the job title, the hiring company, the salary and equity
band, the location, the remote policy, the years of experience asked for, and
the full job description as the company wrote it.

Search by role - `software engineer`, `product manager`, `data scientist` - and
optionally by city, or across Wellfound's remote-only listings.

### What a "page" means here, and why the budget is in jobs

Wellfound's own payload reports `perPage: 20`, and that twenty counts
**companies**, not jobs. Each company brings up to three of its listings along
with it, so one page really carries around forty jobs. Every budget in this
actor is therefore expressed in jobs, never in pages: `maxItems` is a count of
rows you will be charged for, whatever shape the pages arrive in.

### Every job is delivered and charged exactly once

Wellfound re-ranks its results between requests, so the same listing genuinely
appears on more than one page - 8 of 46 job ids were shared between page 1 and
page 2 of a single search when this was measured on 2026-09-11. A job also
legitimately matches more than one of your roles.

De-duplication is global across the whole run, and it happens *before* the
charge. You are never billed twice for one listing.

### Output fields

| Field | Notes |
|---|---|
| `id` | Wellfound's listing id. |
| `url` | Canonical listing URL, e.g. `https://wellfound.com/jobs/4692045-software-engineer`. |
| `title` | The title the company typed, e.g. `Senior Software Engineer - Android`. |
| `slug` | The URL slug for the listing. |
| `primary_role_title` | Wellfound's own normalised role, e.g. `Software Engineer`. A different field from `title`. |
| `description` | The full job description, in the Markdown Wellfound stores it as. |
| `job_type` | `full-time`, `internship`, `contract` and so on, as printed. |
| `compensation` | The band exactly as printed, e.g. `$130k – $210k • 0.05% – 0.2%`. |
| `compensation_min`, `compensation_max` | Salary figures read out of `compensation`. |
| `compensation_currency` | ISO code for the currency the band is printed in - `USD`, `EUR`, `GBP`. |
| `remote` | Wellfound's remote flag on the listing. |
| `remote_kind` | `ONSITE`, `REMOTE` or `ONSITE_OR_REMOTE` where the company set it. |
| `wfh_flexible` | Whether the company marked the role work-from-home flexible. |
| `years_experience_min`, `years_experience_max` | Experience asked for. |
| `live_start_at`, `live_start_at_iso` | When the listing went live, as Unix seconds and as ISO-8601 UTC. |
| `auto_posted` | Whether the listing was synced in automatically rather than written on Wellfound. |
| `ats_source` | Which applicant-tracking system it came from, e.g. `AtsIntegration::Greenhouse::Listing`. |
| `company_id`, `company_name`, `company_slug`, `company_url` | The hiring company. |
| `company_logo_url` | The company's logo. |
| `company_high_concept` | The company's one-line pitch. |
| `company_size` | Headcount band in Wellfound's own vocabulary, e.g. `SIZE_11_50`. |
| `company_badges` | Labels Wellfound shows on the company, e.g. `["Actively Hiring", "Top 10% of responders"]`. |
| `location_names` | Locations on the listing, e.g. `["San Francisco"]`. Empty on a remote listing. |
| `accepted_remote_location_names` | Where a remote listing will hire from. |
| `role`, `location`, `remote_only` | Which of your searches produced this row. |

### What this source does not give

Stated rather than guessed. A missing value is always `null`, never `0` and
never an empty string, because a zero reads as a measurement that was never
taken.

- **No salary on many listings.** Wellfound prints an empty band when the
  company did not state one; that arrives as `null`, not `""`.
- **A compensation string can carry equity and no salary at all.** `No equity`
  on its own is a real value. It sets `compensation_min` and
  `compensation_max` to `null` rather than to zero.
- **Equity percentages are not parsed into numbers.** They are in the
  `compensation` string, but `0.05% – 0.2%` is not money and is deliberately
  not folded into the salary fields.
- **Not every band is in dollars.** Euro bands appear alongside dollar ones,
  which is why `compensation_currency` exists. Do not assume USD.
- **`years_experience_min` of `0` is a real answer** - the company said no
  experience is required. It is not the same as `null`, which means the
  company said nothing.
- **`remote_kind` is absent on most listings**, and absent is not the same as
  onsite. Use `remote` for the flag the site actually sets on every row.
- **No applicant count, no company funding history, no founder details.** The
  search payload does not carry them.
- **Company size is a band, not a number.** `SIZE_11_50` is left in Wellfound's
  vocabulary rather than converted into an invented midpoint.

### Anti-bot behaviour

Wellfound answered a plain datacenter address with no proxy on 2026-09-11, so a
proxy is optional. It does rate-limit an address that walks pages quickly: the
refusal is an HTTP 403 "Security Check" page carrying no data at all. The
scraper classifies that as temporary, takes a fresh exit address and retries,
which is what the proxy is there for. An unknown role is a genuine 404 and is
not retried - retrying it would only spend your money.

### Input

```json
{
  "roles": ["software engineer", "product manager"],
  "location": "san francisco",
  "maxItems": 100,
  "maxPages": 10,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

`location` and `remote` cannot be combined. Wellfound has no search for remote
jobs in a named city, so a run asking for both fails immediately rather than
quietly dropping half the request and charging for the rest.

# Actor input Schema

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

One or more roles to search Wellfound for, e.g. "software engineer", "product manager", "data scientist". Spaces are fine - they are turned into the slug the site uses. Each role is searched separately and the results are merged, with any job that matches more than one role delivered and charged only once.

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

Optional. A city to restrict the search to, e.g. "san francisco", "new york", "london". Leave empty to search every location. Wellfound has no remote-in-a-named-city search, so this cannot be combined with Remote only.

## `remote` (type: `boolean`):

Search Wellfound's remote-only listings instead of all listings. Cannot be combined with Location: the site has no endpoint for remote jobs in a named city, and a run that asked for both would silently drop half the request, so it fails fast instead.

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

Budget for the whole run, across every role, not per role. Jobs that appear under more than one role, or on more than one page, are delivered and charged once each.

## `maxPages` (type: `integer`):

How deep to walk a single role. A page carries around 40 jobs - Wellfound's own "20 per page" counts companies, and each company brings up to three listings. The site paginates far deeper than this default (91 pages for software engineer), but every extra page is another request against an address the site will eventually rate-limit, so more roles is usually better than a deeper walk on one.

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

Optional. Wellfound answered a plain datacenter address on 2026-09-11 with no proxy at all, so this is not required. It does rate-limit an address that walks pages quickly - the refusal is a "Security Check" page - and a proxy is what gives the scraper a fresh address to retry on when that happens.

## Actor input object example

```json
{
  "roles": [
    "software engineer"
  ],
  "remote": false,
  "maxItems": 100,
  "maxPages": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `jobs` (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": [
        "software engineer"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

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

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

```

## MCP server setup

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