# LinkedIn Jobs Scraper with Cache (`confidential_gnat/linkedin-jobs-scraper`) Actor

Scrape LinkedIn (linkedin.com) job postings without login: title, company, location, posted date, salary, applicants, seniority, employment type, industries and full description. Search by keyword, location and filters or by URL. Export JSON, CSV or Excel.

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

## Pricing

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

![LinkedIn Jobs Scraper cover](https://i.postimg.cc/mk4g31V8/Gemini-Generated-Image-ygjjtlygjjtlygjj.jpg)

**Scrape job postings from LinkedIn (linkedin.com) without login**: title, company, location, posted date, salary, applicants, seniority, employment type, industries and the **full job description**. Search by **keyword, location and filters** or paste a LinkedIn jobs URL, then export as **JSON, CSV or Excel** or call it as an **API**. A built-in cache returns only the **new jobs** on every run, so scheduled runs never pay twice for the same job.

**Target website:** [linkedin.com/jobs](https://www.linkedin.com/jobs/)

### ✨ Features of this LinkedIn jobs scraper

- **Job extraction** — title, company with its LinkedIn page and logo, location, posted date, salary (when the job shows one) and the number of applicants.
- **Full job details** — description as text and HTML, seniority level, employment type, job function and industries.
- **Search by keyword and location** — type job titles and a place, or paste a LinkedIn jobs search URL with its filters.
- **Filters** — date posted, job type, experience level and workplace type (on-site, remote, hybrid).
- **Beyond the 1,000 jobs limit** — LinkedIn shows about 1,000 jobs per search; when you ask for more the actor splits the search by job type, experience level, workplace type and posting date and removes duplicates.
- **Cache for new jobs only** — use the same cache project name on every scheduled run to skip jobs you already scraped and pay only for new ones.
- **Single job URLs** — scrape one job page directly.
- **Proxy support** — uses Apify residential proxies by default because LinkedIn blocks many IPs.
- **No browser required** — plain requests keep runs fast and cheap.

### 🚀 How to scrape LinkedIn jobs in 5 steps

1. [Sign up](https://apify.com/sign-up) for a free Apify account — includes **$5 monthly credit**.
2. Open the actor page and click **Try for free**.
3. Fill in the **Input** fields (a LinkedIn jobs URL, or keywords and a location).
4. Click **Start** and wait for the run to complete.
5. Download results from the **Output** tab in JSON, CSV, or Excel format.

You can also run this actor via the [Apify API](https://docs.apify.com/api/v2) or integrate it directly into your workflows using [Zapier](https://zapier.com/apps/apify), [Make](https://www.make.com/), or [n8n](https://n8n.io/).

### 💰 Pricing for the LinkedIn jobs scraper

This actor uses **pay-per-result** billing based on the compute units a run consumes.

- New Apify accounts include **$5 of free monthly credit**.
- The actor uses plain HTTP requests instead of a browser, so it costs significantly less to run than browser-based scrapers.
- Turning off **Scrape job details** makes runs faster and cheaper: you then get the search result fields only.

### 🔧 LinkedIn jobs scraper input configuration

The input form starts with the LinkedIn URLs, the keywords, the job limit and the cache name. The location, job details switch and filters are grouped as optional settings, and the proxy settings are last.

| Field | Type | Required | Default | Description |
| ----- | ---- | -------- | ------- | ----------- |
| LinkedIn job URLs (`startUrls`) | array | — | a software engineer search in the United States | A LinkedIn jobs search page with its filters, or a single job page. |
| Search keywords (`queries`) | array | — | — | Job titles or keywords, one search each. Uses the location and filters below. |
| Max jobs per search or URL (`maxItems`) | integer | — | 5 | Maximum jobs saved for each start URL or keyword. |
| Cache project name (`cacheProjectName`) | string | — | — | Reuse the same name on every run to get only new jobs. Jobs saved in earlier runs under this name are skipped and do not count towards the limit. |
| Location (`location`) | string | — | — | Where to search for the keywords, for example Berlin, Germany. |
| Scrape job details (`scrapeDetails`) | boolean | — | true | Open each job page for the description, criteria, applicants and salary. |
| Date posted (`datePosted`) | string | — | any time | `past24h`, `pastWeek` or `pastMonth`. |
| Job type (`jobTypes`) | array | — | all | `fullTime`, `partTime`, `contract`, `temporary`, `internship`, `volunteer` or `other`. |
| Experience level (`experienceLevels`) | array | — | all | `internship`, `entry`, `associate`, `midSenior`, `director` or `executive`. |
| Workplace type (`workplaceTypes`) | array | — | all | `onSite`, `remote` or `hybrid`. |
| Proxy configuration (`proxyConfiguration`) | object | — | Apify residential proxy | Residential proxies get the fewest blocked requests; you can switch to datacenter proxies to cut cost. |

**Supported URL types:**

- A search page: `https://www.linkedin.com/jobs/search/?keywords=nurse&location=Texas` (the filters in the address are used)
- A job page: `https://www.linkedin.com/jobs/view/4483550346`

### 🖼️ LinkedIn jobs scraper input screenshot

![LinkedIn Jobs Scraper input form in Apify Console: LinkedIn job URLs, search keywords, location, max jobs per search or URL, scrape job details, date posted, job type and workplace type](https://i.postimg.cc/1twzNr0M/Gemini-Generated-Image-gsrsg2gsrsg2gsrs.jpg)

Numbered labels in the screenshot:

1. **LinkedIn job URLs** — LinkedIn job search pages or single job pages to scrape.
2. **Search keywords** — job titles or keywords to search, one search each.
3. **Location** — the place to search in.
4. **Max jobs per search or URL** — how many jobs to save for each URL or keyword.
5. **Scrape job details** — open each job page to add the full description, seniority, employment type, job function, industries, applicants and salary.
6. **Date posted** — only jobs posted within the chosen period.
7. **Job type** — filter by full-time, part-time, contract and more.
8. **Workplace type** — filter by on-site, remote or hybrid.

### 📦 LinkedIn jobs scraper output data

Every job is one flat record with the keys `id`, `url`, `title`, `companyName`, `companyUrl`, `companyLogo`, `location`, `postedAt`, `postedText`, `salary`, `applicantsText`, `seniorityLevel`, `employmentType`, `jobFunction`, `industries`, `descriptionText`, `descriptionHtml`, `applyUrl`, `source`, `scrapedAt`. Every record has all keys; a value the page does not carry is `null`, for example `salary` when the job shows none. Without **Scrape job details** the description, criteria and applicants are `null`. The dataset has 1 view:

- **Jobs** — a compact table of title, company, location, posted date, employment type, seniority, salary, applicants and the job link.

**Output at a glance:**

| Title | Company | Location | Posted | Type | Seniority | Salary |
| ----- | ------- | -------- | ------ | ---- | --------- | ------ |
| [Software Engineer II (Java/AWS)](https://www.linkedin.com/jobs/view/software-engineer-ii-java-aws-at-jpmorganchase-4476983365) | JPMorganChase | New York, NY | 2026-10-29 | Full-time | Not Applicable | $123,500.00/yr - $150,000.00/yr |
| [(Senior) Data Engineer (m/f/x)](https://de.linkedin.com/jobs/view/senior-data-engineer-m-f-x-at-scalable-capital-4483550346) | Scalable Capital | Berlin, Berlin, Germany | 2026-10-26 | Full-time | Mid-Senior level | — |
| [Junior Data Engineer](https://de.linkedin.com/jobs/view/junior-data-engineer-at-reeeliance-4468608506) | reeeliance | Berlin, Germany | 2026-10-29 | Full-time | Entry level | — |
| [Software Engineer III - Golang](https://www.linkedin.com/jobs/view/software-engineer-iii-golang-at-jpmorganchase-4483303207) | JPMorganChase | Chicago, IL | 2026-10-24 | Full-time | Not Applicable | $114,000.00/yr - $155,000.00/yr |
| [Data Engineer (m/w/d)](https://de.linkedin.com/jobs/view/data-engineer-m-w-d-at-meridian-personal-4483725665) | Meridian Personal | Berlin, Germany | 2026-10-26 | Full-time | Associate | — |

**Sample output (raw JSON):**

```json
[
  {
    "id": "4476983365",
    "url": "https://www.linkedin.com/jobs/view/software-engineer-ii-java-aws-at-jpmorganchase-4476983365",
    "title": "Software Engineer II (Java/AWS)",
    "companyName": "JPMorganChase",
    "companyUrl": "https://www.linkedin.com/company/jpmorganchase",
    "companyLogo": "https://media.licdn.com/dms/image/v2/D4E0BAQGxpntCyRgsuA/company-logo_100_100/company-logo_100_100/0/1718711710850/jpmorganchase_logo?e=2147483647&v=beta&t=kP6Xf9uye25nDGkk4RmP87zYyfNqaQWny7e5o3WyKhI",
    "location": "New York, NY",
    "postedAt": "2026-10-29",
    "postedText": "7 hours ago",
    "salary": "$123,500.00/yr - $150,000.00/yr",
    "applicantsText": "Over 200 applicants",
    "seniorityLevel": "Not Applicable",
    "employmentType": "Full-time",
    "jobFunction": null,
    "industries": "Financial Services",
    "descriptionText": "Job DescriptionYou're ready to gain the skills and experience needed to grow within your role and advance your career — and we have the perfect software engineering opportunity for you.As a Software Engineer II at JPMorganChase within the Trust & Security Team, you are part of an agile team that wor…",
    "descriptionHtml": "<strong>Job Description<br><br></strong>You're ready to gain the skills and experience needed to grow within your role and advance your career — and we have the perfect software engineering opportunity for you.<br><br>As a Software Engineer II at JPMorganChase within the Trust &amp; Security Team, y…",
    "applyUrl": null,
    "source": "https://www.linkedin.com/jobs/search/?keywords=software%20engineer&location=United%20States",
    "scrapedAt": "2026-10-29T17:43:16.745Z"
  }
]
```

### 🔁 Save money: scrape only new LinkedIn jobs with the cache

Scheduled runs usually meet the same jobs again and again, and without a cache you pay for them every time. This actor has a built-in cache that **skips previously scraped jobs, so you pay only for new jobs across multiple runs**.

1. Set **Cache project name** to any name, for example `data-engineer-berlin`.
2. Keep the same name on every run, for example from an [Apify Schedule](https://docs.apify.com/platform/schedules).
3. Each run returns only jobs that were not saved before.

Jobs already saved under the same name are skipped before their job page is opened, and they do not count towards **Max jobs per search or URL**, so each run goes deeper into the results instead of repeating the same jobs. Different names keep separate caches.

### 🐍 How to scrape LinkedIn jobs with Python, JavaScript or the API

Run the actor programmatically with the official Apify clients. Replace `<YOUR_API_TOKEN>` with the token from your [Apify Console](https://console.apify.com/account/integrations).

**Python** (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")

run = client.actor("confidential_gnat/linkedin-jobs-scraper").call(run_input={
    "queries": ["data engineer"],
    "location": "Berlin, Germany",
    "datePosted": "pastWeek",
    "maxItems": 50,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

**JavaScript** (`npm install apify-client`):

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });

const run = await client.actor('confidential_gnat/linkedin-jobs-scraper').call({
    queries: ['data engineer'],
    location: 'Berlin, Germany',
    datePosted: 'pastWeek',
    maxItems: 50,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

**cURL** — start a run and wait for the dataset:

```bash
curl -X POST "https://api.apify.com/v2/acts/confidential_gnat~linkedin-jobs-scraper/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"queries": ["data engineer"], "location": "Berlin, Germany", "datePosted": "pastWeek", "maxItems": 50}'
```

### 💡 What you can use LinkedIn jobs data for

- Tracking hiring demand for roles, skills and locations over time.
- Salary benchmarking from the jobs that publish a pay range.
- Lead generation: finding companies that are hiring and who they hire.
- Building job boards and alerts for a niche, city or industry.
- Labour market research on seniority, employment type and remote work.

The data is typically used by recruiters, staffing agencies, HR analysts, job boards, sales teams and market researchers.

### ⚠️ Limitations of the LinkedIn jobs scraper

- **About 1,000 jobs per search** — LinkedIn shows no more per search; the actor splits larger requests by filters, which needs more requests and proxy traffic.
- **Public data only** — everything behind a LinkedIn login (applicant profiles, recruiter details, saved jobs) is out of reach.
- **Salary and apply link** — salary is only filled when the job shows a pay range, and the external apply link is not always available.
- **Blocked IPs** — LinkedIn blocks many IPs, so the actor retries on new ones; very large runs may need residential proxies.

### ❓ LinkedIn jobs scraper FAQ

#### Can I scrape LinkedIn legally?

The actor only collects job postings that are already publicly visible on LinkedIn, with no login, paywall or private content. Scraping publicly available data is generally considered lawful (see *hiQ Labs v. LinkedIn*), but LinkedIn's Terms of Service restrict automated access, so you are responsible for complying with them and with applicable laws such as GDPR and CCPA.

#### What data does the LinkedIn jobs scraper return?

Each job has its title, company with page and logo, location, posted date, salary when shown and the applicants text. With **Scrape job details** on you also get the description as text and HTML, seniority level, employment type, job function and industries.

#### How many jobs can I scrape from one LinkedIn search?

**Max jobs per search or URL** limits the saved jobs for each start URL or keyword. LinkedIn shows about 1,000 jobs per search; above that the actor splits the search by job type, experience level, workplace type and posting date to reach more.

#### Is this the cheapest LinkedIn jobs scraper actor?

Possibly yes. It uses plain HTTP requests instead of a browser, and its built-in cache skips jobs you already scraped, so across multiple runs you pay only for new jobs. Set a **Cache project name** and keep it the same on every run to get this saving.

#### Do I need a proxy to scrape linkedin.com?

Yes, a proxy is needed: LinkedIn blocked requests from a single home or office IP after a few pages. The input defaults to Apify residential proxies, which get the fewest blocked requests. You can switch to datacenter proxies in the proxy settings to lower the cost, but more requests may be blocked.

#### How do I scrape LinkedIn jobs with Python?

Use the Python example above: it starts the actor with your input and iterates over the dataset items.

#### Can I run this LinkedIn jobs scraper on a schedule?

Yes. Create an Apify Schedule for the actor and set a **Cache project name**, so every run returns only the jobs it has not saved before. You can also set **Date posted** to past 24 hours to narrow the search.

#### What output formats are supported?

JSON, CSV, Excel, XML and RSS, either from the **Output** tab or through the Apify API.

#### Why is the salary empty for most LinkedIn jobs?

LinkedIn only shows a pay range for jobs where the employer or the local law provides one, so most jobs return `null` for `salary`.

### 🔗 Relevant actors for job data

| Scraper | Description |
| ------- | ----------- |
| [💼 Dice Jobs Scraper](https://apify.com/confidential_gnat/dice-jobs-scraper) | Tech job listings from Dice by keyword or URL. |
| [🇩🇪 XING Jobs Scraper](https://apify.com/confidential_gnat/xing-jobs-scraper) | Job listings from XING Jobs in Germany: title, company, location and more. |
| [☕ HiringCafe Jobs Scraper](https://apify.com/confidential_gnat/hiringcafe-jobs-scraper) | Job listings from HiringCafe by keyword or URL. |
| [📧 Decision Maker Email Finder](https://apify.com/confidential_gnat/decision-maker-email-finder) | Find decision makers, founders and executives at any company website. |

### 🔗 Other actors you may find useful

| Scraper | Description |
| ------- | ----------- |
| [🥾 AllTrails Scraper — Hiking, Biking & Running Trails](https://apify.com/confidential_gnat/alltrails-scraper) | Hiking, biking and running trails by park, city or state. |
| [📌 Pinterest Pins, Boards & Profiles Scraper](https://apify.com/confidential_gnat/pinterest-pins-scraper) | Pins, videos, boards and profiles from Pinterest searches and URLs. |
| [🔮 Kalshi Markets Scraper](https://apify.com/confidential_gnat/kalshi-markets-scraper) | Prediction market prices, implied probability and volume from Kalshi. |
| [🍷 Vivino Wine Scraper](https://apify.com/confidential_gnat/vivino-wine-scraper) | Wine data from Vivino: name, winery, vintage and ratings. |
| [🛍️ Shopify App Store Scraper](https://apify.com/confidential_gnat/shopify-app-store-scraper) | Apps from the Shopify App Store: name, rating, reviews and pricing. |

### 💬 Support & contact

If you encounter any issues or have questions, please [open an issue](https://apify.com/confidential_gnat/linkedin-jobs-scraper/issues/open).

You can also find more of our actors on the [Actor Flow](https://apify.com/confidential_gnat) page.

# Actor input Schema

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

A LinkedIn jobs search page (https://www.linkedin.com/jobs/search/?keywords=nurse\&location=Texas) with its filters, or a single job page (https://www.linkedin.com/jobs/view/4483550346).

## `queries` (type: `array`):

Job titles or keywords to search, one search each, for example data engineer. Uses the location and filters below.

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

Maximum jobs saved for each start URL or keyword. LinkedIn shows about 1,000 jobs per search, so above that the actor splits the search by job type, experience level, workplace type and posting date.

## `cacheProjectName` (type: `string`):

Reuse the same name on every scheduled run to get only new jobs: jobs saved in earlier runs under this name are skipped and do not count towards the limit.

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

Where to search for the keywords, for example Berlin, Germany or United States.

## `scrapeDetails` (type: `boolean`):

Open each job page to add the full description, seniority level, employment type, job function, industries, applicants and salary. Turn off for a faster run with the search result fields only.

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

Only jobs posted within this time. Applies to the keyword searches.

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

Only these job types. Empty means all.

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

Only these experience levels. Empty means all.

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

Only on-site, remote or hybrid jobs. Empty means all.

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

LinkedIn blocks many IPs, so a proxy is needed. Residential proxies are used by default; they cost more than datacenter proxies but get far fewer blocked requests.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.linkedin.com/jobs/search/?keywords=software%20engineer&location=United%20States"
    }
  ],
  "maxItems": 5,
  "scrapeDetails": true,
  "datePosted": "",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `overview` (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 = {
    "startUrls": [
        {
            "url": "https://www.linkedin.com/jobs/search/?keywords=software%20engineer&location=United%20States"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("confidential_gnat/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 = {
    "startUrls": [{ "url": "https://www.linkedin.com/jobs/search/?keywords=software%20engineer&location=United%20States" }],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("confidential_gnat/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 '{
  "startUrls": [
    {
      "url": "https://www.linkedin.com/jobs/search/?keywords=software%20engineer&location=United%20States"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call confidential_gnat/linkedin-jobs-scraper --silent --output-dataset

```

## MCP server setup

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