Wellfound Jobs Scraper (AngelList)
Pricing
from $0.09 / 1,000 job returneds
Wellfound Jobs Scraper (AngelList)
Wellfound refuses a share of plain HTTP requests, so every page gets up to six attempts from a new address and fingerprint. A page that lands carries every job in full: Markdown description, salary and equity split apart, company badges, exact posting time. $0.085 per 1,000.
Pricing
from $0.09 / 1,000 job returneds
Rating
0.0
(0)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
10 hours ago
Last modified
Categories
Share
Wellfound Jobs Scraper (AngelList Talent)
Wellfound refuses a share of plain HTTP requests outright, with a 403 and no explanation, so this actor gives every listing page up to six attempts, each from a new proxy session and a different browser fingerprint. What lands is worth the retries: a role page carries the complete text of every job on it, not a teaser. Checked on 2026-08-21, all 47 jobs on /role/product-manager came back with a full Markdown description, median around 5,000 characters, none empty.
A role slug like software-engineer is all the input it needs. Each row carries the full job description in Markdown, the compensation string split into salary and equity, the company with its size and Wellfound badges, and the exact posting timestamp.
It runs over plain HTTP. There's no login, no cookie and no headless browser involved, and it never touches residential proxy.
Why the descriptions come back complete
Wellfound's role pages are Next.js pages that ship their own Apollo cache inside __NEXT_DATA__. Every job on the page is already a fully-typed JobListingSearchResult with the whole Markdown description attached, and every company is a StartupResult linked to its jobs. The actor reads that cache straight off the page.
One page request therefore returns roughly 40 to 49 complete jobs. Nothing has to be fetched a second time to get the description, so pulling 200 jobs is 5 requests rather than 205.
Output
| Field | Notes |
|---|---|
jobId, title, jobUrl | the listing |
companyName, companyUrl, companySlug, companyTagline, companySize, companyLogoUrl, companyBadges | company, joined from the same cache. companySize is Wellfound's enum (SIZE_11_50), companyBadges its own labels ("Actively Hiring", "YC Funded", "Top Investors") |
jobType | full-time, internship, contract, part-time, cofounder |
remote, remoteKind, locations, remoteLocations | remoteKind is Wellfound's ONSITE_OR_REMOTE / REMOTE_ONLY enum |
compensation, salaryText, equityText | compensation is Wellfound's raw string ("$135k – $175k • 0.05% – 0.25%"). The other two are that string split in half, never invented |
yearsExperienceMin | only when the poster set one |
description | the whole description in Markdown, as Wellfound stores it |
postedAt | exact ISO timestamp from liveStartAt |
autoPosted, atsSource | whether it arrived from an ATS, and which one |
sourceUrl, page, scrapedAt | provenance |
How often each field is filled
From a 200-row platform run on 2026-08-10: roles software-engineer and product-manager, 3 pages each, 83 distinct companies, 200/200 rows real, 0 diagnostics, 21 seconds.
| Field | Filled |
|---|---|
jobId, title, jobUrl, companyName, companyUrl, companySlug, companySize, companyLogoUrl, companyBadges, primaryRoleTitle, jobType, description, postedAt | 100% |
companyTagline | 97.5% |
compensation, salaryText | 92.5% |
locations | 87.0% |
atsSource | 80.0% |
remoteKind | 28.5% |
remoteLocations | 23.5% |
yearsExperienceMin | 21.5% |
equityText | 14.5% |
Median description length was 4,663 characters. Those percentages move with the roles you pick. A later 252-row sample across different roles came back with salary on 83% and equity on 10%. Equity is the field to watch: most Wellfound posters simply leave it blank, and nothing here is filled in with a guess.
Input
roleSlugs—software-engineer,product-manager,data-scientist. Plain phrases get slugified ("Data Scientist" becomesdata-scientist) and fullwellfound.com/role/<slug>URLs are accepted.searchQueriesis an alias for the same field.locationSlugs— optional, such assan-francisco,new-york,london. Each role is then crawled once per location viawellfound.com/role/l/<role>/<location>.remoteOnly— switches towellfound.com/role/r/<role>and keeps only listings flagged remote. Ignored whenlocationSlugsis set.jobTypes,locationFilters,keywords— filters applied on our side. Rows they drop are not returned and not charged.maxItems(default 100),maxPagesPerSource(default 5),maxRetries(default 6),requestTimeoutSecs(default 25).proxyConfiguration— optional. Leave it empty and the actor uses Apify datacenter proxy with a fresh session per attempt, which is what it's tuned for.
Empty input returns exactly one row labelled _sample: true and charges nothing.
{"roleSlugs": ["software-engineer", "product-manager"],"locationSlugs": ["san-francisco"],"jobTypes": ["full-time"],"keywords": ["python"],"maxItems": 200,"maxPagesPerSource": 5}
That crawls wellfound.com/role/l/software-engineer/san-francisco and the product-manager equivalent, up to 5 pages each, keeps full-time listings whose title, company or description mentions "python", and stops at 200 rows.
Remote instead of a city:
{ "roleSlugs": ["data-scientist"], "remoteOnly": true, "maxItems": 100 }
A real output row
{"ok": true,"_sample": false,"jobId": "3317746","title": "Software Engineer","jobUrl": "https://wellfound.com/jobs/3317746-software-engineer","companyName": "Keeper","companyUrl": "https://wellfound.com/company/keeper-tax","companySlug": "keeper-tax","companyTagline": "File your complex taxes confidently","companySize": "SIZE_11_50","companyLogoUrl": "https://photos.wellfound.com/startups/i/keeper-tax-logo.png","companyBadges": ["Actively Hiring", "YC Funded"],"primaryRoleTitle": "Software Engineer","jobType": "full-time","remote": true,"remoteKind": "ONSITE_OR_REMOTE","locations": ["San Francisco"],"remoteLocations": ["United States"],"compensation": "$135k – $175k • 0.05% – 0.25%","salaryText": "$135k – $175k","equityText": "0.05% – 0.25%","yearsExperienceMin": 0,"description": "### Mission\n\nWe are building…","postedAt": "2026-08-01T00:00:00.000Z","autoPosted": false,"atsSource": "greenhouse","sourceUrl": "https://wellfound.com/role/software-engineer","page": 1,"scrapedAt": "2026-08-10T09:14:02.113Z"}
Diagnostic rows have the opposite shape: ok: false, _diagnostic: true, an errorCode of BAD_INPUT, BLOCKED, RATE_LIMITED, NOT_FOUND, SERVER_ERROR, NETWORK, PARSE_ERROR or NO_RESULTS, and a plain-English error. Filter on ok === true if you only want jobs.
Reliability
Wellfound 403s a share of requests no matter what address they come from. Rotation is what fixes that, not a better address: every attempt uses a new proxy session over rotating datacenter addresses and a different browser TLS fingerprint. On the 200-row run above, 4 of the 5 listing pages parsed on the first attempt and the fifth on the third. None failed outright. A page that never parses becomes an uncharged BLOCKED diagnostic row, so a bad day costs you the start fee and nothing more.
Retries back off, 300 ms doubling to a 5 s ceiling with jitter, so a temporary refusal doesn't turn into a hammering loop. maxRetries caps attempts per page and requestTimeoutSecs caps a single request, which gives a run a predictable worst case.
An earlier build drove a headless browser and fell back to a per-gigabyte proxy whenever it got blocked. It was slower, much more expensive, and still got refused. Both are gone. The direct HTTP path turned out to be cheaper and more reliable, and that's what makes the price below workable.
Billing
Pay per event, event name job: $0.085 per 1,000 jobs, plus a $0.001 start fee per run.
One event per unique job row. Duplicates across pages are charged once, because the runner keeps a set of jobIds, so overlapping pages and two roles that surface the same listing bill once rather than twice. Never charged: the empty-input sample row, rows dropped by jobTypes / locationFilters / keywords, and every diagnostic row.
So 1,000 jobs in one run costs $0.001 + $0.085 = $0.086. A run that finds nothing costs the $0.001 start fee alone. Because descriptions arrive with the listings, there's no second charge for "detail" rows.
What this does not do
- No company-jobs pages.
wellfound.com/company/<slug>/jobssits behind Wellfound's login wall and returned 403 on 8 straight attempts across 4 fingerprints, so that input isn't offered rather than offered and broken. - No per-job detail requests. They'd be pointless; the listing cache already has the full description.
- No recruiter contact details, no candidate profiles, and it doesn't apply to anything.
- No salary normalisation into numbers. Wellfound publishes a string, so you get the string plus its salary and equity halves.
- No residential proxy.
FAQ
What's a role slug?
The last path segment of a Wellfound role page. wellfound.com/role/software-engineer gives you software-engineer. Pasting the whole URL works too.
How many jobs per page?
Roughly 40 to 49. maxPagesPerSource sets how deep it goes, and deep pagination does work: page 20 and page 60 both returned jobs in testing.
Do I really get the full description? Yes, in Markdown, on every row. Median length in the measured run was 4,663 characters.
Can I filter to remote jobs?
Set remoteOnly: true. That switches to Wellfound's remote role pages and drops any listing not flagged remote.
Can I search one city?
Put the city slug in locationSlugs. Use locationFilters instead if you'd rather do a plain substring match over whatever locations a job lists.
What if Wellfound blocks it?
Each page is retried up to maxRetries times on a fresh session and fingerprint. If every attempt fails you get one uncharged BLOCKED row explaining what happened, and no job charges.
Is the sample row charged?
No. Empty input returns one _sample: true row and zero billable events.