Wellfound Jobs Scraper - Startup Roles, Salaries & Remote Jobs
Pricing
from $1.00 / 1,000 dataset items
Wellfound Jobs Scraper - Startup Roles, Salaries & Remote Jobs
Scrape startup jobs from Wellfound.com by keyword, location, role, or remote status. Extract job details, compensation, company badges, and other listing data, with MCP connector export support.
Pricing
from $1.00 / 1,000 dataset items
Rating
5.0
(1)
Developer
Abot API
Maintained by CommunityActor stats
1
Bookmarked
4
Total users
2
Monthly active users
3 days ago
Last modified
Categories
Share
Wellfound Scraper: Startup Jobs, Compensation & Company Data
Wellfound Scraper turns Wellfound startup job listings into a clean dataset. Search one or more Wellfound locations, or paste Wellfound job-search links, and get job title, role, compensation, remote status, posting date, and company details (size, logo, high concept, hiring badges) for every matching listing, plus the full job description text whenever Wellfound's own page data carries it. Narrow results by keyword, role, remote status, compensation, and hiring badges in either mode, then export to JSON, CSV or Excel, or read results straight through the API.
Why This Scraper?
- Two clear modes. Search mode builds Wellfound location pages for you from a list of location slugs; URL mode reads Wellfound
/jobsor/location/...links you paste in. No manual URL building for search mode. - Full job and company context in every row. Title, role, compensation range, remote status, locations, posting date, plus the company's size, logo, one-line pitch and hiring badges.
- Full job description text included whenever Wellfound's own listing data carries it.
- Five filters, both modes. Keyword, role keyword, remote-only, require-compensation and actively-hiring-only all apply whether you searched by location or pasted URLs, so a bulk pull still comes back narrowed.
- Resume and recurring monitoring. Continue one interrupted run from its run ID, or turn on Incremental mode for a schedule that returns only the jobs that are new, changed, or newly back.
- MCP connector export. Send a condensed, human-readable job summary into Notion, Linear, Airtable or Apify connectors while the complete record always stays in the dataset.
- Fails loudly when genuinely blocked. A run where every request is refused stops with a clear message instead of quietly billing an empty result.
Use Cases
- Startup recruiters and sourcers: build a running feed of new engineering, product and sales roles at companies in specific cities or remote-friendly searches.
- Job boards and aggregators: mirror Wellfound listings with company and compensation context to power your own search or alerting product.
- Compensation research: collect posted salary ranges and equity mentions across roles and locations for benchmarking.
- Sales and BD prospecting: use the "actively hiring" and investor/responder badges as signals for which startups are growing right now.
- Job seekers and career sites: track new remote-eligible roles matching specific keywords on a recurring schedule.
Data You Get
Sample shape: values are illustrative placeholders, not from a live listing.
| Field | Example |
|---|---|
jobId | "00000001" |
jobUrl | "https://wellfound.com/jobs/00000001-sample-role" |
jobTitle | "Sample Platform Engineer" |
jobType | "full-time" |
primaryRoleTitle | "Software Engineer" (or a role slug like "software-engineer" when only the role code is available) |
descriptionText | "Full role description text appears here." (markdown stripped, capped at 5000 characters) |
compensation | "$100k - $150k" |
compensationMin / compensationMax | 100000 / 150000 |
hasCompensation / hasEquity | true / false |
locations | ["San Francisco"] |
acceptedRemoteLocations | ["United States"] |
remote / remoteKind | true / "remote" |
yearsExperienceMin / yearsExperienceMax | 3 / 7 |
postedAt | "2026-01-01T00:00:00Z" |
companyName | "Sample Company" |
companyUrl / companyLogoUrl | "https://wellfound.com/company/sample-company" / logo image URL |
companySize | "SIZE_51_200" |
companyHighConcept | "Sample company summary" |
allBadgeLabels | ["Actively Hiring", "Top Investors"] |
activelyHiring / hasTopInvestors | true / true |
quickResponder / topResponder | false / false |
sourceUrl / sourceLabel | "https://wellfound.com/location/san-francisco" / "san-francisco" |
scrapedAt | "2026-01-01T00:00:00Z" |
A few secondary fields ride along too: jobSlug and companySlug (the URL slugs behind jobUrl/companyUrl), descriptionLength (character count of descriptionText), companyId, and autoPosted/atsSource (whether and through which applicant-tracking system a listing was auto-posted, when Wellfound tags one). Note that compensationCurrency currently recognizes only the U.S. dollar sign; postings priced in another currency leave it blank even though compensation still holds the original text. remote is true for any listing with a remote arrangement, including hybrid or flexible ones that merely carry remote configuration data; check remoteKind for the exact arrangement.
How to Use
- Pick a mode:
search(build pages from Wellfound location slugs) orurl(paste Wellfound/jobsor/location/...links). - Fill in locations or URLs for that mode, and switch on any keyword, role, remote, compensation or hiring-badge filters you need.
- Set Max items (and optionally Max pages) to control run size and cost, then click Start.
- Download the dataset as JSON, CSV or Excel, or read it through the API.
Search one location:
{"mode": "search","locations": ["san-francisco"],"maxItems": 20}
Search multiple locations with filters:
{"mode": "search","locations": ["san-francisco", "new-york"],"keywords": ["python", "platform"],"roleKeywords": ["engineer"],"requireCompensation": true,"maxItems": 25}
Paste Wellfound URLs, remote jobs only:
{"mode": "url","startUrls": [{ "url": "https://wellfound.com/location/san-francisco" },{ "url": "https://wellfound.com/jobs" }],"remoteOnly": true,"maxItems": 10}
Daily monitoring with full expiry tracking:
{"mode": "search","locations": ["san-francisco"],"incrementalMode": true,"emitExpired": true,"maxItems": 100000,"maxPages": 0}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/wellfound-jobs-scraper").call(run_input={"mode": "search", "locations": ["san-francisco"]})for job in client.dataset(run["defaultDatasetId"]).iterate_items():print(job["jobTitle"], job["companyName"], job["compensation"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/wellfound-jobs-scraper').call({ mode: 'search', locations: ['san-francisco'] });const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
How Max items is split across locations and URLs
Max items is a cap, not a guaranteed count: a run can return fewer rows when the selected locations, URLs, keywords and filters match fewer current jobs. When a run has more than one location or URL source, the remaining budget is divided roughly evenly across the sources still to be read, in order, so an early source cannot use up the whole cap before later ones are tried. Max pages limits how many result pages are read per source; leave it empty or 0 to walk every page a source has, since Max items is the primary control on run size.
Resume and recurring updates
- Resume (
resumeFromRunId) continues one interrupted run: paste its run or dataset ID and the actor skips every job it already collected there (matched byjobId), so you don't pay twice. A bad or unreadable ID fails the run immediately, before any new scraping starts. - Incremental mode (
incrementalMode) is for a schedule over the same search. The first run returns everything asNEW. Later runs classify each job asNEW,UPDATED(withchangedFields),UNCHANGED(suppressed and not billed unlessemitUnchangedis on),REAPPEARED, or leave the previous state untouched.REAPPEAREDis not something that "happens by default": a job can only be classifiedREAPPEAREDonce a prior run marked it absent, which only happens when that prior run hademitExpiredon and completed a full, uncapped, non-resumed scan of the tracked search (that run normally also emits anEXPIREDrow for the job, though a Resume-seeded placeholder can be marked absent without one). Until that has happened once, no job in that campaign can ever come back asREAPPEARED.stateKeynames or shares the stored state; leaving it empty derives one automatically from mode, locations, URLs, keywords and filters, so different searches never mix state. With Incremental mode off, output is exactly as before, with no extra fields. resumeFromRunIdandincrementalModeare different tools: use Resume after one run was cut off, and Incremental mode for a schedule that runs the same search again and again. Combining them only works to bootstrap a brand-new monitoring campaign from a prior plain run; if that campaign already has saved state, the run fails rather than silently mixing the two.
Send results into your apps (MCP connectors)
Optionally pipe the scraped jobs into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.
What gets written to the connector: a condensed, human-readable summary of each job, not the full JSON. Each job becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset, and a connector write error never fails the run.
- Authorize a connector once under Apify → Settings → Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto the page where job entries should be created. - Use Max jobs to export per connector to cap how many of this run's jobs are sent, separately from the dataset itself.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search for Wellfound location pages, or url for pasted Wellfound links. |
locations | array | no default (prefill: ["san-francisco"]) | Wellfound location slugs or names for search mode. |
startUrls | array | no default (prefill: sample /location/... and /jobs URLs) | Wellfound /jobs or /location/... URLs for URL mode. |
keywords | array | no default (prefill: ["python"]) | Keeps rows where at least one term appears in the job, company, role, location, badge, compensation or description text. |
roleKeywords | array | no default | Keeps rows where at least one term appears in the job title or primary role. |
remoteOnly | boolean | false | Keeps only jobs marked remote or carrying remote configuration data. |
requireCompensation | boolean | false | Keeps only jobs with a compensation value. |
activelyHiringOnly | boolean | false | Keeps only jobs whose company carries an actively-hiring badge. |
maxItems | integer | 20 | Maximum matching rows to save (1 to 100000). Runs can return fewer rows when filters match fewer current jobs. |
maxPages | integer | 0 | Maximum pages to read per location or URL source. 0 walks every result page; maxItems is the primary output cap. |
resumeFromRunId | string | no default (empty) | A previous run ID (or dataset ID) from this actor. Jobs already collected there (matched by jobId) are skipped. |
incrementalMode | boolean | false | Daily/recurring monitoring of the same search. See "Resume and recurring updates" above. |
stateKey | string | no default (empty) | Optional name for a monitoring campaign; auto-derived from mode/locations/URLs/keywords/filters when left empty. |
emitUnchanged | boolean | false | Incremental mode only. Also return (and bill) jobs unchanged since the last run, marked UNCHANGED. |
emitExpired | boolean | false | Incremental mode only. Also return (and bill) jobs no longer found, marked EXPIRED, once a run has fully scanned the search. |
proxy | object | Apify Proxy Residential | Connection settings. The default is recommended for Wellfound. |
mcpConnectors | array | no default (empty) | Optional connector IDs for sending a job summary into your apps. |
notionParentPageUrl | string | no default (empty) | Required only to enable the Notion export. |
maxNotifyListings | integer | 50 | Maximum jobs sent to each selected connector per run. Does not affect the dataset. |
Output Example
Sample shape: values are illustrative placeholders, not from a live listing.
{"jobId": "00000001","jobUrl": "https://wellfound.com/jobs/00000001-sample-platform-engineer","jobSlug": "sample-platform-engineer","jobTitle": "Sample Platform Engineer","descriptionText": "Full role description text appears here.","descriptionLength": 40,"jobType": "full-time","primaryRoleTitle": "Software Engineer","compensation": "$100k - $150k","compensationMin": 100000,"compensationMax": 150000,"compensationCurrency": "$","hasCompensation": true,"hasEquity": false,"locations": ["San Francisco"],"acceptedRemoteLocations": ["United States"],"remote": true,"remoteKind": "remote","yearsExperienceMin": 3,"yearsExperienceMax": 7,"postedAtUnix": 1767225600,"postedAt": "2026-01-01T00:00:00Z","companyId": "00000001","companyName": "Sample Company","companySlug": "sample-company","companyUrl": "https://wellfound.com/company/sample-company","companyLogoUrl": "https://photos.wellfound.com/startups/i/00000001-medium_jpg.jpg","companySize": "SIZE_51_200","companyHighConcept": "Sample company summary","allBadgeLabels": ["Actively Hiring", "Top Investors"],"activelyHiring": true,"hasTopInvestors": true,"quickResponder": false,"topResponder": false,"sourceUrl": "https://wellfound.com/location/san-francisco","sourceLabel": "san-francisco","scrapedAt": "2026-01-01T00:00:00Z"}
Plan Requirement
Keep the default Apify Residential proxy setting for the most reliable results on Wellfound. Max items is a maximum cap, not a guaranteed count: a run can save fewer rows when the selected location, URL, keyword and filter combination matches fewer active jobs.
FAQ
How much does it cost?
You pay a small one-time run start fee plus a per-row price for every job saved to the dataset. The Pricing tab shows the current rates. Use Max items to cap the cost of any run, and leave emitUnchanged/emitExpired off unless you specifically want those extra rows returned and billed.
Is it legal to scrape Wellfound?
This actor collects only publicly available job listing data. You are responsible for how you use it: follow Wellfound's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution.
Can I get only new or changed jobs on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new, updated and (once eligible) reappeared jobs, and unchanged ones are not billed unless you turn emitUnchanged on.
What's the difference between Resume and Incremental mode?
Resume (resumeFromRunId) continues one specific interrupted run from a pasted ID; it is a one-time delta against that one dataset. Incremental mode remembers state itself and is for running the exact same search again and again on a schedule. Use Resume after a run was cut off; use Incremental mode for recurring monitoring. Mixing the two only works to bootstrap a brand-new monitoring campaign; if that state key already has saved history, the run fails rather than guessing which one you meant.
Why did my run fail instead of returning an empty dataset?
If every request to Wellfound was refused, the run stops with a clear message so "no jobs matched" is never confused with "nothing could be read." Retry in a few minutes, ideally with the default Residential proxy. A genuinely empty search, where Wellfound answered normally but nothing matched your location, URL or filters, still succeeds and reports the reason through the run status, without billing a placeholder row.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push job summaries into Notion, Linear or Airtable.
🔗 Want more jobs data?
Pair this actor with these related scrapers from the same team:
| 💼 CareerBuilder Scraper Scrape CareerBuilder.com job listings by search or URL. Returns title, company profile... | 💼 RemoteOK Jobs Scraper Scrape RemoteOK jobs by keyword or job URL. Extract title, company, location, remote... |
| 💼 Jora Jobs Scraper Scrape Jora.com job listings across supported countries by keyword, filters, or URL... | 💼 Monster Jobs Scraper Scrape Monster.com job listings from search and direct job URLs. Extract full... |
| 🏨 Caterer.com Scraper Scrape UK hospitality jobs from Caterer.com, including chef, hotel, restaurant, bar, and... | 💼 We Work Remotely Scraper Extract current remote job listings from weworkremotely.com. Use keyword search or WWR... |
💬 Support
- 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- 🛠️ Need another site, extra fields or a private build? Email contact@abotapi.com.
- ⭐ Enjoying it? A quick review on the actor page helps other users find it.