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

LinkedIn Jobs Scraper — Extract LinkedIn job listings including job titles, company names, locations, salary details, employment types, experience levels, descriptions, posting dates, and job URLs. Useful for recruitment research, job market analysis, hiring insights, and lead generation.

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

## Pricing

from $2.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 — Titles, Salaries, Descriptions and Applicants

LinkedIn Jobs Scraper collects public LinkedIn job postings: job title, company, location, salary, applicant count, employment type, experience level and the full description. Every response is structured JSON — ready to pass directly to an LLM, index into a vector store, or feed a hiring-intelligence pipeline. **No LinkedIn account or login needed**: list companies by name, link or ID, or run a keyword and location search, then narrow results by date posted, job type and experience level. Start with one company, then track hiring across every account you sell to.

***

### What data can I extract with LinkedIn Jobs Scraper?

Using this LinkedIn Jobs API, you will be able to extract the following LinkedIn job posting data:

| 🆔 Job ID | 📝 Job title | 🏢 Company name | 📍 Location |
|---|---|---|---|
| 💰 Salary (when posted) | 📅 Date posted | 🕒 Posted (relative time) | 👥 Applicant count |
| 📊 How to read the applicant count | 💬 Applicant line (as shown on LinkedIn) | 💼 Employment type | 🎓 Experience level |
| 🏷️ Job function (rarely filled in) | 🏭 Industry | 🎁 Benefits mentioned | 🔘 Apply type (Easy Apply or company site) |
| 🚪 Apply link (when public) | 🔗 Job page link | 🏢 Company page link | 🆔 Company ID |
| 👤 Job poster name | 🔗 Job poster profile | 📄 Description (text) | 🧾 Description (HTML) |
| ⏱️ Saved at (UTC) | | | |

***

### How to use LinkedIn Jobs Scraper

Recruiters, sales teams and job-market researchers use it to pull a clean, structured feed of LinkedIn job postings from one run, without writing a single line of scraping code.

**Copy to your AI assistant:**

```text
This Actor returns public LinkedIn job postings as structured JSON: job title, company name, location, salary, employment type, experience level, applicant count and the full job description. Use it whenever someone needs LinkedIn job postings without cookies, a login, or a browser - tracking which companies are hiring this week, building a job board or alert feed, or feeding postings into a hiring-intelligence pipeline for a recruiting or sales team. Inputs: companyInput (array of strings - a company name, LinkedIn company link or numeric company ID per line; leave empty to run a keyword and location search instead), keywords (string, job title or keywords), location (string, default "United States"), geoId (string, a numeric LinkedIn region id), maxJobs (integer 1-1000, default 20, applied per company or per the whole search), sortOrder ("" default | "relevance" | "date" for most recent first), publishedAt ("" any time | "r86400" past 24 hours | "r604800" past week | "r2592000" past month), workType ("" any | "1" on-site | "2" remote | "3" hybrid), contractType ("" any | "F" full-time | "P" part-time | "C" contract | "T" temporary | "I" internship | "V" volunteer), experienceLevel ("" any | "1" internship | "2" entry level | "3" associate | "4" mid-senior | "5" director | "6" executive), proxyConfiguration (object, Apify Proxy settings). LinkedIn's own public job search caps a single query at around 1,000 results; this Actor keeps searching further automatically so maxJobs is still respected on larger searches.
```

#### LinkedIn Jobs Scraper MCP Server: use these Actors from ChatGPT, Claude or Cursor

Point your AI assistant at Apify's MCP server and it can find and run this Actor on its own, searching LinkedIn job postings mid-conversation without any glue code in your prompts.

```bash
claude mcp add --transport http apify "https://mcp.apify.com"
```

#### Step by step

