# LinkedIn Jobs Scraper (`itamartoledano/linkedin-jobs-scraper`) Actor

Scrape LinkedIn job search results by URL, no login needed. Get title, company, logo, location, post date, applicants, seniority, employment type, job function, industry, salary & currency, full description, and Easy Apply flag, one item per job. Proxy support and automatic retries.

- **URL**: https://apify.com/itamartoledano/linkedin-jobs-scraper.md
- **Developed by:** [Itamar Toledano](https://apify.com/itamartoledano) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.20 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## LinkedIn Jobs Scraper

### What is LinkedIn Jobs Scraper and how does it work?

**LinkedIn Jobs Scraper** is an Apify Actor that extracts structured job listings from a LinkedIn job search, **without logging in**.

Paste a LinkedIn job search URL, configure a proxy, and run the Actor. It loads LinkedIn's public (guest) search page with a browser-like HTTP client, then opens each job's public posting page for the full details, and stores **one dataset item per job**. You can download the results from the dataset or pull them through the Apify API.

LinkedIn job search URLs look like this:

```text
https://www.linkedin.com/jobs/search?keywords=Python&location=Germany&position=1&pageNum=0
```

The host must be `www.linkedin.com`, the path must be `/jobs/search`, and the URL needs `keywords`, `location`, or both. LinkedIn filters in the query string are kept, so the easiest way to build a URL is to search on LinkedIn while logged out and copy it from the address bar. Useful filters:

| Filter | Example | Meaning |
| --- | --- | --- |
| `f_TPR` | `r86400`, `r604800` | Posted in the last 24 hours / week (seconds) |
| `f_JT` | `F`, `P`, `C`, `I` | Full-time, part-time, contract, internship |
| `f_WT` | `1`, `2`, `3` | On-site, remote, hybrid |
| `f_E` | `2`, `3`, `4` | Entry level, associate, mid-senior |

### Why scrape LinkedIn jobs?

- **Job market research**: who is hiring for a role, where, and at what seniority
- **Salary benchmarking**: LinkedIn's base pay ranges, parsed into numbers
- **Lead generation**: companies actively hiring, with LinkedIn company links
- **Job alerts & aggregation**: combine date filters (`f_TPR`) with scheduled runs to get fresh postings
- **Competition analysis**: applicant counts per job

### What data can LinkedIn Jobs Scraper extract?

| Data | Fields |
| --- | --- |
| Search | `input`, `search_keywords`, `search_location`, `position` |
| Job | `job_id`, `job_title`, `seniority_level`, `employment_type`, `job_function`, `industries`, `workplace_type` |
| Company | `company_name`, `company_url`, `company_logo` |
| Location & date | `location`, `posted_at`, `posted_relative`, `is_new` |
| Competition | `applicants`, `insights` |
| Salary | `salary_text`, `salary_min`, `salary_max`, `salary_type`, `salary_currency`, `salary_source` |
| Content | `description`, `description_html` |
| Apply | `job_url`, `is_easy_apply` |
| Meta | `has_details`, `fetched_at` |

**Card vs. detail fields:** the search page gives the title, company, logo, location, dates, and badges. With `includeDetails` on (the default), each job's posting page adds the description, criteria (seniority, employment type, function, industries), applicants, salary, and apply type, and `has_details` becomes `true`.

**Notes:**

- `salary_*` is only filled when LinkedIn shows a pay range (common in the US, UK, and Canada). `salary_currency` is the ISO code behind the symbol (`$` → USD, `CA$` → CAD, `£` → GBP, `€` → EUR…), and `salary_source` is `employer` for a company-provided range or `job_post` when LinkedIn found the pay in the post.
- `is_easy_apply` is `true` for LinkedIn Easy Apply jobs and `false` for jobs that apply on the company's site. LinkedIn only reveals the external apply link to signed-in users, so it isn't returned.
- `workplace_type` is filled when the search URL filters on exactly one `f_WT` value.

### How many results can you scrape?

One LinkedIn search page returns up to about **60 jobs**. Set `maxItems` (1–100, default 25) to control how many are saved. For more coverage, run narrower searches (per city, per date range, per job type), for example on a schedule.

### How much will it cost?

Each run makes one search request plus one request per job when `includeDetails` is on (a run with `maxItems: 25` makes 26 requests). Turn `includeDetails` off for a cheaper card-only scrape. Run a few searches first, note the cost per run, and scale from there.

### Is it legal to scrape LinkedIn?

This Actor only reads **public job postings** that LinkedIn shows to logged-out visitors; it never logs in. Job postings can still contain personal data (e.g. recruiter names), so review LinkedIn's terms and your own compliance requirements (e.g. GDPR). See Apify's post on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

### How do I scrape jobs on LinkedIn?

1. Open [linkedin.com/jobs/search](https://www.linkedin.com/jobs/search) in a private window, search, and copy the URL
2. Open **LinkedIn Jobs Scraper** in Apify Console and paste it into `url`
3. Pick `maxItems` and whether to include job details
4. Keep the default proxy (Apify residential) or pick your own
5. Click **Start** and open the **Dataset** tab when the run finishes

#### Tips

- LinkedIn rate-limits guest traffic per IP. Residential proxies work best for larger or frequent runs.
- Sign-in walls and rate-limit responses (HTTP 429/999) are detected and retried automatically (default up to 4 attempts).
- If a single posting page keeps failing, that job is still saved with its search-card fields and `has_details: false`, so one bad page doesn't fail the run.

### Input

| Field | Required | Description |
| --- | --- | --- |
| `url` | Yes | HTTPS LinkedIn job search URL (`www.linkedin.com/jobs/search?keywords=…&location=…`) |
| `maxItems` | No | Maximum jobs to save (1–100, default 25) |
| `includeDetails` | No | Fetch each job's posting page (default `true`) |
| `proxyConfiguration` | Recommended | Apify Proxy or custom proxy URLs |

```json
{
  "url": "https://www.linkedin.com/jobs/search?keywords=Python&location=Germany&position=1&pageNum=0",
  "maxItems": 25,
  "includeDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

### Sample output

One item per job:

```json
{
  "source": "linkedin",
  "input": "https://www.linkedin.com/jobs/search?keywords=Python&location=Germany&position=1&pageNum=0",
  "search_keywords": "Python",
  "search_location": "Germany",
  "position": 1,
  "job_id": "4467502615",
  "job_title": "(Senior) Software Developer Backend / Python",
  "company_name": "Athereon GRC GmbH",
  "company_url": "https://www.linkedin.com/company/athereon-grc",
  "company_logo": "https://media.licdn.com/dms/image/v2/…/athereon_grc_logo?…",
  "location": "Saarbrücken, Saarland, Germany",
  "workplace_type": null,
  "posted_at": "2026-09-17",
  "posted_relative": "1 week ago",
  "is_new": false,
  "insights": [],
  "applicants": "56 applicants",
  "seniority_level": "Associate",
  "employment_type": "Full-time",
  "job_function": "Information Technology",
  "industries": "Software Development",
  "salary_text": null,
  "salary_min": null,
  "salary_max": null,
  "salary_type": null,
  "salary_currency": null,
  "salary_source": null,
  "description": "Ihre Aufgaben\nDu entwickelst Features und Verbesserungen für das Backend unserer SaaS-Applikation…",
  "description_html": "<strong>Ihre Aufgaben</strong><ul><li>Du entwickelst Features…</li></ul>",
  "job_url": "https://www.linkedin.com/jobs/view/4467502615",
  "is_easy_apply": false,
  "has_details": true,
  "fetched_at": "2026-09-29T17:46:40.010873Z"
}
```

A US job with a pay range returns, for example, `"salary_text": "$176,400.00/yr - $226,800.00/yr"`, `"salary_min": 176400`, `"salary_max": 226800`, `"salary_type": "yearly"`, `"salary_currency": "USD"`, `"salary_source": "employer"`.

### Integrations

Connect LinkedIn Jobs Scraper to Make, Zapier, Slack, Google Sheets, Airbyte, GitHub, and more through [Apify integrations](https://apify.com/integrations), or trigger actions with [webhooks](https://docs.apify.com/integrations/webhooks) when a run finishes.

### Using the Apify API

Run the Actor and fetch results programmatically with the [Apify API](https://docs.apify.com/api/v2), using [`apify-client`](https://www.npmjs.com/package/apify-client) for Node.js or [`apify-client`](https://pypi.org/project/apify-client/) for Python. See the **API** tab for code examples.

### FAQ

#### Do I need a LinkedIn account or cookies?

No. The Actor only uses LinkedIn's public guest pages.

#### Does it scrape profiles, companies, or posts?

No. Only job search URLs (`www.linkedin.com/jobs/search`) are accepted.

#### Why do some jobs have `has_details: false`?

Either `includeDetails` is off, or LinkedIn blocked that job's posting page on every retry. The search-card fields are still returned.

#### What happens when LinkedIn shows a sign-in wall?

The Actor treats sign-in redirects, missing results, and HTTP 429/999 responses as blocks, retries, and fails the run if every attempt for the search page is blocked. Switching to residential proxies usually fixes it.

### Your feedback

Found a bug or have a feature request? Open an issue on the Actor's **Issues** tab in Apify Console.

# Actor input Schema

## `url` (type: `string`):

HTTPS LinkedIn job search URL. Host must be www.linkedin.com, the path must be /jobs/search, and it needs keywords and/or location. LinkedIn filters in the URL (f\_TPR date posted, f\_JT job type, f\_WT workplace type, f\_E experience…) are kept.

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

Maximum number of jobs to save. One search page holds up to about 60 jobs.

## `includeDetails` (type: `boolean`):

Open each job's posting page to add the description, seniority level, employment type, job function, industries, applicants, salary with currency, and Easy Apply flag. Adds one request per job.

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

Select Apify Proxy groups/country or provide custom proxy URLs. LinkedIn rate-limits guest traffic per IP, so residential proxies are recommended for larger runs. See https://docs.apify.com/sdk/python/docs/concepts/proxy-management

## Actor input object example

```json
{
  "url": "https://www.linkedin.com/jobs/search?keywords=Python&location=Germany&position=1&pageNum=0",
  "maxItems": 25,
  "includeDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

One item per job (job\_id, job\_title, company, location, seniority, employment type, salary, description, etc.).

# 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 = {
    "url": "https://www.linkedin.com/jobs/search?keywords=Python&location=Germany&position=1&pageNum=0",
    "maxItems": 25,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("itamartoledano/linkedin-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 = {
    "url": "https://www.linkedin.com/jobs/search?keywords=Python&location=Germany&position=1&pageNum=0",
    "maxItems": 25,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("itamartoledano/linkedin-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 '{
  "url": "https://www.linkedin.com/jobs/search?keywords=Python&location=Germany&position=1&pageNum=0",
  "maxItems": 25,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call itamartoledano/linkedin-jobs-scraper --silent --output-dataset

```

## MCP server setup

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