# LinkedIn Jobs Scraper - Listings, Multi-Title, Location, CSV (`flash_scraper/linkedin-jobs-scraper`) Actor

Scrape LinkedIn's public job listings by title & location - job title, company, location, posted date & job URL. Search multiple job titles in one run, deduplicated across queries, freshest first. No login, no cookies, no API key, no auto-apply. Export CSV, JSON or Excel.

- **URL**: https://apify.com/flash\_scraper/linkedin-jobs-scraper.md
- **Developed by:** [Flash Scrape](https://apify.com/flash_scraper) (community)
- **Categories:** Jobs, Social media, Automation
- **Stats:** 5 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $5.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/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 — public job listings with parsed salary, no login, no auto-apply

**Scrape LinkedIn jobs into a clean, analysis-ready spreadsheet.** Give this actor job titles and a location and get back one row per posting: title, company, location, **parsed salary** (min/max/period plus the raw string), employment type, seniority, job function, sector, **applicant count as an integer**, recruiter, posting date, and the job URL — each row topped with a **0–100 job score** so the freshest, best-documented, salary-showing listings sort first. Built for job seekers, recruiters, job-board builders, and labor-market analysts. It reads only **public, logged-out listings** — no LinkedIn login, no cookies, and it never auto-applies. **Pay-per-result**: $5 per 1,000 jobs.

### What it does

- **Searches LinkedIn's public job listings** by keyword and location — postings are fetched through the [`valig/linkedin-jobs-scraper`](https://apify.com/valig/linkedin-jobs-scraper) data provider, with your native filters (date posted, experience level, employment type, remote/on-site/hybrid, specific companies) applied at the source.
- **Parses salaries into numbers**: `"$115,000.00/yr - $120,000.00/yr"` becomes `salaryMin: 115000`, `salaryMax: 120000`, `salaryPeriod: "year"` — and the `minSalary` filter annualizes hourly/monthly pay before comparing.
- **Derives an `isRemote` flag** by scanning the title, location, and description for remote/WFH signals (LinkedIn's own field for this isn't exposed on public listings).
- **Parses applicant counts to integers** so you can filter to low-competition roles with `maxApplicants`.
- **Normalizes and cleans**: posting dates to `YYYY-MM-DD`, tracking parameters stripped from job URLs, whitespace collapsed, duplicates removed across all your search queries.
- **Scores every job 0–100** — salary shown +25, freshness up to +25, full description +20, seniority/sector present +12, company present +8 — and sorts the dataset best-first (ties broken by highest salary).
- **Applies your client-side filters** after cleaning: `requireSalary`, `minSalary` (annualized), `easyApplyOnly`, `maxApplicants`.

### Use cases

- **Job search automation** — schedule a daily run for your target titles, filter to `r86400` (past 24 h) and low applicant counts, and be among the first applicants.
- **Recruiting intelligence** — see which companies are hiring for a role, at what advertised salary, and how much competition each posting draws.
- **Job-board aggregation** — feed a niche job board with clean, deduped LinkedIn postings including salary data where shown.
- **Salary benchmarking** — collect the minority of postings that disclose pay and analyze `salaryMin`/`salaryMax` by title and region.
- **Labor-market research** — track posting volume, seniority mix, and remote share across sectors over time.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `searchQueries` | array | `["data analyst"]` | Job titles, skills, or company keywords — one per line. Each is searched separately and results are deduped. |
| `location` | string | `"United States"` | City, state, country, or zip — e.g. `London`, `Remote`. |
| `datePosted` | string | `""` | `r86400` (past 24 h), `r604800` (past week), `r2592000` (past month), or empty for any time. |
| `experienceLevel` | array | `[]` | Seniority codes: `1` Internship, `2` Entry, `3` Associate, `4` Mid-Senior, `5` Director. |
| `contractType` | array | `[]` | Employment type codes: `F` Full-time, `P` Part-time, `C` Contract, `T` Temporary, `I` Internship. |
| `remote` | array | `[]` | Work arrangement codes: `1` On-site, `2` Remote, `3` Hybrid. |
| `companyNames` | array | `[]` | Filter to specific company names. |
| `companyId` | array | `[]` | Filter by LinkedIn numeric company IDs (from a company page URL). |
| `maxItems` | integer | `100` | Max jobs **per search query** (1–1000). |
| `requireSalary` | boolean | `false` | Drop listings that don't show a salary. |
| `minSalary` | integer | `0` | Keep only jobs paying at least this much per year (hourly/monthly pay annualized; 0 = off). |
| `easyApplyOnly` | boolean | `false` | Keep only LinkedIn Easy Apply jobs. |
| `maxApplicants` | integer | `0` | Keep only jobs with at most this many applicants (0 = off). |

```json
{
  "searchQueries": ["data analyst"],
  "location": "United States",
  "datePosted": "r604800",
  "experienceLevel": ["3", "4"],
  "remote": ["2"],
  "maxItems": 100,
  "requireSalary": true,
  "minSalary": 90000
}
```

### Output

One dataset row per job, deduped across queries and sorted by `job_score`. Export to CSV, JSON, or Excel from the Output tab.

```json
{
  "jobTitle": "Data Analyst",
  "companyName": "Synechron",
  "location": "Pittsburgh, PA",
  "jobFunction": "Information Technology",
  "isRemote": false,
  "salaryRaw": "$115,000.00/yr - $120,000.00/yr",
  "salaryMin": 115000,
  "salaryMax": 120000,
  "salaryPeriod": "year",
  "employmentType": "Full-time",
  "seniority": "Mid-Senior level",
  "sector": "IT Services and IT Consulting",
  "applicants": 200,
  "applyType": "EXTERNAL",
  "applyUrl": "https://careers.synechron.com/...",
  "postedDate": "2026-06-21",
  "postedTimeAgo": "2 weeks ago",
  "recruiterName": null,
  "recruiterUrl": null,
  "companyUrl": "https://www.linkedin.com/company/synechron",
  "jobUrl": "https://www.linkedin.com/jobs/view/4422685636",
  "descriptionText": "We are seeking a Data Analyst to…",
  "descriptionHtml": "<p>We are seeking a Data Analyst to…</p>",
  "jobId": "4422685636",
  "job_score": 69
}
```

### Pricing

This actor uses Apify **pay-per-event pricing: $5 per 1,000 jobs** ($0.005 per result). You're charged only for the cleaned listings delivered **after** dedup and your filters — with `requireSalary` on, listings without pay data cost you nothing. No subscription, no charge for empty runs. Use `maxItems` and the filters to keep cost predictable: a daily 100-job tracked search costs about $0.50/month. The **free Apify plan is enough to try it** on a real search first.

### Tips / FAQ

**Does this apply to jobs for me?** No. It only collects public listings into a dataset — it never logs in and never submits an application, including Easy Apply.

**Do I need a LinkedIn account or cookie?** No. It scrapes the public, logged-out job search — no `li_at` cookie, no credentials, no API key.

**Why is salary usually empty?** LinkedIn shows pay on a minority of postings. The parser fills `salaryMin`/`salaryMax`/`salaryPeriod` whenever a figure appears; use `requireSalary` to keep only those rows.

**What's the difference between `jobFunction` and `isRemote`?** `jobFunction` is the role area LinkedIn lists (e.g. "Information Technology"). Remote status isn't a separate public field, so `isRemote` is derived from remote/WFH keywords in the title, location, and description — treat it as a strong signal, not gospel.

**Where does the data come from, and what if the source is down?** Listings come via an upstream data provider (`valig/linkedin-jobs-scraper`). If one query fails it's skipped and the run continues; on a full transient outage the run ends gracefully with a "temporarily unavailable — please retry" message and **you're charged nothing**.

**Is scraping LinkedIn jobs legal?** This collects **public** job data only, from logged-out pages. LinkedIn rate-limits aggressively and restricts automated access in its terms, so expect occasional partial runs; use the data for personal, research, or recruiting purposes and follow local law.

### Related actors

- [Indeed Jobs Scraper](https://apify.com/flash_scraper/indeed-jobs-scraper) — the same clean-jobs approach for Indeed
- [Multi-Jobboard Scraper](https://apify.com/flash_scraper/multi-jobboard-scraper) — one search across several job boards at once
- [Company & Domain Enricher](https://apify.com/flash_scraper/company-domain-enricher) — turn hiring companies into full firmographic records

**Support:** found a bug or need a feature? Open an Issue on this actor's **Issues tab** — typical response within 1 business day.

# Actor input Schema

## `searchQueries` (type: `array`):

Job titles, skills, or company keywords to search — one per line. e.g. 'data analyst', 'react developer'.

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

City, state, country, or zip to search within — e.g. 'United States', 'London', 'Remote'.

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

Only jobs posted within this window.

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

Filter by seniority (leave empty for all).

## `contractType` (type: `array`):

Filter by employment type (leave empty for all).

## `remote` (type: `array`):

Filter by on-site / remote / hybrid (leave empty for all).

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

Filter to specific company names (leave empty for all).

## `companyId` (type: `array`):

Filter by LinkedIn numeric company IDs (from a company page URL). Leave empty for all.

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

Maximum number of jobs to scrape per search query (1-1000).

## `requireSalary` (type: `boolean`):

Drop listings that don't show a salary.

## `minSalary` (type: `integer`):

Keep only jobs paying at least this much per year (hourly/monthly pay is annualized; 0 = no filter).

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

Keep only jobs that support LinkedIn Easy Apply.

## `maxApplicants` (type: `integer`):

Keep only jobs with at most this many applicants (low-competition roles; 0 = no filter).

## Actor input object example

```json
{
  "searchQueries": [
    "product manager",
    "backend engineer"
  ],
  "location": "United States",
  "datePosted": "",
  "experienceLevel": [],
  "contractType": [],
  "remote": [],
  "companyNames": [],
  "companyId": [],
  "maxItems": 100,
  "requireSalary": false,
  "minSalary": 0,
  "easyApplyOnly": false,
  "maxApplicants": 0
}
```

# Actor output Schema

## `results` (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 = {
    "searchQueries": [
        "data analyst"
    ],
    "location": "United States"
};

// Run the Actor and wait for it to finish
const run = await client.actor("flash_scraper/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 = {
    "searchQueries": ["data analyst"],
    "location": "United States",
}

# Run the Actor and wait for it to finish
run = client.actor("flash_scraper/linkedin-jobs-scraper").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 '{
  "searchQueries": [
    "data analyst"
  ],
  "location": "United States"
}' |
apify call flash_scraper/linkedin-jobs-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/tLw6gWbK8yTwf4k1S/builds/JwsoLhfREbUDHuBeu/openapi.json