1. [Create a free Apify account](https://console.apify.com/sign-up).
2. Open it in the Apify Store.
3. Enter the LinkedIn companies you want (name, link or ID), or a keyword and location.
4. Click **Start** (or send your API request).
5. Download or stream your results in JSON, CSV or Excel.

#### How to scale LinkedIn Jobs Scraper to bulk

List every company you want to track in the companies field, one per line — all of them are searched in the same run, each capped by its own maximum-jobs limit. For ongoing monitoring, schedule the same run daily or weekly with the date-posted filter set to past 24 hours or past week so only new postings keep coming in, or trigger runs from your own code with the Apify API and loop over a longer company list across several calls.

***

### ✨ Features

LinkedIn Jobs Scraper fetches clean, structured job postings from LinkedIn. It's ideal for hiring-signal tracking for sales, recruiting research, job-market analysis, and running a linkedin company jobs scraper against a whole target-account list, building a LinkedIn job search by company into your own tools.

It extracts, per job posting:

- **Job title and company** – the role and who's hiring, with a link to the company's LinkedIn page
- **Salary** – LinkedIn's own pay range when posted, or one found written in the description
- **Applicant count** – how many people applied, and whether that number is exact, "over" or "fewer than"
- **Employment type and experience level** – checked against the posting's own criteria, not LinkedIn's unreliable public search filters
- **Full description** – as plain text and as HTML, plus any benefits mentioned in it
- **Apply details** – Easy Apply or company website, with the apply link when LinkedIn shows one publicly

⚡ Jobs save to the dataset the moment each posting is read, so the output table fills while the run is still going.

***

### Use cases 💡

- **Sales team** — use it as a linkedin hiring data scraper to see who's hiring this week.
- **Recruiter** — track competitors' open roles and how many people apply to each.
- **Market analyst** — run it as a linkedin salary data scraper across companies and cities.
- **Job board builder** — run a daily keyword search with date posted set to the past 24 hours.
- **AI agent builder** — feed postings into a vector store with a linkedin job description scraper.

Building an AI agent? [Connect LinkedIn Jobs Scraper over MCP](#linkedin-jobs-scraper-mcp-server-use-these-actors-from-chatgpt-claude-or-cursor) and let it call the actor on its own.

***

### Why choose this actor?

- **Jobs saved the moment they're read.** A recorded run on one company ("Google", up to 8 jobs) saved all 8 in about 4.5 seconds, and a keyword and location search ("Data Analyst" in Berlin, up to 5 jobs) saved all 5 in about 4.3 seconds — in both runs, every row landed in the dataset within half a second of the next.
- **One company name, three ways in.** A name, a LinkedIn company link or a numeric company ID are all accepted in the same list, and an unmatched name automatically falls back to a keyword search scoped to that company so a typo doesn't return zero jobs.
- **25 fields per job, checked against the posting itself.** Employment type and experience level are matched against each job's own criteria rather than LinkedIn's public search filters, so this linkedin job listings extractor only returns jobs that really are full-time and entry level when you ask for "Full-time, Entry level".

***

### ⬇️ Input

Give it one or more companies (by name, LinkedIn link or numeric ID) in the companies field, or leave it empty and set the job keywords and location fields instead. No field is required — an empty run falls back to the default keyword search.

| Parameter | Required | Type | Description | Example |
| --- | --- | --- | --- | --- |
| `companyInput` | No | Array | Company names, LinkedIn company links or numeric IDs, one per line; empty runs a keyword and location search instead | `["Google", "1035"]` |
| `keywords` | No | String | Job title or keywords; narrows a company's jobs, or is the whole search with no company (default `Software Engineer`) | `"Data Analyst"` |
| `location` | No | String | Where the jobs are based (default `United States`) | `"Berlin"` |
| `geoId` | No | String | Optional numeric LinkedIn region ID | `"101282230"` |
| `maxJobs` | No | Integer | Max jobs saved per company, or for the whole search, 1-1000 (default 20) | `15` |
| `sortOrder` | No | String | `""` LinkedIn's order, `"relevance"`, or `"date"` for most recent first | `"date"` |
| `publishedAt` | No | String | `""` any time, `"r86400"` past 24 hours, `"r604800"` past week, `"r2592000"` past month | `"r604800"` |
| `workType` | No | String | `""` any, `"1"` on-site, `"2"` remote, `"3"` hybrid (LinkedIn doesn't apply this to public searches) | `""` |
| `contractType` | No | String | `""` any, `"F"` full-time, `"P"` part-time, `"C"` contract, `"T"` temporary, `"I"` internship, `"V"` volunteer | `"F"` |
| `experienceLevel` | No | String | `""` any, `"1"` internship, `"2"` entry level, `"3"` associate, `"4"` mid-senior, `"5"` director, `"6"` executive | `"2"` |
| `proxyConfiguration` | No | Object | Apify Proxy settings | `{"useApifyProxy": false}` |

#### Example input

```json
{
  "companyInput": [],
  "keywords": "Data Analyst",
  "location": "Berlin",
  "geoId": "101282230",
  "maxJobs": 5,
  "sortOrder": "",
  "publishedAt": "",
  "workType": "",
  "contractType": "",
  "experienceLevel": "",
  "proxyConfiguration": {"useApifyProxy": false}
}
```

***

### ⬆️ Output

Every job posting is one typed, normalized JSON item with the same field names on every run — nothing is skipped silently, and a field LinkedIn doesn't show for a posting stays `null`. Export LinkedIn jobs to CSV, Excel or JSON (the default) straight from the Console or the API. A real row from the example input above, description shortened:

#### Example output

```json
{
  "id": "4471617910",
  "publishedAt": "2026-09-24",
  "salary": null,
  "title": "Senior Data Analyst",
  "jobUrl": "https://de.linkedin.com/jobs/view/senior-data-analyst-at-cosuno-4471617910?trk=public_jobs_topcard-title",
  "companyName": "Cosuno",
  "companyUrl": "https://de.linkedin.com/company/cosuno?trk=public_jobs_topcard-org-name",
  "location": "Berlin, Berlin, Germany",
  "postedTime": "1 week ago",
  "applicationsCount": "200",
  "applicantsCountType": "at_least",
  "applicantsText": "Over 200 applicants",
  "description": "Your mission We're a small data team with a big job: helping everyone at Cosuno make better decisions. Our data platform is stable and in good hands. What we need now is someone who takes our most important, open-ended business questions and answers them properly …",
  "contractType": "Full-time",
  "experienceLevel": "Not Applicable",
  "workType": null,
  "sector": "Construction",
  "applyUrl": null,
  "applyType": "EXTERNAL",
  "descriptionHtml": "<div class=\"show-more-less-html__markup show-more-less-html__markup--clamp-after-5 relative overflow-hidden\"><strong>Your mission<br><br></strong>We're a small data team with a big job: helping everyone at Cosuno make better decisions. …</div>",
  "companyId": "12601870",
  "benefits": "bonus",
  "posterProfileUrl": null,
  "posterFullName": null,
  "scrapedAt": "2026-10-08T08:51:55Z"
}
```

***

### How does it work?

This actor is built to scrape LinkedIn job postings the same way a signed-out visitor's browser would: it reads the same public job-search and job-detail pages the LinkedIn site loads — plain HTTP requests, no browser. Requests go through rotating proxies, and the run automatically retries and switches to a residential proxy when LinkedIn blocks a request, so a block on one request doesn't fail the job or the run. Only publicly visible data is returned: what anyone can see on a LinkedIn job page or in LinkedIn's public job search without an account. The output schema is normalized and stays the same shape even when LinkedIn redesigns its pages, so your integration doesn't need to change when LinkedIn does. When a single search would otherwise hit LinkedIn's own result cap, the run keeps searching further on its own so your maximum-jobs setting is still respected.

***

### How do you integrate LinkedIn Jobs Scraper into your stack?

Think of it as a linkedin job postings api you can call from any stack: a REST API from any language, MCP for AI agents, and no-code automation tools.

#### Using LinkedIn Jobs Scraper with the Apify API

Once this Actor is live in your account, any language that can send an HTTP request can call it — POST your input JSON to its `run-sync-get-dataset-items` endpoint with your Apify API token, then read the job rows straight back from the response body. The same call works from Python, Go, Ruby, Node.js or plain cURL; the official `apify-client` package wraps it for Python and JavaScript if you prefer a typed client over raw HTTP.

*Works in Go, Ruby, Node.js, cURL — any language that can make an HTTP request.*

#### MCP integration for AI agents

```bash
claude mcp add --transport http apify "https://mcp.apify.com"
```

This registers Apify's MCP server as a tool source your agent can call directly: it searches the Apify Store for LinkedIn Jobs Scraper, adds it as a tool, and runs it for a company list or a keyword search without you writing any scraping logic or input-schema glue code. Compatible with Claude Code, Cursor and Windsurf, and any other MCP client that supports Streamable HTTP servers.

#### No-code tools (n8n, Make, LangChain)

In n8n, use the Apify node's "Run an Actor" action with this Actor and your input JSON, or an HTTP Request node pointed at the run-sync endpoint with your API token. In Make, the Apify app's "Run an Actor" module followed by "Get Dataset Items" gives you the same job rows inside a scenario. In LangChain, `langchain-apify`'s `ApifyDatasetLoader` loads a finished run's dataset straight into documents you can hand to a chain or a retriever.

***

### Is it legal to scrape LinkedIn jobs?

Scraping publicly available data is generally lawful in most jurisdictions, although LinkedIn's own User Agreement restricts automated access to its site. LinkedIn Jobs Scraper returns only job pages that any visitor can open without signing in — nothing behind a login wall. Job poster names and profile links, where a posting shows one, can count as personal data under GDPR and similar laws, so storing and using them needs a lawful basis under your local data-protection rules. Consult legal counsel if your use case involves bulk storage of personal data.

***

### Frequently asked questions

#### What fields does LinkedIn Jobs Scraper return?

Job title, company name, location, salary and the full job description are the top fields — see [the data fields section](#what-data-can-i-extract-with-linkedin-jobs-scraper) for the complete list, including applicant counts, employment type, experience level and apply details.

#### Does LinkedIn Jobs Scraper require a LinkedIn account or login?

No. Only public job posting data is extracted, and no LinkedIn credentials are needed at any point.

#### How fast does LinkedIn Jobs Scraper run?

A recorded run searching one company ("Google", up to 8 jobs) saved all 8 jobs in about 4.5 seconds, and a keyword and location search ("Data Analyst" in Berlin, up to 5 jobs) saved all 5 in about 4.3 seconds. Every run reads live data — nothing is cached.

#### What happens if a job is no longer listed or a company doesn't match?

A job that LinkedIn no longer lists is skipped without being charged, and named in the run's log. A company name that doesn't match a LinkedIn company falls back automatically to a keyword search scoped to that company name; if that still finds nothing, the company is named in the log and the run's status message while the rest of the run carries on.

#### Can I scrape multiple LinkedIn companies or searches at once?

Yes. List every company you want in the companies field, one per line — all of them run in the same job, each capped by its own maximum-jobs limit, so a single run can cover an entire list of target accounts.

#### Does LinkedIn Jobs Scraper work with Claude, ChatGPT and other AI agent tools?

Yes — it's reachable through Apify's MCP server. Run `claude mcp add --transport http apify "https://mcp.apify.com"` to register it as a tool in Claude Code, Cursor or Windsurf. Any agent that can call an HTTP endpoint can also use the REST API directly.

#### Does LinkedIn Jobs Scraper return data in a format LLMs can use directly?

Yes. Every job posting comes back as typed, normalized JSON with consistent field names and no HTML parsing required for the plain-text fields. Pass it straight to an LLM, index it into a vector store, or feed it to an agent tool with no transformation step.

#### What happens when LinkedIn changes its layout or anti-bot system?

The actor is actively maintained. When LinkedIn changes how its pages work, the actor is updated to match — your calls keep returning the same JSON schema with no changes needed on your end.

#### Can I use LinkedIn Jobs Scraper without managing proxies or browser infrastructure?

Yes. Proxy rotation runs on the actor's side — plain HTTP requests, retried and switched to a residential proxy automatically when LinkedIn blocks one. You send one request and get structured job data back, with no proxy accounts or browser setup to maintain.

#### Which LinkedIn job fields work best for AI training data and RAG indexing?

For RAG indexing, the full job description, job title and company name carry the most context. For structured training data, the applicant count, employment type, experience level and salary are the most consistent fields across postings. All fields come back as typed primitives — strings, integers, booleans — so no normalization is required.

***

### Your feedback

Found a bug or missing a field? Let us know through the Actor's feedback channel so it can be fixed. Every report is read, and fixes ship as LinkedIn's own pages keep changing.

# Actor input Schema

## `companyInput` (type: `array`):

One per line: a company name (Google), a LinkedIn company link (https://www.linkedin.com/company/google/) or a numeric LinkedIn company ID (1441). Names separated by commas or the word "and" on one line are searched as separate companies, so write "Procter & Gamble" rather than "Procter and Gamble". A name is first matched to its LinkedIn company; when no match is found, the run searches the name as a keyword and keeps only jobs of that company. All companies are searched at the same time. Leave empty to run one keyword and location search instead.

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

Job title or keywords, e.g. Software Engineer or Data Analyst. With companies, only that company's jobs matching these keywords are returned. Leave empty for all jobs.

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

Where the jobs are based, e.g. United States, London or Berlin: anything LinkedIn's job search understands. Empty means United States.

## `geoId` (type: `string`):

Optional numeric LinkedIn location ID sent with the search. Pick a country from the list, or paste any geoId number copied from a LinkedIn job search link (the part after geoId=). Leave empty to search by Location only. Values that are not numbers are ignored and the run log says so.

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

Maximum jobs saved for each company, or for the whole search when no company is given (1-1000), counted after the job type and experience filters. A company with fewer matching jobs gives all it has. A search that reaches LinkedIn's limit of about 1000 results is split by date posted (and by US state for United States searches without a geoId) to read further. Free plan users get up to 20 jobs per input and 200 items per month; paid plans have no limit.

## `sortOrder` (type: `string`):

Default and Most relevant use LinkedIn's own order. Most recent first searches the newest jobs first (past hour, then past 6 hours, 24 hours, 3 days, week, 2 weeks and month, within the Date posted filter), so the jobs saved are the most recently posted ones. Jobs are saved as soon as they are read, so rows in the dataset are not strictly ordered by date.

## `publishedAt` (type: `string`):

Only jobs posted within this time window. Choose Any time to turn it off.

## `workType` (type: `string`):

Passed to LinkedIn's search, but LinkedIn does not apply this filter to public job searches and job pages carry no on-site or remote field, so it cannot be checked per job and results can include every work arrangement. The run log repeats this note when the filter is set.

## `contractType` (type: `string`):

Only jobs with this employment type. Checked against each job's own employment type; jobs that don't match are skipped and not charged. Choose Any to turn it off.

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

Only jobs with this seniority level. Checked against each job's own seniority level; jobs that don't match (including jobs marked Not Applicable) are skipped and not charged. Choose Any to turn it off.

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

With Apify Proxy on, every request goes through it (the residential group when no group is chosen, or Apify's default proxy when your plan has no residential access; US unless you pick a country). With it off, requests start on a direct connection and the run switches to the residential proxy as soon as LinkedIn blocks it. If the proxy refuses the connection, the run continues directly.

## Actor input object example

```json
{
  "companyInput": [
    "Google"
  ],
  "keywords": "Software Engineer",
  "location": "United States",
  "geoId": "",
  "maxJobs": 20,
  "sortOrder": "",
  "publishedAt": "",
  "workType": "",
  "contractType": "",
  "experienceLevel": "",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped jobs, one row per job posting. Rows appear while the run goes on.

# 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 = {
    "companyInput": [
        "Google"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("socialdataapi/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 = {
    "companyInput": ["Google"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("socialdataapi/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 '{
  "companyInput": [
    "Google"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call socialdataapi/linkedin-jobs-scraper --silent --output-dataset

```

## MCP server setup

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