# LinkedIn Jobs Scraper — Salaries, Recruiters & Descriptions (`vero-api/linkedin-jobs-scraper`) Actor

Scrape LinkedIn jobs by keyword and location, or paste LinkedIn job search links. Get titles, companies, salaries, full descriptions, recruiters, seniority, employment type, apply type and applicant counts as JSON, CSV or Excel. No login or API key.

- **URL**: https://apify.com/vero-api/linkedin-jobs-scraper.md
- **Developed by:** [VeroAPIs](https://apify.com/vero-api) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Features:** Limited permissions
- **Stats:** 38 total users, 1 monthly users, 100.0% runs succeeded, 6 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 job listings

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 — Salaries, Recruiters & Descriptions

LinkedIn Jobs Scraper **extracts job listings from LinkedIn**: title, company, location, posting date, salary (with min, max, currency and period), full description, seniority, employment type, applicant count, apply type and the recruiter who posted the job. Download them as **JSON, CSV, Excel, or XML**. It runs in the cloud, needs no coding, and **no LinkedIn login or API key**.

Try it right away: type what you're searching for and where, click **Start**, and watch the dataset fill up with structured job data. Or paste the link of a search you already ran on LinkedIn.

### What data does it extract?

Each result is **one job listing**:

| Data | Details |
|---|---|
| 💼 **Job** | title, LinkedIn URL, posting date, "time ago", and any badges (e.g. *Actively Hiring*) |
| 🏢 **Company** | nested `company` object: name, LinkedIn page URL, and logo |
| 📍 **Location** | where the job is based, as shown on LinkedIn |
| 💰 **Salary** | pay or salary range as shown, plus `salaryMin`, `salaryMax`, `salaryCurrency` and `salaryPeriod` as clean values |
| 📋 **Details** | seniority level, employment type, and industries |
| 👥 **Applicants** | number of applicants (as a number and as LinkedIn phrases it) |
| 🚪 **Apply type** | `easyApply` (apply on LinkedIn) or `external` (apply on the employer's site) |
| 🙋 **Job poster** | the recruiter or hiring manager's name, headline and profile link, when LinkedIn shows one |
| 📝 **Description** | the full job description in both plain text and HTML, plus any emails written in it |
| 🔎 **Search** | the keywords and location of the search that found the job |

### How do I scrape LinkedIn jobs?

1. **Say what you want**: enter *Search keywords* (a job title or skill) and a *Location*. Put several on separate lines to run many searches at once. Or paste LinkedIn search links into *LinkedIn search links*.
2. **Narrow it down** *(optional)*: filter by date posted, experience level, job type, Easy Apply, under 10 applicants, distance, or specific companies.
3. **Set how many**: choose *Maximum jobs*, or use `0` for every job LinkedIn shows (about 1,000 per search).
4. **Click Start**, then download the results from the **Storage** tab in any format, or send them anywhere with integrations.

### Paste a LinkedIn search link

Already built the perfect search on LinkedIn? Run it on linkedin.com/jobs, copy the address from your browser, and paste it into **LinkedIn search links**. You can paste as many links as you like. The scraper keeps the link's keywords, location, date posted, company, distance, Easy Apply, under-10-applicants, experience level, and job type settings. When you add links, the keyword and location fields are not used; the other filters on the form still apply.

### Many searches in one run

Put each keyword on its own line, and each location on its own line. Every keyword runs in every location, so `data analyst` and `nurse` × `London` and `Paris` gives four searches in one run. Jobs found by more than one search are saved once, and each row tells you which search found it.

### Filters that really filter

LinkedIn's public job search no longer applies its experience level, job type, remote, or sort filters on its own. This scraper checks every job's LinkedIn page instead, so with **Experience level** or **Job type** set you get only jobs that carry the label you picked. Jobs that don't match are skipped and **never charged**. Pick a single level or type for the fastest results: its words (for example *entry level* or *contract*) are added to your search so more of the jobs found match. When a search keeps turning up jobs that don't match, it wraps up and the run tells you, so you can pick a single level or use broader keywords.

Looking for remote or hybrid work? Add `remote` or `hybrid` to your keywords.

### Speed vs. detail

By default the scraper opens each job's page to collect the full description, seniority, employment type, industries, applicant count, apply type, and job poster. If you only need the essentials shown on the results list (title, company, location, date, and salary when present), turn off **Fetch full job details** for a much faster, lighter run.

### Input example

```json
{
    "keywords": "software engineer\ndata scientist",
    "location": "United States",
    "maxItems": 100,
    "datePosted": "pastWeek",
    "experienceLevel": ["entryLevel"],
    "jobType": ["fullTime"],
    "easyApply": false,
    "under10Applicants": false,
    "scrapeCompanyDetails": true
}
```

Or with a search link:

```json
{
    "startUrls": [{ "url": "https://www.linkedin.com/jobs/search/?keywords=marketing%20manager&location=Germany&f_TPR=r604800" }],
    "maxItems": 50
}
```

### Output example (abridged)

```json
{
    "id": "4406118990",
    "title": "Software Engineer, New Grad",
    "url": "https://www.linkedin.com/jobs/view/4406118990",
    "company": {
        "name": "Notion",
        "url": "https://www.linkedin.com/company/notionhq",
        "logo": "https://media.licdn.com/dms/image/v2/…/notionhq_logo"
    },
    "location": "San Francisco, CA",
    "postedDate": "2026-10-21",
    "postedTimeAgo": "4 days ago",
    "salary": "$126,000.00/yr - $146,000.00/yr",
    "salaryMin": 126000,
    "salaryMax": 146000,
    "salaryCurrency": "USD",
    "salaryPeriod": "yearly",
    "emails": ["recruiting@example.com"],
    "employmentType": "Full-time",
    "seniorityLevel": "Entry level",
    "industries": "Software Development",
    "applicantsCount": 200,
    "applicantsText": "Over 200 applicants",
    "applyType": "external",
    "jobPoster": {
        "name": "Jane Doe",
        "title": "Senior Technical Recruiter at Notion",
        "profileUrl": "https://www.linkedin.com/in/example-recruiter"
    },
    "benefits": ["Actively Hiring"],
    "descriptionText": "About the role\n\nWe're looking for a software engineer to build Notion's editor…",
    "descriptionHtml": "<strong>About the role</strong><br><br>We're looking for a software engineer…",
    "searchKeywords": "software engineer",
    "searchLocation": "United States"
}
```

### Input reference

| Field | Type | Description |
|---|---|---|
| `keywords` | string | Job title, skill, or company to search for. One search per line. |
| `location` | string | City, state, country, or region. One per line. Leave empty to search worldwide. |
| `startUrls` | array | LinkedIn job search links. When set, `keywords` and `location` are not used. |
| `maxItems` | integer | Total jobs to return across all searches. `0` = no limit. Default `25`. |
| `datePosted` | string | `any`, `past24h`, `pastWeek`, or `pastMonth`. Default `any`. |
| `experienceLevel` | array | Any of `internship`, `entryLevel`, `associate`, `midSenior`, `director`, `executive`. Checked on each job's page. |
| `jobType` | array | Any of `fullTime`, `partTime`, `contract`, `temporary`, `internship`, `volunteer`, `other`. Checked on each job's page. |
| `easyApply` | boolean | Only jobs you can apply to with LinkedIn Easy Apply. Default `false`. |
| `under10Applicants` | boolean | Only jobs with fewer than 10 applicants so far. Default `false`. |
| `radius` | integer | Search radius in miles around the location. |
| `companyIds` | array | Restrict to specific companies by numeric LinkedIn company ID (the `f_C` value in a LinkedIn search link, e.g. `1441` for Google). |
| `scrapeCompanyDetails` | boolean | Open each job page for the full description and details. Default `true`. |

### Why scrape LinkedIn jobs?

- **Job-market research**: track demand for roles, skills, and titles over time.
- **Recruiting & sourcing**: monitor who's hiring, who posted each job, and how competitive each posting is.
- **Lead generation**: find companies actively hiring in your space, with the recruiter to contact.
- **Salary benchmarking**: gather pay ranges as clean numbers where they're disclosed.
- **Job alerts**: schedule a daily run with *Date posted* set to *Past 24 hours* and get fresh jobs every morning.

### Integrations

Send results straight to Google Sheets, Slack, Airtable, a webhook, or your own database with Apify integrations, or connect the scraper to **Make**, **n8n**, and **Zapier**. Schedule runs in Apify Console to keep a job feed up to date automatically.

### Run it from your code or AI assistant

Call it from JavaScript with the Apify client (`npm install apify-client`):

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('vero-api/linkedin-jobs-scraper').call({
  keywords: 'product manager',
  location: 'London, England, United Kingdom',
  datePosted: 'pastWeek',
  maxItems: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, 'jobs');
```

Or from Python (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("vero-api/linkedin-jobs-scraper").call(run_input={
    "keywords": "product manager",
    "location": "London, England, United Kingdom",
    "datePosted": "pastWeek",
    "maxItems": 100,
})
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item["title"], item["company"]["name"], item["salary"])
```

Your token is under **Settings → API & Integrations** in Apify Console.

AI assistants such as Claude, ChatGPT, and Cursor can run it too, through the Apify MCP server. Add this to your assistant's MCP settings:

```json
{
  "mcpServers": {
    "linkedin-jobs-scraper": {
      "url": "https://mcp.apify.com?tools=vero-api/linkedin-jobs-scraper"
    }
  }
}
```

Then just ask, for example:

- *"Find entry-level data analyst jobs posted in London this week and list the ones with a salary."*
- *"Which companies posted remote product manager jobs on LinkedIn today, and who are the recruiters?"*

### Pricing

This Actor uses **pay-per-event** pricing: a tiny fee when a run starts, plus a flat fee per job delivered; the exact rate is on the **Pricing** tab. You only pay for the listings you actually receive. Jobs skipped by your filters are free. With **Fetch full job details** on, you pay only for jobs delivered with their full details. Any other job is replaced with the next one at no charge. Set *Maximum jobs* to control your spend, and a run stops cleanly at your spending limit.

### FAQ

**Do I need a LinkedIn account or API key?** No. The scraper reads LinkedIn's public job pages, the same ones anyone can see without logging in.

**Can I paste a LinkedIn search link?** Yes. Paste one or more links into *LinkedIn search links*, or straight into the keywords box, and the scraper runs those searches.

**How many jobs can I get?** LinkedIn shows about 1,000 jobs per search. For bigger pulls, add more keywords or locations on separate lines, or narrow each search by date posted.

**Can I search several job titles and cities at once?** Yes. Put each keyword and each location on its own line; every keyword runs in every location, and each job is saved once.

**Do the experience level and job type filters really work?** Yes. Every job is checked against the label on its LinkedIn page, and jobs that don't match are skipped at no charge. LinkedIn marks many jobs as "Not Applicable" for experience level; those are left out when you pick a level.

**How do I find remote jobs?** Add `remote` (or `hybrid`) to your keywords. LinkedIn's public pages don't label jobs as remote or on-site, so there's no separate filter.

**Does it get salaries?** Yes, whenever the employer lists pay on LinkedIn, as the original text plus clean min, max, currency, and period values.

**Does it get the recruiter?** Yes, when LinkedIn shows who posted the job: name, headline, and profile link in `jobPoster`.

**How do I get only new jobs every day?** Schedule the actor in Apify Console with *Date posted* set to *Past 24 hours*.

**What formats can I download?** JSON, CSV, Excel, XML, RSS, and HTML, or read the results through the Apify API.

**Is this an official LinkedIn tool?** No. This actor is not affiliated with, endorsed by, or sponsored by LinkedIn. It collects public job listings that anyone can browse on LinkedIn.

### More tools from us

- [Multi Job Board Scraper](https://apify.com/vero-api/multi-job-board-scraper-linkedin-indeed-glassdoor-more): jobs from LinkedIn, Indeed, Glassdoor, and more in one run.
- [Indeed Jobs Scraper](https://apify.com/vero-api/indeed-jobs-scraper): job listings, salaries, and companies from Indeed.
- [Google Jobs Scraper](https://apify.com/vero-api/google-jobs-scraper): jobs gathered from across the web by Google.
- [Naukri Jobs Scraper (Gulf)](https://apify.com/vero-api/naukri-jobs-scraper): jobs, salaries, and companies from Naukri across the Gulf and India.
- [Bayt Jobs Scraper (Middle East)](https://apify.com/vero-api/bayt-jobs-scraper): job listings from Bayt across the Middle East and North Africa.
- [Email Validator](https://apify.com/vero-api/email-validator): check that the contact emails you collect are deliverable.

### Notes

- Nothing to configure: reliable results are handled for you.
- The scraper uses LinkedIn's **public** job pages, the same data anyone can see without logging in. It does not log in or access private data.
- `emails`, `salary`, and `jobPoster` are included whenever the posting shows them.
- LinkedIn shows roughly **1,000 results** per search. To pull more, split your search into narrower queries (by location, keywords, or date).

# Actor input Schema

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

The job title, skill or company to search for, as you'd type it into LinkedIn's job search box (e.g. <code>software engineer</code>, <code>registered nurse</code>). Put each search on its own line to run several in one go. Add words like <code>remote</code>, <code>entry level</code> or <code>contract</code> to focus the search.

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

City, state, country or region to search in (e.g. <code>London, England, United Kingdom</code>, <code>Germany</code>). Put each location on its own line to search several; every keyword line runs in every location. Leave empty to search worldwide.

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

LinkedIn job search links to scrape, one per line. Run your search on linkedin.com/jobs and copy the address from your browser. When you add links, the keyword and location fields are not used; the filters below still apply.

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

How many jobs to return in total, across all searches. LinkedIn shows up to about 1,000 jobs per search. Use <code>0</code> for no limit.

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

Only return jobs posted within this time window.

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

Keep only jobs whose LinkedIn page lists one of these experience levels. Jobs with another level, or none, are skipped and never charged. Pick one level for the fastest results: its words (e.g. entry level) are added to your search. Leave empty to include all levels.

## `jobType` (type: `array`):

Keep only jobs whose LinkedIn page lists one of these employment types. Other jobs are skipped and never charged. Pick one type for the fastest results: its word (e.g. contract) is added to your search. Leave empty to include all types.

## `easyApply` (type: `boolean`):

Turn on to get only jobs you can apply to directly on LinkedIn with Easy Apply.

## `under10Applicants` (type: `boolean`):

Turn on to get only fresh jobs with fewer than 10 applicants so far, so you can be among the first to apply.

## `radius` (type: `integer`):

Search radius around the location, in miles (e.g. <code>25</code>). Works with a city or area. Leave empty for LinkedIn's default.

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

Numeric LinkedIn company IDs, one per line, to see only those companies' jobs (e.g. <code>1441</code> for Google). Find the ID as the <code>f_C</code> value in the link of a company's job search on LinkedIn.

## `scrapeCompanyDetails` (type: `boolean`):

Keep on to add each job's full description, seniority level, employment type, industries, applicant count, apply type and the person who posted it. Turn off for a faster run with only what the results list shows (title, company, location, date and salary when listed). The experience level and job type filters always use the full details.

## Actor input object example

```json
{
  "keywords": "software engineer",
  "location": "United States",
  "maxItems": 25,
  "datePosted": "any",
  "easyApply": false,
  "under10Applicants": false,
  "scrapeCompanyDetails": true
}
```

# Actor output Schema

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

Every job found, with all fields: id, title, url, company (name, url, logo), location, postedDate, salary, salaryMin, salaryMax, salaryCurrency, salaryPeriod, employmentType, seniorityLevel, industries, applicantsCount, applyType, jobPoster, emails, descriptionText and the searchKeywords and searchLocation that found it.

# 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": "software engineer",
    "location": "United States"
};

// Run the Actor and wait for it to finish
const run = await client.actor("vero-api/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 = {
    "keywords": "software engineer",
    "location": "United States",
}

# Run the Actor and wait for it to finish
run = client.actor("vero-api/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 '{
  "keywords": "software engineer",
  "location": "United States"
}' |
apify call vero-api/linkedin-jobs-scraper --silent --output-dataset

```

## MCP server setup

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