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

Scrapes LinkedIn job listings with full details: title, company, location, salary, description, employment type, seniority level, and more. Supports keyword search, location filters, date posted, job type, experience level, and automatic pagination.

- **URL**: https://apify.com/codingfrontend/linkedin-jobs-scraper.md
- **Developed by:** [Coding Frontned](https://apify.com/codingfrontend) (community)
- **Categories:** Jobs, Automation, Developer tools
- **Features:** Limited permissions
- **Stats:** 20 total users, 4 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

Search LinkedIn’s public guest jobs endpoint and return normalized, deduplicated job listings. The Actor supports public date, job-type, experience, and workplace filters, bounded pagination, optional detail enrichment, local HTML fixtures, and truthful run diagnostics. It does not require login credentials.

Target: [LinkedIn public jobs](https://www.linkedin.com/jobs/)

### Use cases

- Build a current job-market dataset for a keyword and location.
- Compare public listings by recency, workplace, employment type, or experience level.
- Enrich a bounded result set with public descriptions, criteria, salary text, skills, and benefits.
- Regression-test parsing against synthetic list/detail HTML before a live run.

### Input

The minimum valid input is:

```json
{
  "keywords": "software engineer"
}
```

Supported fields:

| Field | Type | Default / bounds | Description |
| --- | --- | --- | --- |
| `keywords` | string | required, 1–200 chars | Public job-search text. |
| `location` | string | `United States`, 1–200 chars | Location sent to LinkedIn. |
| `maxJobs` | integer | `50`, 1–100 | Maximum unique normal records. |
| `maxPages` | integer | derived, 1–20 | Optional pagination bound. |
| `datePosted` | enum | `anyTime` | `pastMonth`, `pastWeek`, or `past24Hours` are also supported. |
| `jobType` | enum | any | `F` full-time, `P` part-time, `C` contract, `T` temporary, `I` internship, `V` volunteer, `O` other. |
| `experienceLevel` | enum | any | LinkedIn public levels `1`–`6`. |
| `remoteFilter` | enum | any | `1` on-site, `2` remote, `3` hybrid. |
| `scrapeJobDetails` | boolean | `true` | Fetch public job detail HTML for each unique result. |
| `includeDiagnostics` | boolean | `true` | Include minimal diagnostic rows for blocked/empty/failing requests. |
| `requestTimeoutSecs` | integer | `30`, 10–120 | Per-request timeout. |
| `maxRequestRetries` | integer | `2`, 0–5 | Transient HTTP retry limit. |
| `requestDelayMs` | integer | `250`, 0–10000 | Pacing between public endpoint requests. |
| `proxyConfiguration` | object | residential US proxy | Standard Apify proxy configuration; set `{ "useApifyProxy": false }` for a direct local smoke run. |

For local development, `fixtureListHtml` or `fixtureListFiles` enables deterministic list-page mode. `fixtureListFile` is a compatible single-file alias. `fixtureDetailHtml`, `fixtureDetailFiles`, and `fixtureDetailFile` provide detail pages for fixture enrichment. Fixture paths must stay inside this Actor directory and use `.html` or `.htm`.

Example with filters and bounded output:

```json
{
  "keywords": "data engineer",
  "location": "New York",
  "maxJobs": 10,
  "datePosted": "pastWeek",
  "jobType": "F",
  "remoteFilter": "2",
  "scrapeJobDetails": false,
  "includeDiagnostics": true
}
```

### Output

Normal dataset rows contain public business and provenance fields. `jobDescription` is used instead of the platform-reserved `description` field.

| Field | Meaning |
| --- | --- |
| `position`, `jobId`, `jobTitle`, `company`, `location`, `jobUrl` | Stable normalized listing identity and core public fields. |
| `companyUrl`, `companyLogo`, `isRemote`, `postedDate`, `applicantCount` | Public card metadata when available. |
| `salary`, `employmentType`, `seniorityLevel`, `industry`, `jobFunction` | Public detail criteria when available. |
| `jobDescription`, `descriptionBullets`, `benefits` | Public detail content when available. |
| `searchKeywords`, `searchLocation`, `scrapedAt` | Search context and collection provenance. |

The earlier `detailScraped` row field was intentionally removed as extraction instrumentation. Detail request/success/failure counts remain in the `OUTPUT` key-value summary, while business fields are retained.

Diagnostic rows, when enabled, contain only `url`, `error`, `errorCode`, and `scrapedAt`; they never masquerade as job records. The `OUTPUT` key-value record includes success/empty/partial status, normal and diagnostic counts, pagination, detail, deduplication, request, proxy, fixture, and bounded failure evidence.

### Limits and responsible use

Requests are sequential and bounded. Responses larger than 3 MB, access challenges, and malformed public cards are handled fail-closed with summary/diagnostic evidence. LinkedIn job availability and public endpoint behavior change frequently.

Use public job data lawfully and respect LinkedIn terms, rate limits, and applicable privacy and data-protection requirements. Do not provide credentials or attempt to bypass access controls.

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

### Local development

From this Actor directory:

```bash
npm install
npm test
npm run check
apify run --purge --input-file test/inputs/fixture-basic.json
apify run --purge --input-file test/inputs/fixture-detail.json
npm run validate
```

The fixture runs do not contact LinkedIn. A direct public smoke input can use `proxyConfiguration: { "useApifyProxy": false }`; no credentials are required.

# Changelog

This Actor's version history is a separate document: https://apify.com/codingfrontend/linkedin-jobs-scraper/changelog.md

# Actor input Schema

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

Required public job search text.

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

Location sent to LinkedIn's public search endpoint.

## `maxJobs` (type: `integer`):

Maximum unique job records to save.

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

Optional development bound for public pagination.

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

LinkedIn public recency filter.

## `jobType` (type: `string`):

LinkedIn public employment-type filter.

## `experienceLevel` (type: `string`):

LinkedIn public experience-level filter.

## `remoteFilter` (type: `string`):

LinkedIn public on-site, remote, or hybrid filter.

## `scrapeJobDetails` (type: `boolean`):

Request each public job page for description, criteria, salary, skills, and benefits when available.

## `includeDiagnostics` (type: `boolean`):

Write minimal diagnostic rows for blocked pages, empty results, and bounded request/detail failures.

## `requestTimeoutSecs` (type: `integer`):

Bounded timeout for each public endpoint request.

## `maxRequestRetries` (type: `integer`):

Bounded retries for transient HTTP failures.

## `requestDelayMs` (type: `integer`):

Optional pacing between public endpoint requests.

## `fixtureListHtml` (type: `string`):

Local development only: inline synthetic LinkedIn guest list HTML.

## `fixtureListFiles` (type: `array`):

Local development only: HTML files inside this Actor directory, processed as sequential pages.

## `fixtureListFile` (type: `string`):

Legacy-friendly single local list fixture path; use fixtureListFiles for pagination.

## `fixtureDetailHtml` (type: `string`):

Local development only: inline synthetic public job detail HTML reused for each fixture job.

## `fixtureDetailFiles` (type: `array`):

Local development only: HTML files inside this Actor directory, selected in request order.

## `fixtureDetailFile` (type: `string`):

Legacy-friendly single local detail fixture path.

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

Residential US proxy is the safe default for LinkedIn public endpoints.

## Actor input object example

```json
{
  "keywords": "software engineer",
  "location": "United States",
  "maxJobs": 5,
  "maxPages": 6,
  "datePosted": "anyTime",
  "jobType": "",
  "experienceLevel": "",
  "remoteFilter": "",
  "scrapeJobDetails": true,
  "includeDiagnostics": true,
  "requestTimeoutSecs": 30,
  "maxRequestRetries": 2,
  "requestDelayMs": 250,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

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

No description

## `output` (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 = {
    "keywords": "software engineer",
    "location": "United States",
    "maxJobs": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("codingfrontend/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",
    "maxJobs": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("codingfrontend/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",
  "maxJobs": 5
}' |
apify call codingfrontend/linkedin-jobs-scraper --silent --output-dataset

```

## MCP server setup

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