# Wellfound Jobs Scraper (`cliqtomedia/wellfound-jobs-scraper`) Actor

Wellfound Jobs Scraper extracts public Wellfound job listings with stable IDs, useful filters and clear run diagnostics. Independent project with no login or access-control bypass.

- **URL**: https://apify.com/cliqtomedia/wellfound-jobs-scraper.md
- **Developed by:** [Cliqto Media](https://apify.com/cliqtomedia) (community)
- **Categories:** Jobs, Developer tools
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.25 / 1,000 wellfound 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?

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

Extract public Wellfound job listings into a clean Apify Dataset. Each saved
listing has a stable numeric job ID, a canonical Wellfound job URL and
source-backed fields such as company, location, remote status, compensation,
posting date and description when those values are published on the page.

This is an independent project. It is not affiliated with, endorsed by or
sponsored by Wellfound or AngelList.

### What it does

- Reads public Wellfound jobs, role, location and exact-job pages.
- Accepts a public URL directly or builds search URLs from role and location
  slugs.
- Keeps one Dataset row per unique numeric Wellfound job ID.
- Supports keyword, remote-only, employment-type and posting-age filters over
  fetched public fields.
- Preserves canonical job URLs and the URL family used for the extraction.
- Writes a run summary, diagnostics and progress record to the Key-Value Store,
  including useful empty, partial, blocked and not-found outcomes.

### What it does not do

The Actor does not use a Wellfound account or private session. It does not
collect candidate, profile, contact or application data; fetch external ATS or
company pages; solve CAPTCHAs; bypass access controls; or promise a global,
complete or permanently fresh Wellfound index. Coverage is limited to the
public pages fetched in the run and is labelled `public_page_subset`.

### Input

The default input reads the public `https://wellfound.com/jobs` feed. A useful
role-and-location prefill is:

```json
{
  "startUrls": [
    { "url": "https://wellfound.com/role/l/software-engineer/new-york" }
  ],
  "maxItems": 50,
  "maxPagesPerSeed": 3,
  "maxRequests": 200,
  "includeDescription": true
}
```

Use `startUrls` for public search or exact-job URLs. `roles` and `locations`
are convenience fields; leave `startUrls` empty when using them. With no
explicit URL, role or location, the bounded `/jobs` feed is used. `query`, `remoteOnly`, `jobType` and
`postedWithinDays` are filters over the pages fetched for the run.
`includeDescription` is enabled by default: when a listing page has no inline
description, the Actor makes one bounded exact-job request for that candidate.
This is especially important for the public `/jobs` feed, whose structured
listing state carries the job/company fields but not the full description. Set
it to `false` for link-first output. Detail requests remain inside
`maxItems`/`maxRequests`.

The safety and resource controls are deliberately explicit:

- `maxItems`: 1–1,000 requested Dataset rows;
- `maxPagesPerSeed`: 1–50 pages per URL;
- `maxRequests`: 1–1,500 request attempts for the run;
- `requestTimeoutSecs`: 5–60 seconds per attempt;
- `requestDelayMs`: 500–10,000 milliseconds between request starts;
- `maxRetries`: 0–2 temporary-error retries.

The source or filters can produce fewer rows than any requested maximum.
`AUTO` and `DIRECT` use the supported direct HTTPS connection path.

### Output

Dataset rows include:

- stable `id` (`wellfound:<numeric-id>`) and `jobId`;
- `title`, `jobUrl`, company fields and role/type fields;
- `locations`, accepted remote locations and explicit remote signals;
- published compensation text and parsed salary/equity values when unambiguous;
- posting timestamp, public description, ATS label and badges when available;
- `sourceUrl`, `sourceMode`, `sourcePage`, `observedAt` and `coverage`.

Unavailable source fields remain `null` or `[]`; they are not guessed. The
Dataset contains job rows only. The Key-Value Store contains:

- `RUN_SUMMARY` — final product status, counts, limits, transport and timing;
- `RUN_DIAGNOSTICS` — machine-readable source or input diagnostics;
- `RUN_PROGRESS` — the latest progress snapshot.

See [the input and output specification](docs/SPEC.md), [the Dataset output
contract](docs/OUTPUT-CONTRACT.md) and [the support guide](docs/publication/SUPPORT.md).

#### Example row

This example uses placeholder values. A real row keeps the same fields and
records only values published by Wellfound.

```json
{
  "recordType": "JOB_LISTING",
  "id": "wellfound:1234567",
  "jobId": "1234567",
  "title": "Senior Software Engineer",
  "jobUrl": "https://wellfound.com/jobs/1234567-senior-software-engineer",
  "companyName": "Example Labs",
  "primaryRole": "Software Engineer",
  "jobType": "full-time",
  "locations": ["New York City"],
  "remote": false,
  "compensationText": "$140k – $180k",
  "salaryMin": 140000,
  "salaryMax": 180000,
  "salaryCurrency": "USD",
  "postedAt": "2026-09-13T00:00:00.000Z",
  "description": "Example public job description.",
  "sourceMode": "search",
  "coverage": "public_page_subset"
}
```

### Pricing

The Actor charges $0.00025 for each saved job listing. That is $0.25 per 1,000
saved rows. Empty, filtered, duplicate, diagnostic, blocked, invalid and failed
outcomes do not create a result charge.

### Source and safe use

The Actor reads public Wellfound pages with limited HTTPS requests. Do not use
it with private credentials, private sessions or data you are not allowed to
access. Review the current [Wellfound site](https://wellfound.com/) Terms and
applicable law before using extracted data. This project does not grant any
permission to republish source data.

# Changelog

This Actor's version history is a separate document: https://apify.com/cliqtomedia/wellfound-jobs-scraper/changelog.md

# Actor input Schema

## `mode` (type: `string`):

Detects the route automatically. A company-jobs challenge is reported as a terminal source result.

## `startUrls` (type: `array`):

Optional public HTTPS Wellfound search, company-jobs or exact-job URLs. Leave empty to use the bounded public /jobs feed; roles and locations build their own search URLs.

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

Role slugs such as software-engineer. Combine with locations to build a public search URL.

## `locations` (type: `array`):

Location slugs such as new-york.

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

Keep only rows with an explicit public remote signal. Unknown remote status is not included.

## `query` (type: `string`):

Match fetched title, company, role and verified description text. This is a local filter over fetched pages.

## `jobType` (type: `string`):

Filter fetched rows by employment type; any keeps all observed types.

## `postedWithinDays` (type: `integer`):

Keep rows posted within this many days when the source provides an exact timestamp.

## `includeDescription` (type: `boolean`):

Fetches one bounded exact job page when a listing page has no inline description; disable for link-first output.

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

Maximum valid rows to write. The source or filters may return fewer rows.

## `maxPagesPerSeed` (type: `integer`):

Maximum number of pages to read for each URL. The source may end earlier.

## `maxRequests` (type: `integer`):

Hard run-wide request budget, including redirects, retries and optional detail requests.

## `requestTimeoutSecs` (type: `integer`):

Timeout for each direct HTTPS request attempt.

## `requestDelayMs` (type: `integer`):

Minimum delay between direct source requests. A source retry delay may extend it.

## `maxRetries` (type: `integer`):

Retries temporary timeouts, connection errors, rate limits and 5xx responses.

## `transport` (type: `string`):

AUTO and DIRECT use the supported direct HTTPS path. Proxy transports are not available.

## Actor input object example

```json
{
  "mode": "auto",
  "startUrls": [],
  "remoteOnly": false,
  "query": "",
  "jobType": "any",
  "includeDescription": true,
  "maxItems": 50,
  "maxPagesPerSeed": 3,
  "maxRequests": 200,
  "requestTimeoutSecs": 20,
  "requestDelayMs": 750,
  "maxRetries": 2,
  "transport": "AUTO"
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `runSummary` (type: `string`):

No description

## `runDiagnostics` (type: `string`):

No description

## `runProgress` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("cliqtomedia/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 = {}

# Run the Actor and wait for it to finish
run = client.actor("cliqtomedia/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 '{}' |
apify call cliqtomedia/wellfound-jobs-scraper --silent --output-dataset

```

## MCP server setup

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