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

Scrape Lenny's Jobs for tech roles, companies, locations, experience levels, posting dates, company stages, valuations, technologies, and application links.

- **URL**: https://apify.com/scraper\_guru/lennys-jobs-scraper.md
- **Developed by:** [LIAICHI MUSTAPHA](https://apify.com/scraper_guru) (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 $3.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

<p align="center">
  <img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/FLeKbYIKjUnkcAaFx-actor-LhiKIPuxUDkzjKW94-5GqpWQ5GNw-lennys-jobs-scraper-logo.png" alt="Lenny's Jobs Scraper logo" width="180">
</p>

<p align="center"><strong>Structured technology job data, ready for search, analysis, and automation.</strong></p>

Extract structured technology job listings from [Lenny's Jobs](https://www.lennysjobs.com/). Filter by keywords, location, job category, experience level, and posting date, then export the results as JSON, CSV, Excel, XML, or RSS through Apify.

### Features

- Extracts job titles, companies, locations, remote status, and application links
- Captures job categories, experience levels, employment types, and posting dates when available
- Includes company stage, valuation, salary range, investors, technologies, and descriptions from public page data
- Supports keyword, location, category, level, and date filters
- Removes duplicate listings automatically
- Saves run diagnostics to the key-value store for monitoring
- Uses browser rendering for the JavaScript-driven job feed

### Use Cases

- Monitor new product, engineering, design, growth, and AI roles
- Build curated startup and technology job alerts
- Research hiring demand across company stages and locations
- Track remote-work and seniority trends
- Enrich recruiting, talent intelligence, and labor-market datasets
- Feed job data into n8n, Make, Zapier, Airtable, or a data warehouse

### Input

The default input collects up to 25 recent jobs. The Store prefill uses 10 jobs and two loading rounds so Apify's automated quality test can finish quickly.

```json
{
  "keywords": ["product manager", "AI"],
  "locations": ["Remote", "United States"],
  "categories": ["Product"],
  "levels": ["Senior"],
  "postedWithinDays": 30,
  "maxItems": 100,
  "scrollRounds": 8,
  "includeDescription": true
}
```

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `keywords` | string\[] | `[]` | Match the title, company, category, description, or technologies |
| `locations` | string\[] | `[]` | Match locations or remote status |
| `categories` | string\[] | `[]` | Match job categories |
| `levels` | string\[] | `[]` | Match experience levels |
| `postedWithinDays` | integer | `30` | Keep recent jobs; use `0` to disable |
| `maxItems` | integer | `25` | Maximum number of saved jobs |
| `scrollRounds` | integer | `4` | Number of feed-loading scrolls |
| `includeDescription` | boolean | `true` | Include descriptions when available |
| `proxyConfiguration` | object | direct | Optional Apify Proxy settings |
| `failOnEmpty` | boolean | `false` | Fail empty runs for monitoring workflows |

### Output

Each dataset item follows a stable normalized structure. Fields unavailable in the source are returned as `null` or an empty array.

```json
{
  "job_title": "Senior Product Manager",
  "company_name": "Example AI",
  "location": "San Francisco, CA / Remote",
  "remote_status": "Remote",
  "employment_type": "Full-time",
  "experience_level": "Senior",
  "job_category": "Product",
  "date_posted": "2026-08-20T10:00:00.000Z",
  "company_stage": "Series B",
  "company_valuation": "$1B",
  "company_industry": "Enterprise AI",
  "salary_min": 180000,
  "salary_max": 230000,
  "investors": ["Example Ventures"],
  "technologies": ["SQL", "Python"],
  "description": "Build AI-powered products for enterprise teams...",
  "job_url": "https://www.lennysjobs.com/jobs/example-ai/senior-product-manager",
  "company_url": "https://example.ai/",
  "source": "Lenny's Jobs",
  "scraped_at": "2026-08-21T12:00:00.000Z"
}
```

### How to Use

1. Open the Actor in Apify Console.
2. Add optional filters or keep the prefilled defaults.
3. Click **Start**.
4. Open the **Dataset** tab to preview or download the jobs.
5. Use the API, schedules, or integrations to automate recurring collection.

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("USERNAME/lennys-jobs-scraper").call(run_input={
    "keywords": ["product manager", "AI"],
    "locations": ["Remote"],
    "maxItems": 100,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["job_title"], item["company_name"], item["job_url"])
```

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('USERNAME/lennys-jobs-scraper').call({
    keywords: ['product manager', 'AI'],
    locations: ['Remote'],
    maxItems: 100,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Integrations

Send the dataset to Google Sheets, Slack, webhooks, Make, Zapier, or your own API. For recurring alerts, create an Apify Task with saved filters and attach a schedule or webhook.

### Pricing

Your run cost depends mainly on browser runtime and memory usage. Start with a small `maxItems` value, then increase `maxItems` and `scrollRounds` only when you need broader coverage. Apify displays the exact platform cost for every run.

### Limitations

- The Actor extracts public data available on Lenny's Jobs; field availability varies by listing.
- The source is JavaScript-driven and may occasionally be unavailable.
- Filters are applied to the jobs loaded during the run, not to every job in the source database.
- Website changes can require updates to field aliases or extraction fallbacks.

### FAQ

#### Does this Actor require a login?

No. It reads public job listings and does not use account credentials.

#### Can I collect only remote roles?

Yes. Add `Remote` to `locations`.

#### Can I monitor newly posted jobs?

Yes. Save the input as an Apify Task, set `postedWithinDays` to a small value, and run it on a schedule.

#### Why are some fields null?

Not every listing exposes salary, company funding, valuation, technologies, employment type, or a description.

#### What happens when no jobs match?

The default run succeeds and writes the reason to `STATS`. Set `failOnEmpty` to `true` when an empty result should trigger monitoring alerts.

#### Is this Actor affiliated with Lenny's Jobs, Lenny Rachitsky, or TrueUp?

No. This is an independent data-extraction tool for public information.

### Responsible Use

Use the Actor in accordance with applicable laws, the source website's terms, and privacy requirements. Avoid excessive run frequency and do not use the data for spam or discriminatory employment decisions.

# Actor input Schema

## `keywords` (type: `array`):

Keep jobs whose title, company, category, description, or technologies contain at least one keyword.

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

Keep jobs matching at least one location. Use Remote to include remote roles.

## `categories` (type: `array`):

Optional job categories such as Product, Engineering, Design, Marketing, or Sales.

## `levels` (type: `array`):

Optional experience levels such as Entry, Mid, Senior, Lead, Manager, or Executive.

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

Keep jobs posted within this many days. Set to 0 to disable the date filter.

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

Maximum number of jobs saved to the dataset.

## `scrollRounds` (type: `integer`):

How many times to scroll the job feed to load more results.

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

Include descriptions when they are present in the public page data.

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

Optional proxy settings. Direct access is used by default.

## `failOnEmpty` (type: `boolean`):

Stop the run with an error if extraction returns no matching jobs. Useful for monitoring scheduled runs.

## Actor input object example

```json
{
  "keywords": [],
  "locations": [],
  "categories": [],
  "levels": [],
  "postedWithinDays": 30,
  "maxItems": 10,
  "scrollRounds": 2,
  "includeDescription": true,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "failOnEmpty": false
}
```

# Actor output Schema

## `jobs` (type: `string`):

The dataset containing extracted and normalized job records.

## `runStats` (type: `string`):

Extraction counts, active filters, and diagnostic warnings.

# 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 = {
    "postedWithinDays": 30,
    "maxItems": 10,
    "scrollRounds": 2,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scraper_guru/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 = {
    "postedWithinDays": 30,
    "maxItems": 10,
    "scrollRounds": 2,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("scraper_guru/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 '{
  "postedWithinDays": 30,
  "maxItems": 10,
  "scrollRounds": 2,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call scraper_guru/lennys-jobs-scraper --silent --output-dataset

```

## MCP server setup

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