How to use Wellfound Jobs Scraper
Step by step: in the Apify Store, over the API, from JavaScript or Python, in n8n, and from AI agents through MCP or LangChain.
$2.70 per 1,000 jobs (live Apify price on 2026-11-03).
1. In the Apify Store (no code)
- Open arcadium/wellfound-jobs and sign in to Apify (a free account works).
- Fill in the input form. The fields below are the ones the example uses.
- Set a maximum cost per run in the run options if you want a hard cap.
- Start the run. Rows appear in the Output tab as they arrive.
- Export the dataset as JSON, CSV or Excel, or connect an integration.
| Input field | Type | Description |
|---|---|---|
roles | array | Wellfound role names or slugs, e.g. ["software engineer", "product manager", "data-scientist"]. Each role is searched in every location below. Wellfound's own role list: wellfound.com/role/<slug>. |
locations | array | City or country names or slugs, e.g. ["San Francisco", "New York", "London", "united-states"]. "remote" searches remote jobs. Without roles, each location returns all startup jobs there. Empty = no location filter. |
startUrls | array | Wellfound role or location pages, e.g. https://wellfound.com/role/l/software-engineer/san-francisco, https://wellfound.com/role/r/data-scientist or https://wellfound.com/location/berlin. |
maxJobsPerSearch | integer | Jobs per role and location or URL, 1 to 10,000 (default 100). A search ends when Wellfound has no more pages. |
Example input:
{
"roles": [
"software engineer"
],
"locations": [
"New York"
],
"startUrls": [],
"maxJobsPerSearch": 50
}
2. Over the Apify API
The synchronous endpoint runs the actor and returns its rows in one call (for runs up to about five minutes; use the asynchronous run endpoint for longer ones).
curl -X POST "https://api.apify.com/v2/acts/arcadium~wellfound-jobs/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"roles":["software engineer"],"locations":["New York"],"startUrls":[],"maxJobsPerSearch":50}'
3. From JavaScript
// npm install apify-client
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('arcadium/wellfound-jobs').call({
"roles": [
"software engineer"
],
"locations": [
"New York"
],
"startUrls": [],
"maxJobsPerSearch": 50
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
4. From Python
# pip install apify-client
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("arcadium/wellfound-jobs").call(run_input={
"roles": ["software engineer"],
"locations": ["New York"],
"startUrls": [],
"maxJobsPerSearch": 50,
})
items = client.dataset(run.default_dataset_id).list_items().items # apify-client 3.x returns a Run object
print(items)
5. In n8n
Paste this node into a workflow (it is a plain HTTP Request node). Create a Header Auth credential with name Authorization and value Bearer <APIFY_TOKEN>; each returned row becomes one item for the next node.
{
"nodes": [
{
"name": "Run arcadium/wellfound-jobs",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
0,
0
],
"parameters": {
"method": "POST",
"url": "https://api.apify.com/v2/acts/arcadium~wellfound-jobs/run-sync-get-dataset-items",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "{\"roles\":[\"software engineer\"],\"locations\":[\"New York\"],\"startUrls\":[],\"maxJobsPerSearch\":50}",
"options": {
"timeout": 300000
}
}
}
],
"connections": {}
}
6. From an AI assistant (MCP)
Add Apify’s MCP server to Claude Desktop, Cursor, VS Code or any MCP client, limited to this actor:
{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com/?tools=arcadium/wellfound-jobs",
"headers": {
"Authorization": "Bearer <APIFY_TOKEN>"
}
}
}
}
More on the MCP page.
7. From LangChain
# pip install langchain-apify (reads APIFY_API_TOKEN from the environment)
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("arcadium/wellfound-jobs")
rows = tool.invoke({"run_input": {
"roles": ["software engineer"],
"locations": ["New York"],
"startUrls": [],
"maxJobsPerSearch": 50,
}})
# or give `tool` to an agent: create_react_agent(llm, [tool])
Sample output
One row, from the example in the actor’s README. Long text is shortened and lists are cut to two items.
{
"rowType": "job",
"platform": "wellfound",
"jobId": "4844846",
"url": "https://wellfound.com/jobs/4844846-software-engineer",
"title": "Software Engineer",
"role": "Software Engineer",
"jobType": "full-time",
"remote": false,
"remoteKind": null,
"wfhFlexible": null,
"locations": [
"New York"
],
"acceptedRemoteLocations": [],
"compensation": "$142k – $187k",
"salary": {
"min": 142000,
"max": 187000,
"currency": "USD",
"period": "year",
"source": "structured"
},
"equityMinPercent": null,
"equityMaxPercent": null,
"yearsExperienceMin": null,
"yearsExperienceMax": null,
"postedAt": "2026-10-15T00:02:06Z",
"description": "## About Check\n\nPayroll is broken. It's still running on decades-old infrastructure. **We're rebuilding it.** ...",
"atsSource": "ashby",
"autoPosted": false,
"companyId": "8170097",
"companyName": "Check",
"companySlug": "checkhq",
"companyUrl": "https://wellfound.com/company/checkhq",
"companyTagline": "Check’s mission is to make paying people simple",
"companySize": "51-200",
"companyStage": "Growth Stage",
"companyBadges": [
"Actively Hiring",
"B2B"
],
"ycFunded": false,
"topInvestors": true,
"recentlyFunded": false,
"valuation": "Valuation $500M+",
"companyLogoUrl": "https://photos.wellfound.com/startups/i/8170097-670b14dbd6d668e33d45382818a7008d-medium_jpg.jpg",
"companyWebsite": "https://checkhq.com/",
"industries": [
"SaaS",
"Enterprise Software"
],
"jobLocations": [
{
"locality": null,
"region": "New York",
"country": "United States"
}
],
"directApply": true,
"validThrough": null,
"detailsIncluded": true,
"source": "software engineer in new york",
"sourceType": "roleLocation",
"searchRole": "software-engineer",
"searchLocation": "new-york",
"position": 1,
"scrapedAt": "2026-10-22T12:00:00.000Z"
}
| Field | What it holds |
|---|---|
rowType | Kind of row. Filter on this first. Values: 'job': one job with its startup (charged). 'error': a role, location or URL gave no jobs; see code and message (free). |
platform | Always 'wellfound'. |
jobId | Wellfound job id (digits), stable across runs. Use it to deduplicate. |
url | Job page on Wellfound, e.g. https://wellfound.com/jobs/2421931-software-engineer. |
title | Job title as posted. |
role | Wellfound's role category of the job, e.g. 'Software Engineer'. |
jobType | Values: full-time, contract, internship, cofounder. |
remote | True when the job can be done remotely. |
remoteKind | Values: ONSITE, REMOTE, ONSITE_OR_REMOTE. Null when the startup did not set it. |
wfhFlexible | True when the startup marks work from home as flexible. Null when not set. |
locations | Office locations of the job, e.g. ['New York', 'San Francisco']. |
acceptedRemoteLocations | Where remote candidates may live, e.g. ['United States']. Empty when not restricted or not remote. |
compensation | Pay and equity text as Wellfound shows it, e.g. '$75k – $150k CAD • 0.0% – 0.1%'. |
salary | Pay range {min, max, currency, period, source}; 'structured' when read from the job page, 'text' when parsed from compensation. Null when no pay is shown. |
equityMinPercent | Low end of the equity offer in percent. Null when none is shown. |
equityMaxPercent | High end of the equity offer in percent. Null when none is shown. |
yearsExperienceMin | Minimum years of experience asked for. Null when not set. |
yearsExperienceMax | Maximum years of experience asked for. Null when not set. |
postedAt | When the job went live, ISO 8601. |
description | Full job description in Markdown; emails, phone numbers and greeting names are removed. Null with descriptionFormat none. |
atsSource | Applicant tracking system the job was imported from: greenhouse, ashby, lever, workable, ... 'other' for one we do not list, null when posted on Wellfound directly. |
autoPosted | True when Wellfound imported the job automatically. |
companyId | Wellfound startup id. |
companyName | Startup name. |
companySlug | Startup slug on Wellfound, e.g. 'checkhq'. |
companyUrl | Startup profile on Wellfound, built from companySlug. |
companyTagline | The startup's one-line pitch as shown on Wellfound. |
companySize | Employee range, e.g. '1-10', '11-50', '51-200', '5000+'. |
companyStage | Stage badge: 'Early Stage', 'Growth Stage', 'Scale Stage' or 'Public Stage'. Null when not shown. |
companyBadges | All badges Wellfound shows, e.g. 'Top Investors', 'YC Funded', 'Recently funded', 'Responds within a week'. |
ycFunded | True when Wellfound shows the YC Funded badge. |
topInvestors | True when Wellfound shows the Top Investors badge. |
recentlyFunded | True when Wellfound shows the Recently funded badge. |
valuation | Valuation badge, e.g. 'Valuation $1B+'. Null when not shown. |
companyLogoUrl | Startup logo image. |
companyWebsite | Startup website from the job page (includeJobDetails). Null otherwise. |
industries | Industries from the job page, e.g. ['SaaS', 'Fin Tech'] (includeJobDetails). Null otherwise. |
jobLocations | Structured job addresses [{locality, region, country}] from the job page (includeJobDetails). Null otherwise. |
directApply | True when you apply on Wellfound itself (includeJobDetails). Null otherwise. |
validThrough | Closing date of the posting when the job page gives one. Null otherwise. |
detailsIncluded | True when the job page was read for this row. |
source | The search this job came from, e.g. 'software engineer in New York' or a URL. |
sourceType | Values: role, roleLocation, roleRemote, location, url. |
searchRole | Role slug of the search, e.g. 'software-engineer'. Null for location searches. |
searchLocation | Location slug of the search, 'remote' for remote searches, null when none. |
position | 1-based rank of the job in its search. |
jobsDb | Only with jobsDbExport: {ats, companyDomain, fingerprint} for merging with other job sources. |
scrapedAt | When the row was read, ISO 8601. |
input | Error rows only: the role, location or URL that gave no jobs. |
code | Error rows only. Values: not_found, no_match, unavailable, blocked, invalid_input. |
message | Error rows only: what went wrong, in plain words. |
Schedule it
In Apify Console, create a Task from your input and add a Schedule (for example daily). Each run writes a new dataset; integrations can push the rows to Google Sheets, Slack, a webhook or your database.