# Lenny's Jobs Scraper (`sashaebashu/lennys-jobs-scraper`) Actor

Read Lenny's Jobs: product, growth, engineering and design roles with the salary band where one is published, plus what is known about the company — stage, valuation, total funding, last raise, headcount and how many other roles it has open.

- **URL**: https://apify.com/sashaebashu/lennys-jobs-scraper.md
- **Developed by:** [Sasha Ebashu](https://apify.com/sashaebashu) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 results

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?

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

## Lenny's Jobs Scraper — Roles, Salaries & Company Funding

Lenny's Jobs is where product, growth, engineering and design people look for work. This Actor
reads it: the role, the company and what it does, the location, the salary band where one is
published, and what is known about the employer — stage, valuation, total funding, last raise,
headcount, age, and how many other roles it has open.

### It gets past the board's 50-job ceiling

The board hands an anonymous visitor **50 jobs per query and then removes the "Show more" button
entirely**, however large a total it advertises. Measured: 30 → 45 → 50 → button gone, against a
counter reading "7,000+". Any scraper that asks one question gets 50 jobs and stops there.

Changing a filter starts a fresh query and brings the button back. So this Actor asks many narrower
questions instead of one broad one — every category and sub-category the board offers, 41 of them —
and merges the answers by apply link.

**Measured: 1,000 jobs from 474 companies in under seven minutes, with zero duplicates.** It stopped
because it had collected what was asked for, not because the board ran out: only 23 of the 41 slices
were needed.

| Asked for | Collected | Companies | Time |
|---|---|---|---|
| 50 | 50 | 47 | 28 s |
| 400 | 400 | 246 | 3 min 34 |
| 1,000 | 1,000 | 474 | 6 min 53 |

### It does not lose a third of the board

Job cards are found by their apply link, not by a list of known applicant-tracking systems. That
distinction matters more than it sounds: matching Greenhouse, Lever, Ashby and Workday misses every
employer that hosts its own careers page — **Meta, Microsoft, TikTok, Databricks, Roku, Fivetran** —
which is 22 of every 50 jobs in the sample. Counted against the "Am I a fit?" buttons the page
renders, this finds 30 of 30.

### What you get per job

| | |
|---|---|
| **Role** | Title, location, when it was posted as both text and a date, technologies mentioned |
| **Pay** | The band as written, plus `salaryMin` and `salaryMax` as plain numbers |
| **Apply** | The employer's own application link, not a redirect through the board |
| **Company** | Name, what it does, stage, valuation, total funding, last raise, headcount, age, trajectory score, and how many other roles it has open |

### Notes & limits

Properties of the source, measured rather than assumed:

- **A salary band is published on roughly 30% of postings**, a company stage on 40% and a valuation
  on 56%. Those are facts about the board, not gaps in the reading — the fields are simply absent on
  the rest, and are left empty rather than guessed.
- **The board is behind Cloudflare, which serves a bot check to Apify's own machines.** Through the
  proxy the same page loads normally, and the cheap datacenter group is enough — residential is not
  needed. The proxy is therefore on by default; without it the run cannot start.
- **Filters are not in the URL.** The page keeps its state in memory and the address bar never
  changes, so there is no link that encodes a filtered view and every filter is a click.
- **Date ranges are not a useful slice.** They nest inside one another: a "past week" query returned
  15 results of which 14 were already in the unfiltered 50. Categories and sub-categories partition
  the board; dates do not, so they are not swept.
- **The board's technology box does not filter anything.** Typing into it — programmatically or key
  by key — left the count at 7,000+, while the same code path took the title search from 7,000+ down
  to 37. It is therefore not offered as an input; the technologies named in each posting come back in
  `techTags` so you can filter on them yourself.
- **Sub-categories are where the volume is.** Engineering alone breaks into Backend, Full-Stack, AI,
  Data, Platform, Security, QA, DevOps, Site Reliability, Mobile, Front-End and more, each with its
  own ceiling of 50.
- Posting age is given as the board writes it (`10 days`) and as a timestamp derived from it, so
  rows can be sorted and compared rather than read. The derived date is only as precise as the
  original — "1 month" is a month, not a day.
- The Actor honours your **Maximum cost per run** and stops when the cap is reached.

### Input

| Field | What it does |
|---|---|
| **Search** | The board’s own search box, by job title or company. |
| **Job category** | Pin a single category, spelled as the board spells it. Leave empty to sweep them all. |
| **Sweep every category** | On by default. This is what gets past 50; switch it off for a single quick query. |
| **Posted within** | Any time, past month, past week, past 3 days. |
| **Only the Lenny 100 / Only posted by Lenny's community** | The board's two curation switches. It opens with the Lenny 100 filter **on**, which cuts thousands of jobs to a few dozen — this Actor switches it off unless you ask for it. |
| **Maximum jobs** | How many to collect. This, not the board, is what stops the run. |

# Actor input Schema

## `searchQuery` (type: `string`):

Job title or company, exactly as you would type it into the board's search box — `Group Product Manager`, `Stripe`.

## `jobCategory` (type: `string`):

One of the categories the board offers, spelled as it appears there: `Product Management`, `Marketing & Growth`, `Engineering (Software)`, `Design (Product)`. Leave empty for every category.

## `datePosted` (type: `string`):

How recent the postings must be.

## `lenny100Only` (type: `boolean`):

Restrict to the curated Lenny 100 companies. The board switches this on by default and it cuts thousands of jobs down to a few dozen — this Actor switches it off unless you ask for it.

## `communityOnly` (type: `boolean`):

Restrict to roles posted by members of Lenny's community rather than pulled from company career pages.

## `maxJobs` (type: `integer`):

How many jobs to collect. The board loads them in batches of roughly fifteen, so a larger number means more clicks and a longer run.

## `sweepCategories` (type: `boolean`):

The board serves an anonymous visitor 50 jobs per query and then hides the button, whatever total it advertises. With this on, the Actor asks the same question once per category and merges the answers, which is the only way past that ceiling. Ignored when you pin a single category.

## `proxyConfiguration` (type: `object`):

Left on, and it has to be: the board is behind Cloudflare, which serves a bot check to Apify's own machines. Routed through the proxy the same page loads fine, and the cheap datacenter group is enough — no residential needed.

## Actor input object example

```json
{
  "searchQuery": "",
  "jobCategory": "",
  "datePosted": "all",
  "lenny100Only": false,
  "communityOnly": false,
  "maxJobs": 100,
  "sweepCategories": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `pay` (type: `string`):

No description

## `companies` (type: `string`):

No description

## `full` (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("sashaebashu/lennys-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("sashaebashu/lennys-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 sashaebashu/lennys-jobs-scraper --silent --output-dataset

```

## MCP server setup

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