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

LinkedIn jobs scraper: export public job postings from any LinkedIn jobs search URL with title, company, location, salary and date, plus optional full description and company details. No login.

- **URL**: https://apify.com/keklik/linkedin-jobs-scraper.md
- **Developed by:** [Keklik Technologies](https://apify.com/keklik) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.17 / 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.
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** lets you **scrape LinkedIn job postings** and export them to JSON, CSV or Excel: **job title, company, location, date posted, salary, full description, seniority, employment type, industries, applicant count, apply type and the recruiter who posted it**, plus optional **company details** such as website, size and headquarters. Paste a LinkedIn job search URL or type a job title and a location, press Start, and get **one row per job**. **No LinkedIn account, no login and no cookies** are needed.

### What data can you extract from LinkedIn Jobs?

Each job becomes one row with up to 42 fields:

| Group | Fields |
|---|---|
| **Job** | Job ID, job URL, title, location, date posted, "posted 3 days ago", highlight ("Actively Hiring") |
| **Company** | Company name, LinkedIn page, logo, company ID |
| **Salary** | Salary as shown, plus min, max, currency and period (year, month, hour) |
| **Full job details** | Description as text and HTML, seniority level, employment type, industries, applicant count, apply type (Easy Apply or external) |
| **Job poster** | Name, headline, profile URL and photo of the recruiter, when LinkedIn shows them |
| **Company details** | Website, industry, size band, employees on LinkedIn, followers, founding year, headquarters, type, specialties, description, tagline |

### Use cases

- **Job market research**: track how many jobs a role, skill or city has, and how salaries move.
- **Recruiting and sales leads**: find companies hiring for a role, with their size, website and the recruiter who posted it.
- **Job boards and aggregators**: feed fresh LinkedIn jobs into your own site with a daily scheduled run.
- **Competitor tracking**: watch which roles your competitors are hiring for.
- **Personal job search**: get every new job for your search in a spreadsheet instead of scrolling.

### How to scrape LinkedIn jobs

1. Open **LinkedIn Jobs Scraper** on Apify and click **Try for free**.
2. Search for jobs on [linkedin.com/jobs](https://www.linkedin.com/jobs/search), set the filters you want, and copy the URL from your browser. Or skip that and type job titles and a location in the input.
3. Paste the URL into **LinkedIn job search or job URLs**. Add more URLs, one per line, for more searches.
4. Leave **Full job details** on if you want descriptions; turn on **Company details** if you want each company's website and size.
5. Click **Start**. 100 jobs with full details take about a minute.
6. Open the **Output** tab and download the results as JSON, CSV, Excel, XML or HTML, or fetch them with the Apify API.

### Input

| Field | What it does |
|---|---|
| **LinkedIn job search or job URLs** | A search URL from linkedin.com/jobs/search (keywords, location and filters included), or a single job URL (linkedin.com/jobs/view/...). |
| **Job titles or keywords** + **Location** | Another way to search: each keyword is its own search in that location. |
| **Date posted** | Past 24 hours, past week or past month. |
| **Workplace**, **Job type**, **Experience level** | Remote, full-time, entry level and so on. See [the note on filters](#do-all-linkedin-filters-work). |
| **Easy Apply only**, **Fewer than 10 applicants** | LinkedIn's own filters. |
| **Posted since** | Only jobs posted since `12h`, `3d`, `2w` ago, or since a date such as `2026-10-01`. Handy for daily runs. |
| **Skip job titles containing**, **Skip companies** | Drop jobs you don't want. Skipped jobs are free. |
| **Full job details** | Opens each job for the description and the rest of the "Full job details" fields. On by default. |
| **Company details** | Adds the hiring company's details from its LinkedIn page. Off by default. |
| **Max jobs per search**, **Max jobs in total** | Stop early. LinkedIn shows at most 1,000 jobs per search. |

```json
{
    "urls": ["https://www.linkedin.com/jobs/search?keywords=Software%20Engineer&location=United%20States&f_TPR=r604800"],
    "searchTerms": ["data analyst"],
    "location": "London",
    "datePosted": "pastWeek",
    "jobDetails": true,
    "companyDetails": false,
    "maxJobsPerSearch": 100
}
```

### Output

A row from a real run, with the description shortened:

```json
{
    "job_id": "4476590411",
    "url": "https://www.linkedin.com/jobs/view/4476590411",
    "title": "Data Analyst",
    "company_name": "Searchability NS&D",
    "company_url": "https://www.linkedin.com/company/searchability-ns-d",
    "location": "London Area, United Kingdom",
    "posted_at": "2026-10-12",
    "posted_time_ago": "1 week ago",
    "salary": "£37,000.00/yr - £60,000.00/yr",
    "description": "New Permanent Opportunity for a Security Cleared Data Analyst\n• Must have active SC Clearance\n• Mid to Senior levels available …",
    "seniority_level": "Mid-Senior level",
    "employment_type": "Full-time",
    "industries": "Data Infrastructure and Analytics and IT Services and IT Consulting",
    "applicants_count": 200,
    "apply_type": "easy_apply",
    "salary_min": 37000.0,
    "salary_max": 60000.0,
    "salary_currency": "GBP",
    "salary_period": "year",
    "poster_name": "Dillon Lewis",
    "poster_title": "Recruitment Consultant at Searchability NS&D",
    "company_id": "86641560",
    "company_website": "https://linktr.ee/searchability",
    "company_industry": "Staffing and Recruiting",
    "company_size": "11-50 employees",
    "company_employees_count": 21,
    "company_followers_count": 45696,
    "company_headquarters": "Manchester",
    "company_type": "Privately Held",
    "company_specialties": ["IT Recruitment", "National Security", "Recruitment", "SC Clearance", "DV Clearance"],
    "source_url": "https://www.linkedin.com/jobs/view/4476590411",
    "scraping_time": "2026-10-19T19:08:27+00:00"
}
```

A few fields worth knowing:

- **`applicants_count`** is a floor: LinkedIn shows "Over 200 applicants" as the most, which gives `200`.
- **`salary`** is only filled when the employer published one. In our tests between 1 job in 10 (US) and 1 in 4 (UK) had a salary.
- **`poster_name`** and the other poster fields are filled only when LinkedIn shows who posted the job. That varies a lot: about 1 job in 3 in a London search, almost none in a US one.
- **`search_keywords`** shows the exact keywords the search ran with, including any words added by the Workplace, Job type or Experience level filters.

The **Output** tab has an **Overview** view. You can export the dataset to **JSON, CSV, Excel, XML and HTML**.

### How much does it cost to scrape LinkedIn jobs?

LinkedIn Jobs Scraper uses **pay-per-event pricing**: you pay only for the jobs you get and the extras you turn on.

| Event | Free plan | Bronze | Silver | Gold |
|---|---|---|---|---|
| Job | $0.25 | $0.22 | $0.20 | $0.17 |&#x20;
| Full job details | $0.13 | $0.12 | $0.10 | $0.09 |&#x20;
| Company details | $0.50 | $0.45 | $0.40 | $0.35 |&#x20;

Prices are per 1,000 events.&#x20;

For example, 1,000 jobs with full details cost $0.38 on the Free plan and $0.26 on Gold.  Jobs removed by filters, and extras LinkedIn didn't return, are free. The Apify Free plan's monthly credits let you try the scraper before you pay.

### Integrations and API

You can run LinkedIn Jobs Scraper from your own code with the **Apify API**.

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("keklik/linkedin-jobs-scraper").call(
    run_input={"searchTerms": ["data analyst"], "location": "London", "maxJobsPerSearch": 100}
)
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], job["company_name"], job["salary"])
```

**Node.js**

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('keklik/linkedin-jobs-scraper').call({
    searchTerms: ['data analyst'],
    location: 'London',
    maxJobsPerSearch: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((job) => [job.title, job.company_name]));
```

You can also:

- **Schedule** a daily run with **Posted since** set to `1d` to get only new jobs.
- Use **webhooks** to get notified, or trigger your own pipeline, when a run finishes.
- Connect the results to **Make, Zapier, Google Sheets**, Airbyte and other tools through Apify integrations.
- Give AI agents access through the **Apify MCP server**, so Claude, ChatGPT or Cursor can search LinkedIn jobs for you.

### FAQ

#### Is it legal to scrape LinkedIn jobs?

This scraper collects only job postings that LinkedIn shows publicly to visitors who are not logged in. Some fields, such as the job poster's name, are personal data, which laws such as the GDPR and CCPA protect. Make sure you have a lawful reason to collect and use it. If you are unsure, ask a lawyer.

#### Do I need a LinkedIn account?

No. You don't need a LinkedIn account, a login or cookies, and the scraper never uses yours.

#### How many jobs can I get from one search?

LinkedIn shows at most 1,000 jobs per search, logged in or not. To get more, split the search: one search per city instead of one per country, or one per keyword. Each search URL or keyword in the input is its own search, and a job found by two searches is saved once.

#### Do all LinkedIn filters work?

Date posted, Easy Apply, Fewer than 10 applicants, company and location filters work as on LinkedIn. **Workplace (remote, hybrid), Job type and Experience level don't**: LinkedIn ignores them for logged-out visitors. The scraper adds their words to the search keywords instead, for example "Remote (Full-time OR Part-time) accountant", which brings closely matching jobs but is not an exact filter. Check `employment_type` and `seniority_level` in the results if you need to be strict. Sorting by "Most recent" is also ignored by LinkedIn; use **Posted since** or **Date posted** instead.

#### Why did some inputs fail?

Inputs that fail are listed, with the reason, in the **`FAILED`** record of the run's key-value store (open the run, then **Storage**, then **Key-value store**):

- **`invalid_input`**: not a LinkedIn job search or job URL.
- **`search_without_keywords_or_location`**: the search URL has no keywords, location or company.
- **`not_found`**: the job was removed or never existed.
- **`no_jobs_found`**: the search has no jobs, or all of them were filtered out or already saved by another search.
- **`blocked`**: LinkedIn refused every attempt. Run it again later.

#### Do I need to set up proxies?

No. There is nothing to configure.

### Related scrapers

- [LinkedIn Company Scraper](https://apify.com/keklik/linkedin-company-scraper): the full LinkedIn page of the companies you found, with every office location, products and similar companies.
- [Google Maps Leads Scraper](https://apify.com/keklik/google-maps-leads-scraper): phone numbers, websites and emails of local businesses.

### Support

Found a bug or missing a field? Open an issue in the **Issues** tab and we'll look at it. Need a custom LinkedIn scraper or data in a different format? Contact us through Apify and we'll build it for you.

# Changelog

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

# Actor input Schema

## `urls` (type: `array`):

Paste the URL of a job search from linkedin.com/jobs (with your keywords, location and filters), or the URL of a single job posting (linkedin.com/jobs/view/...). One search URL gives up to 1,000 jobs.

## `searchTerms` (type: `array`):

Job titles or keywords to search, such as "data analyst" or "nurse". Each one is its own search, in the location below.

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

Where to search for the keywords above: a country, region or city, such as "United States", "London" or "Île-de-France".

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

Only jobs posted in this window. A search URL that already has its own date filter keeps it.

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

On-site, remote or hybrid. LinkedIn's logged-out search ignores this filter, so the scraper adds the words to the search keywords instead ("Remote accountant"); expect closer matches, not an exact filter.

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

Full-time, part-time, contract and so on. Added to the search keywords, like Workplace.

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

Internship to executive. Added to the search keywords, like Workplace.

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

Only jobs you can apply to on LinkedIn.

## `under10Applicants` (type: `boolean`):

Only jobs with fewer than 10 applicants so far.

## `postedSince` (type: `string`):

Only jobs posted since then: 12h, 3d or 2w back from the start of the run, or a date such as 2026-10-01. Use it for daily or weekly runs that only want new jobs.

## `excludeTitles` (type: `array`):

Words that drop a job when its title contains them, such as "senior" or "intern". Not case-sensitive. Skipped jobs are free.

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

Company names to drop, written as LinkedIn shows them. Not case-sensitive. Skipped jobs are free.

## `jobDetails` (type: `boolean`):

Open each job's page for the full description, seniority, employment type, industries, applicant count, apply type, parsed salary and the job poster. Charged per job that gets them.

## `companyDetails` (type: `boolean`):

Add the hiring company's website, industry, size, employee and follower counts, headquarters, founding year, type, specialties and description from its LinkedIn page. Charged per job that gets them.

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

Stop each search after this many jobs. LinkedIn shows at most 1,000 jobs per search; to get more, split it into narrower searches (by location or keyword).

## `maxResults` (type: `integer`):

Stop the whole run after this many jobs. Leave empty for no limit.

## Actor input object example

```json
{
  "urls": [
    "https://www.linkedin.com/jobs/search?keywords=Software%20Engineer&location=United%20States&f_TPR=r604800"
  ],
  "datePosted": "any",
  "easyApplyOnly": false,
  "under10Applicants": false,
  "jobDetails": true,
  "companyDetails": false,
  "maxJobsPerSearch": 100
}
```

# Actor output Schema

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

One row per job: title, company, location, date, salary, and the extras you turned 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 = {
    "urls": [
        "https://www.linkedin.com/jobs/search?keywords=Software%20Engineer&location=United%20States&f_TPR=r604800"
    ],
    "maxJobsPerSearch": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("keklik/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 = {
    "urls": ["https://www.linkedin.com/jobs/search?keywords=Software%20Engineer&location=United%20States&f_TPR=r604800"],
    "maxJobsPerSearch": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("keklik/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 '{
  "urls": [
    "https://www.linkedin.com/jobs/search?keywords=Software%20Engineer&location=United%20States&f_TPR=r604800"
  ],
  "maxJobsPerSearch": 100
}' |
apify call keklik/linkedin-jobs-scraper --silent --output-dataset

```

## MCP server setup

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