# LinkedIn Jobs Scraper — Job Pages, Salary & New Jobs Monitor (`saliga/linkedin-jobs-scraper`) Actor

Scrape LinkedIn jobs by keyword and location or any job search link. Full job description, salary, seniority, applicants, Easy Apply flag, staffing-agency and AI-job flags, de-duplicated, daily new-jobs alerts and a list of hiring companies. No login or cookies.

- **URL**: https://apify.com/saliga/linkedin-jobs-scraper.md
- **Developed by:** [Salih Küçükkayış](https://apify.com/saliga) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 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.

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

Get **LinkedIn jobs** by keyword and location, or paste any **LinkedIn job search link** with your filters. Every job comes with the **full job page**: description, seniority level, employment type, job function, industry, number of applicants, salary when LinkedIn shows it and whether you apply **on LinkedIn (Easy Apply) or on the company's own site**. No login, no cookies, no LinkedIn account needed.

![LinkedIn Jobs Scraper demo: input, run and results table from a real run](https://raw.githubusercontent.com/msalihk/apify-actor-examples/620b5a0f9925474404cef5a8900ec9e53f19d641/media/linkedin-jobs-scraper.gif)

What the other LinkedIn job scrapers leave to you:

- **Staffing agencies flagged.** Every job has `staffingAgency: true/false` (from LinkedIn's industry and the company name). One switch drops them, and dropped jobs are not charged.
- **De-duplicated.** The same job found by several searches is returned once, with every search that found it.
- **New jobs only.** Turn on *Only new jobs since the last run*, schedule the Actor daily, and get just the jobs you have not seen. Jobs seen before are not charged.
- **Hiring companies list.** Switch *Output* to *Companies*: one row per company with jobs found, jobs posted in the last 7 and 30 days, AI jobs, remote jobs, seniority mix and sample titles. A ready-made list of who is hiring, for sales and recruiting.
- **AI jobs flagged.** `aiJob: true` when the job builds with AI (AI/ML roles, or engineering roles that ask for LLM, RAG, OpenAI and similar).
- **Salary as numbers.** `salaryMin`, `salaryMax`, `salaryCurrency` and `salaryPeriod`, not just text.

### What you can use it for

- **Job alerts and job boards**: fresh jobs for a niche, every day, without duplicates or agency reposts.
- **Recruiting**: who is hiring for the roles you place, and where, with the agencies flagged.
- **Sales prospecting**: companies hiring data engineers, nurses or salespeople right now are companies with a budget and a problem. Use the *Companies* output as a lead list.
- **Labour market research**: salary ranges, seniority mix, remote share and applicant counts by role and location.
- **AI adoption tracking**: which companies are hiring to build with AI.

### Quick start

Press **Start** with the example input (data engineer jobs in the United Kingdom), or give your own:

```json
{
  "keywords": ["data engineer", "analytics engineer"],
  "locations": ["London", "Remote"],
  "postedWithin": "week",
  "maxJobsPerSearch": 200,
  "excludeStaffingAgencies": true
}
```

Or set up a search on [linkedin.com/jobs](https://www.linkedin.com/jobs) with every filter you need, copy the link from the address bar and paste it into *LinkedIn job search links*:

```json
{
  "searchUrls": ["https://www.linkedin.com/jobs/search/?keywords=nurse&location=Texas&f_TPR=r86400&f_E=2"]
}
```

### Output

One row per job (fields that LinkedIn does not show for a job are left out):

```json
{
  "id": "4012345678",
  "title": "Data Engineer",
  "company": "Acme Ltd",
  "companyUrl": "https://uk.linkedin.com/company/acme-ltd",
  "companySlug": "acme-ltd",
  "location": "London, England, United Kingdom",
  "postedAt": "2026-10-20",
  "url": "https://www.linkedin.com/jobs/view/4012345678/",
  "easyApply": false,
  "seniorityLevel": "Mid-Senior level",
  "employmentType": "Full-time",
  "jobFunction": "Engineering and Information Technology",
  "industries": "Software Development",
  "applicants": 200,
  "applicantsText": "Over 200 applicants",
  "salaryText": "£55,000.00 - £70,000.00",
  "salaryMin": 55000,
  "salaryMax": 70000,
  "salaryCurrency": "GBP",
  "salaryPeriod": "year",
  "remote": false,
  "staffingAgency": false,
  "aiJob": true,
  "aiLevel": "stack",
  "aiTerms": ["OpenAI", "LLM", "RAG"],
  "description": "About us\nWe build data tools.\n- Python and SQL\n- Experience with LLMs, RAG and OpenAI APIs",
  "search": "data engineer @ United Kingdom"
}
```

With *Output: Companies*, one row per hiring company:

```json
{
  "company": "Acme Ltd",
  "companyUrl": "https://uk.linkedin.com/company/acme-ltd",
  "jobsFound": 7,
  "postedLast7Days": 3,
  "postedLast30Days": 7,
  "aiJobs": 2,
  "remoteJobs": 1,
  "staffingAgency": false,
  "industries": "Software Development",
  "seniority": {"Mid-Senior level": 4, "Entry level": 2, "Not given": 1},
  "topLocations": {"London, England, United Kingdom": 6, "Remote": 1},
  "sampleTitles": ["Data Engineer", "ML Engineer", "Analytics Engineer"]
}
```

### Input

| Field | What it does |
|---|---|
| Job keywords | One search per line, as you would type it on LinkedIn. |
| Locations | City, region or country. Every keyword is searched in every location. Empty: worldwide. |
| LinkedIn job search links | Paste links from linkedin.com/jobs; all their filters are kept. |
| Max jobs per search | Up to 1,000 (LinkedIn's own limit per search). |
| Posted within | Any time, past 24 hours, past week, past month. |
| Experience level, Job type, On-site / remote | LinkedIn's filters. |
| Open each job page | Full description and job details (on by default). |
| Drop staffing and recruiting agencies, Drop jobs whose title contains, Drop these companies | Cleaning; dropped jobs are not charged. |
| Output | Jobs, or Companies (hiring summary). |
| Only new jobs since the last run, Monitor name | Job alerts: only jobs not returned before. |

### Pricing

You pay per result: **per job** in the *Jobs* output, **per company** in the *Companies* output, plus a small fee per run. Duplicates, jobs dropped by your filters and jobs the monitor has already seen are free. Apify's free plan credit covers a first test.

### Run it on a schedule

For job alerts, create a [task](https://docs.apify.com/platform/actors/running/tasks) with your searches and *Only new jobs since the last run* on, then [schedule](https://docs.apify.com/platform/schedules) it daily. Send new jobs where you need them with integrations: Slack, Google Sheets, email, Zapier, Make or n8n, or call it from your own code through the Apify API.

### FAQ

**Do I need a LinkedIn account or cookies?** No. The Actor reads the job pages LinkedIn shows to visitors who are not signed in.

**Why not the LinkedIn API?** LinkedIn's job APIs are only open to approved partners (job boards and applicant tracking systems). This Actor gives you the public job listings without a partnership.

**Does it collect personal data?** No. It returns jobs and companies only. The "meet the hiring team" box on job pages (names of employees) is skipped on purpose.

**Why do I get fewer jobs than LinkedIn says?** LinkedIn returns about 1,000 jobs per search at most, and its counts include similar jobs. Split big searches: more specific keywords, smaller locations or *Posted within: past week*.

**How do I get more than 1,000 jobs?** Add several keywords or locations: each one is a separate search, and duplicates between them are removed for free.

**Some jobs have no salary.** LinkedIn shows a salary only when the employer gives one or LinkedIn estimates it for the card. When it is there, you get it as text and as numbers.

**What does `staffingAgency` mean?** The job was posted by a recruiting agency: the company is a known agency, or the ad is written the way agencies write ("our client is", "we're working with a ..."). In a test on 100 UK data engineer jobs it flagged 28. Use it to remove reposted jobs and get to the real employer.

**Is there a link to apply on the company's site?** LinkedIn shows the external apply link only to signed-in members, and this Actor does not sign in. `easyApply: false` tells you the job is applied for on the company's site; search the title there, or use [Career Site Jobs](https://apify.com/saliga/career-site-jobs) for direct links.

**The log shows retries.** LinkedIn limits how often one address can ask. The Actor retries from another proxy address automatically. If a run is slow, choose the RESIDENTIAL proxy group under *Advanced*.

**What about Indeed, Glassdoor or the company's own career site?** For jobs straight from company career sites (Greenhouse, Lever, Ashby, Workable, Recruitee, Workday) with salary and a new-jobs monitor, see [Career Site Jobs](https://apify.com/saliga/career-site-jobs).

### Related Actors

- [Career Site Jobs](https://apify.com/saliga/career-site-jobs): jobs straight from company career sites, with a hiring summary per company.
- [Bulk LLM Runner](https://apify.com/saliga/bulk-llm-runner): summarise or classify job descriptions with ChatGPT, Claude or Gemini.
- [Dataset Merge & Dedupe](https://apify.com/saliga/dataset-merge-dedupe): merge LinkedIn and career-site jobs into one clean table and export to CSV or Excel.
- [Tech Stack Detector](https://apify.com/saliga/tech-stack-detector): see which technologies the hiring companies' websites use.

# Actor input Schema

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

One search per line, as you would type it on LinkedIn: data engineer, "product manager" fintech, nurse. Each keyword is searched in every location below.

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

City, region or country as LinkedIn spells it: London, Germany, United States, Remote. Leave empty for worldwide.

## `searchUrls` (type: `array`):

Set up a search on linkedin.com/jobs with all the filters you want, copy the link from the address bar and paste it here. Keywords, location, date, experience, job type, remote and company filters are kept.

## `maxJobsPerSearch` (type: `integer`):

LinkedIn shows at most about 1,000 jobs for one search. To get more, split it: more specific keywords, smaller locations or a shorter date range.

## `postedWithin` (type: `string`):

Only jobs posted in this window.

## `experienceLevels` (type: `array`):

Leave empty for all levels.

## `jobTypes` (type: `array`):

Leave empty for all job types.

## `workplaceTypes` (type: `array`):

Leave empty for all.

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

Numeric LinkedIn company IDs, e.g. 1441 for Google. Easiest: filter by company on linkedin.com/jobs and paste the link above instead.

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

Most recent is best for monitoring.

## `includeJobDetails` (type: `boolean`):

Adds the full description, seniority level, employment type, job function, industries, applicant count, Easy Apply or company site, and salary when shown. Off: faster, card fields only (title, company, location, date, salary on the card).

## `excludeStaffingAgencies` (type: `boolean`):

Every job gets staffingAgency: true/false (from LinkedIn's industry and the company name). On: those jobs are left out and not charged.

## `excludeTitleKeywords` (type: `array`):

e.g. senior, intern, sales. Not charged.

## `excludeCompanies` (type: `array`):

Company names (or parts of names) to leave out. Not charged.

## `outputMode` (type: `string`):

Companies: one row per company with jobs found, jobs posted in the last 7 and 30 days, AI jobs, remote jobs, seniority mix, top locations and sample titles. A ready-made list of who is hiring.

## `onlyNewJobs` (type: `boolean`):

Remembers the jobs it returned and gives only jobs not seen in earlier runs with the same monitor name. Schedule the Actor daily for job alerts. Jobs seen before are not charged.

## `monitorName` (type: `string`):

Keep separate memories, e.g. one per client. Letters, digits and dashes.

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

Apify Proxy is used by default. If you see many retries in the log, choose the RESIDENTIAL group.

## Actor input object example

```json
{
  "keywords": [
    "data engineer"
  ],
  "locations": [
    "United Kingdom"
  ],
  "maxJobsPerSearch": 100,
  "postedWithin": "any",
  "sortBy": "recent",
  "includeJobDetails": true,
  "excludeStaffingAgencies": false,
  "outputMode": "jobs",
  "onlyNewJobs": false,
  "monitorName": "default",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per job (or per company with the Companies output).

## `companies` (type: `string`):

One row per hiring company (Companies output).

## `fullResults` (type: `string`):

Every field, including full descriptions.

# 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": [
        "data engineer"
    ],
    "locations": [
        "United Kingdom"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("saliga/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": ["data engineer"],
    "locations": ["United Kingdom"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("saliga/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": [
    "data engineer"
  ],
  "locations": [
    "United Kingdom"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call saliga/linkedin-jobs-scraper --silent --output-dataset

```

## MCP server setup

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