# Advanced LinkedIn Jobs Scraper – Fast & Affordable (`practicaltools/linkedin-jobs`) Actor

The most affordable LinkedIn job scraper on Apify. Extract 1,000+ jobs in minutes, including full details (title, company, location, description, link). Pay-as-you-go, no cookies, no hassle.

- **URL**: https://apify.com/practicaltools/linkedin-jobs.md
- **Developed by:** [Practical Tools](https://apify.com/practicaltools) (community)
- **Categories:** Jobs, Automation, Lead generation
- **Stats:** 414 total users, 53 monthly users, 100.0% runs succeeded, 15 bookmarks
- **User rating**: 4.26 out of 5 stars

## Pricing

from $0.70 / 1,000 jobs

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

## LinkedIn Jobs Scraper – $1 per 1,000 Jobs. No Login. AI Search.

Extract LinkedIn job listings with pay-per-result pricing, optional full job descriptions, and AI-powered natural language search. No LinkedIn account required.

### 💰 Pricing

| Event | Cost |
|---|---|
| Job scraped | $0.001 (1,000 jobs = $1.00) |
| Job description fetched | $0.001 per description (optional) |

- No setup fees, no subscriptions, no per-run charges
- Zero results = zero charge
- Description fetching is opt-in — only pay for it if you enable it

***

### 📋 Output

Each job is a **separate dataset item** (one row per job). Download as JSON, CSV, or Excel from Apify.

**Standard fields** (always returned):

| Field | Description |
|---|---|
| `jobId` | LinkedIn's internal job posting ID |
| `title` | Job title |
| `company` | Company name |
| `location` | Job location |
| `datePosted` | Posting date |
| `url` | Direct link to the job posting |
| `labels` | Badges like "Easy Apply", "Actively Hiring" |
| `logo` | Company logo URL |
| `discoveredAt` | Timestamp when the job was scraped |
| `source` | Always `"linkedin"` |

**Optional field** (when `fetchDescription: true`):

| Field | Description |
|---|---|
| `description` | Full job description as plain text |

***

### 🚀 How to Use

#### Simple search

```json
{
  "keywords": "Product Manager",
  "location": "San Francisco Bay Area",
  "maxPages": 5
}
```

#### With job descriptions

```json
{
  "keywords": "Software Engineer",
  "location": "New York",
  "maxPages": 3,
  "fetchDescription": true
}
```

> **Note:** Enable `fetchDescription` when you need to filter by description content downstream. Each description costs one extra request and $0.001.

#### AI-powered natural language search

Describe your search in plain English instead of filling out individual fields:

```json
{
  "naturalLanguageQuery": "senior product manager at Google or Meta in San Francisco, remote, posted last week",
  "useNaturalLanguage": true,
  "openaiApiKey": "your-openai-api-key",
  "fetchDescription": true
}
```

More examples:

- `"software engineer jobs in New York, entry level, full time"`
- `"data scientist positions at startups, remote, from last week"`
- `"marketing manager roles in Chicago or Austin, hybrid"`

The AI (GPT-4-turbo) resolves company names to LinkedIn IDs, locations to geo IDs, and maps natural language filters to LinkedIn's search parameters. Falls back to regex parsing if the AI call fails.

#### Advanced filtering

```json
{
  "keywords": "Software Engineer",
  "location": "United States",
  "experienceLevel": ["3", "4"],
  "workLocation": ["2", "3"],
  "contractType": ["1"],
  "timePosted": "r604800",
  "sortBy": "DD",
  "maxPages": 20,
  "fetchDescription": true
}
```

#### Search by company names

```json
{
  "keywords": "Data Scientist",
  "companyNames": ["Google", "Microsoft", "Apple"],
  "timePosted": "r604800",
  "maxPages": 10
}
```

***

### ⚙️ Input Reference

#### Search parameters

| Field | Type | Description |
|---|---|---|
| `keywords` | string | Job title, skills, or keywords |
| `location` | string | City, state, or country |
| `geoId` | string | LinkedIn geo ID (overrides `location`) |
| `distance` | integer | Search radius in miles (5–100) |
| `companyNames` | string\[] | Company names (resolved to LinkedIn IDs) |
| `companyIds` | string\[] | LinkedIn company IDs directly |
| `industryIds` | string\[] | LinkedIn industry IDs |

#### Filters

| Field | Type | Values |
|---|---|---|
| `experienceLevel` | string\[] | `1` Internship · `2` Entry · `3` Associate · `4` Mid-Senior · `5` Director · `6` Executive |
| `workType` | string\[] | `1` Full-time · `2` Part-time · `3` Contract · `4` Temporary · `5` Volunteer · `6` Internship |
| `workLocation` | string\[] | `1` On-site · `2` Remote · `3` Hybrid |
| `timePosted` | string | `r3600` 1h · `r86400` 24h · `r604800` 1w · `r2592000` 1mo |
| `companySizes` | string\[] | `1`–`8` (1-10 up to 10,000+ employees) |
| `easyApplyOnly` | boolean | LinkedIn Easy Apply jobs only |
| `sortBy` | string | `R` Relevance · `DD` Date |

#### Behavior options

| Field | Type | Default | Description |
|---|---|---|---|
| `maxPages` | integer | `1` | Pages to scrape (10 jobs per page) |
| `fetchDescription` | boolean | `false` | Fetch full job description for each job |
| `maxRequestsPerCrawl` | integer | `100` | Hard cap on HTTP requests |

> **Tip:** When `fetchDescription` is enabled, each job uses 2 requests (1 search + 1 detail). Set `maxRequestsPerCrawl` accordingly — e.g. 10 jobs needs at least 20 requests.

#### AI search (optional)

| Field | Type | Description |
|---|---|---|
| `naturalLanguageQuery` | string | Plain English job search query |
| `useNaturalLanguage` | boolean | Enable AI parsing |
| `openaiApiKey` | string | Your OpenAI API key (bring your own) |

#### Advanced

| Field | Type | Description |
|---|---|---|
| `startUrls` | array | Override with your own LinkedIn search URLs |
| `linkedinParams` | object | Raw LinkedIn query params (overrides friendly fields) |
| `proxy` | object | Apify proxy or custom proxy URLs |

***

### ❓ FAQ

**Do I need a LinkedIn account?**
No. The actor uses LinkedIn's public guest API — no authentication required.

**Is this legal?**
This actor only accesses publicly available job listings that anyone can view without logging in.

**When should I use `fetchDescription`?**
When you need to filter jobs by their content — required skills, responsibilities, salary info embedded in the description, etc. If you only need titles, companies, and locations, leave it off to save cost and time.

**What if I get zero results?**
You pay nothing. Charges only apply to successfully scraped jobs and descriptions.

**How does the AI search work?**
Your query is sent to GPT-4-turbo which extracts job title, location, company, experience level, work type, and time frame, then resolves them to LinkedIn's internal IDs. If the AI call fails, a regex fallback handles the parsing.

**Do I need an OpenAI key?**
Only for natural language search. All other input modes work without one.

**Can I use my own proxies?**
Yes — pass `proxyUrls` in the `proxy` field, or use Apify's residential proxy network via `useApifyProxy: true`.

# Actor input Schema

## `naturalLanguageQuery` (type: `string`):

Describe your job search in plain English (e.g., 'senior software engineer positions in San Francisco, remote, from last week')

## `useNaturalLanguage` (type: `boolean`):

Use natural language processing to parse your query

## `openaiApiKey` (type: `string`):

Your OpenAI API key for natural language processing

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

Optional list of start URLs. If empty, the actor will build search URLs from other parameters.

## `keywords` (type: `string`):

Job title, skills, or company names to search for

## `location` (type: `string`):

City, state, or country (e.g., 'San Francisco Bay Area', 'New York')

## `geoId` (type: `string`):

LinkedIn internal geo ID for more precise location targeting (optional, overrides location)

## `distance` (type: `integer`):

Search radius from the specified location

## `experienceLevel` (type: `array`):

Select one or more experience levels

## `workType` (type: `array`):

Employment type preferences

## `workLocation` (type: `array`):

On-site, hybrid, or remote work preferences

## `timePosted` (type: `string`):

How recently the job was posted

## `companyNames` (type: `array`):

Specific companies to search within (will be resolved to company IDs)

## `companyIds` (type: `array`):

LinkedIn company IDs (f\_C parameter) - use instead of company names for exact matching

## `industryIds` (type: `array`):

LinkedIn industry IDs to filter by (f\_I parameter)

## `companySizes` (type: `array`):

Filter by company employee count

## `easyApplyOnly` (type: `boolean`):

Show only jobs with LinkedIn Easy Apply

## `jobsInNetwork` (type: `boolean`):

Show only jobs where you have 1st/2nd degree connections

## `sortBy` (type: `string`):

How to sort the job results

## `maxPages` (type: `integer`):

Maximum number of pages to scrape. Each page contains exactly 10 jobs. Set to 0 for unlimited pages (not recommended due to rate limiting).

## `fetchDescription` (type: `boolean`):

Fetch the full job description for each result. Makes one additional request per job. Charged separately at $0.001 per description.

## `linkedinParams` (type: `object`):

Raw LinkedIn search query parameters (for advanced users). These will override the friendly fields above.

## `maxRequestsPerCrawl` (type: `integer`):

Maximum number of HTTP requests the crawler will make (helps control costs and runtime)

## `proxy` (type: `object`):

Proxy settings for the crawler to avoid rate limiting and blocking

## `crawlerOptions` (type: `object`):

Fine-tune crawler performance and reliability settings

## `output` (type: `object`):

Configure how scraped data is saved and formatted

## Actor input object example

```json
{
  "naturalLanguageQuery": "Find senior product manager roles at tech companies like Google, Meta, or Apple in the San Francisco Bay Area, remote or hybrid, posted in the last month",
  "useNaturalLanguage": false,
  "keywords": "Product Manager",
  "location": "United States",
  "distance": 25,
  "timePosted": "r2592000",
  "easyApplyOnly": false,
  "jobsInNetwork": false,
  "sortBy": "R",
  "maxPages": 1,
  "fetchDescription": false,
  "maxRequestsPerCrawl": 100
}
```

# 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 = {
    "keywords": "Product Manager",
    "location": "United States"
};

// Run the Actor and wait for it to finish
const run = await client.actor("practicaltools/linkedin-jobs").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 = {
    "keywords": "Product Manager",
    "location": "United States",
}

# Run the Actor and wait for it to finish
run = client.actor("practicaltools/linkedin-jobs").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": "Product Manager",
  "location": "United States"
}' |
apify call practicaltools/linkedin-jobs --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=practicaltools/linkedin-jobs",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/SnNEWiOAQe9V9bEzL/builds/osUhjqbyLY76u8OaU/openapi.json
