# Wellfound Job Posting Scraper — Salary & Benefits (`thenetaji/wellfound-job-posting-scraper`) Actor

Turn Wellfound job links into structured rows: the salary range as numbers with the period it covers, employment type, whether you apply on Wellfound or the company's own system, where applications are accepted from, the company website, its industries, benefits and the posting body.

- **URL**: https://apify.com/thenetaji/wellfound-job-posting-scraper.md
- **Developed by:** [The Netaji](https://apify.com/thenetaji) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.40 / 1,000 postings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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 Job Posting Scraper

Turn a list of Wellfound job links into structured rows. Each link returns the salary range as
numbers with the period it is quoted over, the employment type, whether the application is
completed on Wellfound or handed to the company's own system, where applicants may be based, the
company's website, the industries it works in, the benefits it advertises and the full posting
body as published HTML.

This is the Actor for links that already exist — in a spreadsheet, a job feed, a competitor's
board — rather than for finding them. Discovery is the
[Wellfound Jobs Scraper](https://apify.com/thenetaji/wellfound-jobs-scraper)'s job.

### Accepted input

```json
{
  "jobUrls": [
    "https://wellfound.com/jobs/4579450-software-engineer",
    "4521165-staff-software-engineer-ai"
  ]
}
```

A full URL or the `id-slug` tail on its own; both forms may be mixed in one list. The id and the
slug are both part of the address and both are required — see the first question below. A link
listed twice is read once.

### What a row looks like

```json
{
  "job_id": "4579450",
  "title": "Software Engineer",
  "slug": "software-engineer",
  "url": "https://wellfound.com/jobs/4579450-software-engineer",
  "company_name": "Oklo",
  "company_website": "https://www.oklo.com",
  "company_logo_url": "https://photos.wellfound.com/startups/i/5268250-…-medium_jpg.jpg",
  "posted_at": "2026-08-12T16:29:14.000Z",
  "salary_min": 110000,
  "salary_max": 155000,
  "salary_currency": "USD",
  "salary_period": "YEAR",
  "employment_type": "FULL_TIME",
  "job_location_type": "TELECOMMUTE",
  "direct_apply": true,
  "locations": ["Santa Clara, California, United States"],
  "applicant_locations": ["United States"],
  "industry": "Clean Energy, Renewable Energies, Renewable Tech, and Nuclear Energy",
  "benefits": "Healthcare benefits - We cover 99% of benefits - medical, dental, and vision…",
  "description_html": "<p>Join us in pioneering the next generation of nuclear reactors!…</p>"
}
```

Every field is null when the posting does not state it, rather than being omitted or filled with a
zero. `salary_period` is worth reading before the numbers are used: a range quoted `HOUR` and one
quoted `YEAR` are not comparable, and the period is the only thing that says which is which.

### Questions

**Why is the numeric id on its own not enough?**
Because Wellfound resolves a posting on the whole `id-slug` address. On 16 August 2026 three ids
taken straight out of a search were requested without their slug, and again with a wrong one, and
all six came back as the same empty response a deleted posting returns. Since an id-only request
cannot succeed, an entry without its slug is reported and dropped before it costs anything rather
than being sent and billed. Every row the jobs scraper produces carries `url` and `slug`, which is
where the pairs come from.

**A link returned no row. Was it an error?**
No. A posting that has been taken down — the role was filled, the company withdrew it — answers
exactly like a link that never existed, so from outside those are one outcome. The run logs the
link that produced nothing, carries on with the rest of the list, and nothing is charged for it.
Losing nineteen good rows to one closed posting would be the wrong trade.

**What does this add over the search rows?**
The pay as numbers with a period attached, `employment_type`, `direct_apply`,
`job_location_type`, `applicant_locations`, the company's own website, `industry`, `benefits` and
the posting body as HTML. The search row already carries the description as plain text, the pay as
a display string, the locations and the experience band, so a run here is worth it for the
structured pay and the company website rather than for the text.

**`locations` is empty on some postings. Is that missing data?**
It is meaningful rather than missing: a fully remote posting states no place, and those rows carry
`job_location_type: "TELECOMMUTE"` instead. `applicant_locations` is the separate question of
where a hire may sit, and it is stated independently — a role anchored in one city that will take
applicants anywhere in a country fills in both.

**Why is `description_html` markup rather than text?**
Because that is how the posting is published, and stripping it would throw away the headings and
lists that make a long posting readable. The plain-text version of the same body is on every row
of the [Wellfound Jobs Scraper](https://apify.com/thenetaji/wellfound-jobs-scraper), so a pipeline
that wants text without parsing HTML should read it there.

**Can several hundred links be run at once?**
Yes — the list is walked in order, one request per link, and each row is charged individually.
There is no page limit and no cursor to manage, so the practical bound is how long the run may
take rather than a cap in the Actor.

### Related Actors

[Wellfound Jobs Scraper](https://apify.com/thenetaji/wellfound-jobs-scraper) searches by role and
city and can attach everything above to each result in the same run, which is cheaper than
exporting a search and re-reading it here.

[Wellfound Company Scraper](https://apify.com/thenetaji/wellfound-company-scraper) takes the
company behind a posting and returns its funding, team, perks and other open roles.

# Actor input Schema

## `jobUrls` (type: `array`):

Wellfound job URLs, one per line: `https://wellfound.com/jobs/3061448-senior-software-engineer`. The `3061448-senior-software-engineer` part on its own is accepted too.

Both halves are needed. The numeric id alone does not resolve a posting — the site answers it with the same empty response it gives a posting that has been taken down — so an entry without its slug is reported and skipped before it costs a request. Every row the job search returns carries the URL in the form this field takes.

## Actor input object example

```json
{
  "jobUrls": [
    "https://wellfound.com/jobs/3061448-senior-software-engineer"
  ]
}
```

# Actor output Schema

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

All records scraped by this run

# 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 = {
    "jobUrls": [
        "https://wellfound.com/jobs/3061448-senior-software-engineer"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("thenetaji/wellfound-job-posting-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 = { "jobUrls": ["https://wellfound.com/jobs/3061448-senior-software-engineer"] }

# Run the Actor and wait for it to finish
run = client.actor("thenetaji/wellfound-job-posting-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 '{
  "jobUrls": [
    "https://wellfound.com/jobs/3061448-senior-software-engineer"
  ]
}' |
apify call thenetaji/wellfound-job-posting-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,thenetaji/wellfound-job-posting-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/aZtN8K2gbAiyFtHbm/builds/VZfKvFLSuFKM1bpnI/openapi.json
