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

Scrape LinkedIn job listings by keyword, location, search URL, or job ID. Extract titles, companies, locations, posted dates, full descriptions when available, salary signals, criteria, applicant text, Easy Apply status, and job URLs. Export data, run via API, or schedule runs.

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

## Pricing

$1.50 / 1,000 job listings

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

### 💼 What does LinkedIn Jobs Scraper do?

LinkedIn Jobs Scraper extracts clean, deduplicated data from public
[LinkedIn](https://www.linkedin.com/jobs/) job listings: job title, company
name, location, posted date, applicant text, employment criteria, salary signals,
full description text and HTML when available, Easy Apply status, LinkedIn job
URLs, and more.

To get that data, enter a job title or keyword, paste a LinkedIn Jobs search
URL, or add known LinkedIn job IDs or URLs. Locations are optional, so you can
run broad keyword searches or narrow them to specific markets. You can also run
the scraper through the Apify API, schedule it, or connect it to other tools.
It saves one row per job by default, so overlapping keywords, locations, search
URLs, job IDs, and pages do not fill your dataset with duplicate listings.

With LinkedIn Jobs Scraper, you can:

- Scrape LinkedIn job listings by job title, keyword, company, role family, and
  location.
- Extract detailed job posting data, including description text and HTML when
  available.
- Collect company names, company URLs, logo URLs, locations, salary signals,
  applicant text, job criteria, Easy Apply status, and LinkedIn job URLs.
- Filter LinkedIn jobs by posting date, radius, job type, workplace type,
  experience level, employer exclusions, title filters, and sort order.
- Run keyword/location searches, paste LinkedIn search URLs, or enrich known job
  IDs from the form, JSON, or API input.
- Enrich known LinkedIn job IDs or job URLs without running search discovery.
- Save clean unique job listings with duplicate skips, title filters, and
  run-summary counters.
- Download LinkedIn job data in JSON, JSONL, CSV, Excel, XML, RSS, or HTML.
- Check the run summary to see how many jobs were found, saved, skipped,
  duplicated, filtered, blocked, or stopped.

### 📦 What job listing data can I extract?

With this Actor, you can extract the following data from public LinkedIn job
postings:

|                          |                       |                       |
| ------------------------ | --------------------- | --------------------- |
| 💼 Job title             | 🏢 Company name       | 📍 Job location       |
| 📝 Full description text | 🧾 Description HTML   | 🔎 Description status |
| 💰 Salary range          | 💵 Salary currency    | ⏱️ Salary period      |
| 🧑‍💻 Employment type       | 🪜 Seniority          | 🏠 Workplace / remote |
| 🧰 Job function          | 🏷️ Industries         | 👥 Applicant text     |
| 🔗 Company URL           | 🖼️ Company logo URL   | ⚡ Easy Apply status  |
| 🌐 LinkedIn job URL      | 🔍 Search keyword     | 🧭 Search location    |
| 📊 Jobs saved            | ♻️ Duplicates skipped | 🚦 Stop reason        |

Here are the main output groups:

| Data group              | Example fields                                                                                            |
| ----------------------- | --------------------------------------------------------------------------------------------------------- |
| 💼 Job details          | `jobId`, `title`, `employmentType`, `seniority`, `jobFunction`, `industries`, `isEasyApply`               |
| 🏢 Company details      | `companyName`, `companyUrl`, `companyLogoUrl`                                                             |
| 📍 Location             | `locationRaw`, `locationCity`, `locationRegion`, `locationCountry`, `workplaceType`, `isRemote`           |
| 💰 Salary               | `salaryRaw`, `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`                                   |
| 📝 Description          | `descriptionSnippet`, `descriptionText`, `descriptionHtml`, `descriptionStatus`                           |
| 🔗 Links and enrichment | `jobUrl`, `isEasyApply`, `isExpired`                                                                      |
| 🧭 Search provenance    | `query`, `searchLocation`, `searchPosition`, `pageNumber`                                                 |
| 📊 Run summary          | `candidateItemsSeen`, `jobsSaved`, `duplicateCandidatesSeen`, `duplicatesSkipped`, warnings, `stopReason` |

Salary, applicant counts, Easy Apply signals, and full descriptions depend on
what LinkedIn exposes for each public job listing. If full job descriptions
matter for your workflow, check the `descriptionStatus` field in the output and
the detail counters in the run summary.

### ⚙️ Can I use this Actor through an API?

Yes. You can run LinkedIn Jobs Scraper manually in Apify Console or use it as an
API for LinkedIn job data.

Developers can call this Actor through:

- Apify API
- Python SDK
- Node.js SDK
- Webhooks
- Scheduled runs
- Apify integrations

This makes it useful for recruiting pipelines, job-board enrichment, hiring
dashboards, warehouse loads, agents, and automated labor-market research.

### Clean, duplicate-free LinkedIn job datasets

LinkedIn job results can overlap across related keywords, locations, search
URLs, known job IDs, and pages. For normal datasets, keep
`saveOnlyUniqueItems` enabled so the Actor saves one row per job and skips
duplicate candidates before they become saved rows.

The `OUTPUT` summary shows `candidateItemsSeen`, `duplicateCandidatesSeen`,
`duplicatesSkipped`, and `jobsSaved`, so you can see how many matching rows were
found, how many were duplicates, and how many unique job listings were saved.
Turn unique-job mode off only when you intentionally want to measure keyword
overlap or search ranking behavior.

### 📊 Why scrape LinkedIn jobs?

LinkedIn is a major source of job market data. Scraping LinkedIn jobs can help
you track hiring demand, role language, salary signals, employer activity, and
remote-work patterns across markets.

Here are just some of the ways you could use LinkedIn job data:

| Use case                      | How LinkedIn job data helps                                                   |
| ----------------------------- | ----------------------------------------------------------------------------- |
| 📈 Monitor hiring trends      | Track demand by role, skill, location, company, seniority, or workplace type. |
| 💰 Benchmark salaries         | Compare salary signals across markets and job families where available.       |
| 🧲 Build recruiting workflows | Collect active job listings for sourcing, staffing, and lead generation.      |
| 🏢 Track competitors          | Watch hiring activity, expansion signals, and technology adoption.            |
| 🧪 Research labor markets     | Analyze job descriptions, criteria, applicant text, and company demand.       |
| 🧱 Enrich job boards          | Feed clean LinkedIn job data into apps, databases, and career tools.          |

### LinkedIn jobs scraper with no login or cookies

LinkedIn Jobs Scraper works with public LinkedIn Jobs surfaces. You do not need
to provide a LinkedIn account, login session, or browser cookies. Paste a role
and optional location, a LinkedIn Jobs search URL, or known LinkedIn job IDs and run the
Actor from Apify Console or API.

### Scrape LinkedIn jobs by job ID or URL

Use `jobIds` when you already know the LinkedIn job IDs or job URLs you want to
enrich. This mode skips search discovery and focuses on the known job listings,
which is useful for job-board enrichment, saved lead lists, and repeatable data
refreshes.

Use `startUrls` when you already built a LinkedIn Jobs search in the LinkedIn UI
and want to preserve those search filters in the Actor run.

If you provide more than one source type in the same run, the Actor combines
them, removes duplicate jobs when `saveOnlyUniqueItems` is enabled, and applies
one shared `maxItems` cap across the whole run.

### LinkedIn Easy Apply, salary, and criteria data

When public job details are available, the Actor can add Easy Apply status,
salary signals, applicant text, seniority, employment type, workplace type, job
function, industries, full description text, and description HTML. Check
`descriptionStatus` and the run summary to see which detail fields were exposed
for each run.

### 💵 How much does scraping LinkedIn jobs cost?

LinkedIn Jobs Scraper uses a Pay-Per-Event pricing model. You are charged for
saved job listings.

The current price is **$1.50 per 1,000 saved job listings**, or **$0.0015 per
job listing**. For example:

| Saved job listings | Estimated Actor charge |
| ------------------ | ---------------------- |
| 100 jobs           | $0.15                  |
| 1,000 jobs         | $1.50                  |
| 10,000 jobs        | $15.00                 |

Start with `maxItems` between 10 and 100 if you want to test the output before
running larger searches. The run summary shows how many candidate jobs were
seen, how many unique jobs were saved, and why the run stopped. For normal runs,
keep **Unique jobs only** enabled so duplicate candidates are skipped before
they become saved rows.

### 🚀 How do I use LinkedIn Jobs Scraper?

LinkedIn Jobs Scraper was designed for an easy start even if you've never
extracted data from the web before. Here's how you can scrape LinkedIn job data
with this tool:

1. Create or log in to your Apify account.
2. Open **LinkedIn Jobs Scraper**.
3. Choose a source: add job titles or keywords, paste LinkedIn Jobs search URLs,
   or add known LinkedIn job IDs or URLs.
4. Optionally add one or more locations for keyword searches. Location narrows
   the keyword search.
5. Set the maximum number of job listings to collect.
6. Add filters such as posted date, radius, job type, workplace type, experience
   level, employer exclusions, or title filters if needed.
7. Click **Start** and wait for the data to be extracted.
8. Download your data in JSON, JSONL, CSV, Excel, XML, RSS, or HTML.

### ⬇️ Input

The input needs at least one way to choose jobs:

- **Option 1: Keywords** - Search LinkedIn by job titles/keywords, optionally
  with locations.
- **Option 2: LinkedIn search URLs** - Paste a LinkedIn Jobs search URL when you
  already configured filters in LinkedIn and want to preserve them.
- **Option 3: Job IDs or job URLs** - Provide known LinkedIn job IDs/URLs to
  enrich specific listings without search discovery.

They can also be mixed in one run. If mixed, the actor combines results,
deduplicates them, and applies one shared Job listings to collect cap.

Locations are optional for keyword searches. If filled, LinkedIn searches for
Keywords AND each Location. LinkedIn search URLs keep their own filters, and job
IDs or job URLs target exact listings.

You can also add optional filters for date, radius, job type, workplace type,
experience level, page depth, employer exclusions, and title filters.

Here's a simple input example for a broad software engineer search:

```json
{
    "searchTerm": "software engineer",
    "location": "",
    "postedWithin": "7d",
    "distance": 25,
    "sortBy": "relevance",
    "maxItems": 25,
    "maxPagesPerSearch": 2,
    "balanceKeywordCoverage": true,
    "saveOnlyUniqueItems": true,
    "fetchJobDetails": true,
    "jobType": "any",
    "workplaceType": "any",
    "experienceLevel": "any"
}
````

Click on the **Input** tab for a full explanation of input in JSON.

#### 🔎 Search terms

Use one job title, skill, company, or role family per line. This field is
optional when you use LinkedIn search URLs or job IDs. Multiple distinct search
terms can help you collect broader job market data.

Good search terms:

```text
data engineer
analytics engineer
data scientist
software engineer
product manager
```

Overlapping search terms can return the same job more than once. Keep
`saveOnlyUniqueItems` enabled unless you are measuring keyword overlap or search
ranking.

If LinkedIn returns broad results for a role, add title filters. This is useful
for searches like `backend engineer`, `CTO`, or `data analyst`, where broad
keyword matching can include off-target roles.

```json
{
    "searchTerm": "backend engineer",
    "location": "Germany",
    "titleMustInclude": "backend engineer\nplatform engineer",
    "titleExclude": "frontend\nrecruiter\nsales",
    "maxItems": 100
}
```

#### 📍 Locations

Add one city, region, country, or remote-friendly location per line. Locations
are only used with keyword searches. Leave the field blank for broader LinkedIn
results. LinkedIn handles geography from each location value you provide.

Good locations:

```text
Toronto, ON, Canada
New York, NY
San Francisco Bay Area
Remote
United States
```

JSON/API users can run a location matrix by passing `locations` as an array.
For example, three keywords and two locations create six keyword/location
searches:

```json
{
    "searchTerm": "data scientist",
    "locations": ["Toronto, ON, Canada", "New York, NY", "Seattle, WA"],
    "maxItems": 300
}
```

#### 🎛️ Filters, quality controls, and run tuning

| Option                      | What it does                                                                 |
| --------------------------- | ---------------------------------------------------------------------------- |
| 📅 `postedWithin`           | Searches jobs from the selected freshness window.                            |
| 📍 `distance`               | Searches around the selected location.                                       |
| 🔀 `sortBy`                 | Sorts LinkedIn results by relevance or date.                                 |
| 🧑‍💻 `jobType`                | Filters full-time, part-time, contract, temporary, internship, or volunteer. |
| 🏠 `workplaceType`          | Filters on-site, remote, or hybrid jobs.                                     |
| 🪜 `experienceLevel`        | Filters by LinkedIn seniority level when available.                          |
| 📄 `maxPagesPerSearch`      | Sets the page depth for each keyword/location or search URL.                 |
| 🚫 `excludeCompanies`       | Skips matching employers and counts skipped rows in the run summary.         |
| 🎯 `titleMustInclude`       | Saves jobs whose title contains at least one required word or phrase.        |
| 🧹 `titleExclude`           | Skips jobs whose title contains off-target words or phrases.                 |
| ♻️ `saveOnlyUniqueItems`    | Saves one row per job across overlapping keywords, locations, URLs, pages.   |
| ⚖️ `balanceKeywordCoverage` | Spreads results across keywords and locations before going deeper.           |
| 📝 `fetchJobDetails`        | Adds full descriptions, criteria, applicant text, and Easy Apply signals.    |
| ⏱️ `requestDelayMillis`     | Controls delay between requests. The Actor enforces a 500 ms minimum.        |

#### 🔗 LinkedIn search URLs and job IDs

You can also start from LinkedIn search URLs or known job IDs.

Use `startUrls` when you already built a search in LinkedIn and want to preserve
its filters:

```json
{
    "startUrls": [
        {
            "url": "https://www.linkedin.com/jobs/search/?keywords=data%20engineer&location=Toronto%2C%20ON"
        }
    ],
    "maxItems": 50,
    "fetchJobDetails": true
}
```

Use `jobIds` when you already have LinkedIn job IDs or job URLs and only want
detail enrichment:

```json
{
    "jobIds": ["<linkedin-job-id-or-url>"],
    "maxItems": 1,
    "fetchJobDetails": true
}
```

Leave `jobIds` empty unless you already have known listings to enrich. The form
does not include seeded job IDs.

### ⬆️ Output sample

The results will be wrapped into a dataset which you can find in the **Output**
tab. Each result is one saved LinkedIn job listing.

For easier postprocessing, export the results to one of the supported formats:
JSON, JSONL, CSV, Excel spreadsheet, XML, RSS, or HTML table.

Here's an example of the exported JSON output:

```json
{
    "jobId": "4428089436",
    "title": "Data Engineer - Python, ETL",
    "companyName": "Example Company",
    "companyUrl": "https://www.linkedin.com/company/example",
    "companyLogoUrl": "https://media.licdn.com/example-logo",
    "locationRaw": "Toronto, Ontario, Canada",
    "locationCity": "Toronto",
    "locationRegion": "Ontario",
    "locationCountry": "Canada",
    "workplaceType": "hybrid",
    "isRemote": false,
    "salaryRaw": "$110,000-$130,000 CAD",
    "salaryMin": 110000,
    "salaryMax": 130000,
    "salaryCurrency": "CAD",
    "salaryPeriod": "year",
    "employmentType": "fulltime",
    "seniority": "Mid-Senior level",
    "jobFunction": "Information Technology",
    "industries": ["IT Services and IT Consulting"],
    "postedAtRaw": "5 days ago",
    "postedAt": "2026-06-16T20:35:49.490Z",
    "applicantsRaw": "Be among the first 25 applicants",
    "descriptionSnippet": "Build reliable data systems...",
    "descriptionText": "Full job description text...",
    "descriptionHtml": "<p>Full job description HTML...</p>",
    "descriptionStatus": "full",
    "jobUrl": "https://www.linkedin.com/jobs/view/example-4428089436",
    "query": "data engineer",
    "searchLocation": "Toronto, ON, Canada",
    "verifiedAt": "2026-06-21T20:35:49.490Z",
    "isExpired": false,
    "verificationSource": "detail",
    "scrapedAt": "2026-06-21T20:35:49.490Z"
}
```

#### 📌 Run summary

LinkedIn Jobs Scraper also saves an `OUTPUT` summary in the default key-value
store. Use it to see why the final number of saved jobs changed.

```json
{
    "stopReason": "max_items_reached",
    "searchesQueued": 6,
    "pagesParsed": 18,
    "requestedMaxItems": 100,
    "candidateItemsSeen": 142,
    "jobsSaved": 100,
    "detailRequests": 100,
    "detailPagesParsed": 99,
    "detailFailures": 1,
    "duplicateCandidatesSeen": 12,
    "duplicatesSkipped": 12,
    "rowsExcludedByCompany": 0,
    "rowsExcludedByDate": 0,
    "rowsExcludedByJobType": 0,
    "rowsExcludedByWorkplace": 0,
    "rowsExcludedByExperience": 0,
    "rowsExcludedByTitle": 0,
    "blockedRequests": 1,
    "failedRequests": 0,
    "warnings": [],
    "statusMessage": "Saved 100 LinkedIn job listings."
}
```

### ❓ Why did I get fewer jobs than requested?

`maxItems` is a cap on saved rows, not a guarantee that every search has that
many matching jobs.

If your run saves fewer jobs than requested, check the `OUTPUT` summary. It
shows whether rows were skipped because of duplicates, employer exclusions, date
filters, job-type filters, workplace filters, experience filters, title filters,
source exhaustion, page limits, failed requests, or blocked detail pages.

Common reasons include:

- The selected role and location have fewer available jobs than `maxItems`.
- Strict filters removed many candidate rows.
- Title include/exclude filters removed broad or off-target LinkedIn matches.
- Multiple keywords returned the same jobs and unique-job mode skipped
  duplicates.
- LinkedIn did not expose a detail page for every discovered job.
- The search depth limit was reached before enough unique matching jobs were
  found.

If you need more rows, increase `maxPagesPerSearch`, relax strict filters, add
more distinct keywords, expand the search radius, or search broader locations.

### ✅ Tips for scraping LinkedIn jobs

- Start with a small test run and inspect the dataset before increasing
  `maxItems`.
- Use distinct keywords instead of near-duplicates.
- Keep `saveOnlyUniqueItems` enabled for normal datasets.
- Use `balanceKeywordCoverage` for market maps across multiple role families.
- Use `titleMustInclude` and `titleExclude` when LinkedIn returns broad or
  off-target roles.
- Use `postedWithin` for fresh job monitoring.
- Keep `fetchJobDetails` enabled when full descriptions matter.
- Increase `maxPagesPerSearch` gradually for larger runs.
- Check `descriptionStatus` when full job descriptions are important.
- Check the run summary for duplicates, detail failures, blocked requests, and
  stop reason.

### ❓ FAQ

#### Does LinkedIn Jobs Scraper need login or cookies?

No. You do not need to provide a LinkedIn account, login session, or browser
cookies.

#### Can I use LinkedIn Jobs Scraper through an API?

Yes. Run it with the Apify API, Python SDK, Node.js SDK, webhooks, schedules, or
integrations. The dataset contains saved job rows and the `OUTPUT` key-value
store record contains the run summary.

#### Can I scrape LinkedIn jobs by job ID?

Yes. Use the `jobIds` input with LinkedIn job IDs or job URLs when you already
know which listings you want to enrich.

#### Why are salaries, applicant text, or full descriptions sometimes missing?

Those fields depend on what LinkedIn exposes publicly for each listing. Use
`descriptionStatus`, salary fields, and run-summary detail counters to separate
complete rows from partial rows.

#### How do I avoid duplicate jobs?

Keep `saveOnlyUniqueItems` enabled. The Actor saves one row per job across
overlapping keywords, locations, search URLs, job IDs, and pages. The `OUTPUT`
summary reports `candidateItemsSeen`, `duplicateCandidatesSeen`,
`duplicatesSkipped`, and `jobsSaved`, so you can audit how many candidates were
found, skipped as duplicates, and saved as unique job listings.

#### How much does it cost?

The current Actor charge is **$1.50 per 1,000 saved job listings**. Check the
Pricing tab before production runs because live Store pricing is the source of
truth.

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

This Actor extracts public job listing data. You are responsible for making sure
your use case complies with applicable laws, platform terms, and privacy rules.

Job listings can sometimes include personal data or contact details. You should
not scrape, store, or process personal data unless you have a legitimate reason
and the right legal basis. If you're unsure whether your reason is legitimate,
consult your lawyers.

LinkedIn is a trademark of its owner. This Actor is independent and is not
affiliated with, endorsed by, or sponsored by LinkedIn.

### 🔗 Related job scrapers

- [LinkedIn Jobs Scraper](https://apify.com/chronometrica/linkedin-jobs-scraper)
  for LinkedIn job search, search URLs, known job IDs, Easy Apply signals, and
  job criteria.
- [Indeed Jobs Scraper](https://apify.com/chronometrica/indeed-jobs-scraper)
  for Indeed salaries, full descriptions, benefits, skills, and apply links.

### 🛟 Support

If a run does not return what you expected, open an issue with the run ID and
the input you used. The run summary shows saved rows, skipped rows, filters,
warnings, detail counters, and stop reason so support can be specific.

Related searches: LinkedIn scraper, LinkedIn jobs scraper, scrape LinkedIn jobs,
LinkedIn job listings, remove duplicate jobs, duplicate-free job scraper, unique
job listings, deduped job listings, job board deduplication, LinkedIn job
descriptions, LinkedIn jobs no cookies, LinkedIn job ID scraper, LinkedIn jobs
search URL scraper, LinkedIn Easy Apply scraper, LinkedIn salary data, job
market data, recruiting data, HR analytics, salary benchmarking, job board data,
company hiring signals.

# Actor input Schema

## `searchTerm` (type: `string`):

Search LinkedIn by job titles/keywords, optionally with locations.

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

Optional for Keywords. If filled, LinkedIn searches for Keywords AND each Location. Enter one city, region, country, or Remote per line. Leave blank for broad LinkedIn results.

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

Paste a LinkedIn Jobs search URL when you already configured filters in LinkedIn and want to preserve them.

## `jobIds` (type: `array`):

Provide known LinkedIn job IDs/URLs to enrich specific listings without search discovery.

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

This cap applies to all 3 ways: Keywords, LinkedIn search URLs, and Job IDs or job URLs. If mixed, the actor stops when this many job listings are saved.

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

Only keep jobs posted in this time window. For URLs and job IDs, this is checked when LinkedIn shows a posted date.

## `distance` (type: `integer`):

Search distance in miles when you enter a location.

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

Choose the order for keyword and location searches.

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

Choose one job type, or keep Any.

## `workplaceType` (type: `string`):

Choose on-site, remote, hybrid, or keep Any.

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

Choose one seniority level, or keep Any.

## `maxPagesPerSearch` (type: `integer`):

How many result pages to check for each keyword/location or search URL. Increase slowly for larger runs.

## `excludeCompanies` (type: `string`):

Optional. Enter one employer per line. Matching jobs are skipped and counted in the run summary.

## `titleMustInclude` (type: `string`):

Optional. Enter one word or phrase per line. A job is saved only if its title contains one of these.

## `titleExclude` (type: `string`):

Optional. Enter one word or phrase per line. Jobs with these words in the title are skipped.

## `saveOnlyUniqueItems` (type: `boolean`):

Save each LinkedIn job only once, even if it appears from more than one keyword, URL, or ID. Keep this on for normal runs.

## `balanceKeywordCoverage` (type: `boolean`):

Give each keyword and location a turn before going deeper. Useful when you enter more than one keyword or location.

## `fetchJobDetails` (type: `boolean`):

Keep on to collect full descriptions, criteria, applicant text, and Easy Apply signals when LinkedIn shows them.

## `requestDelayMillis` (type: `integer`):

Wait time between LinkedIn requests. Values below 500 ms are raised automatically.

## Actor input object example

```json
{
  "searchTerm": "software engineer\ndata analyst\nproduct manager",
  "startUrls": [],
  "jobIds": [],
  "maxItems": 25,
  "postedWithin": "7d",
  "distance": 25,
  "sortBy": "relevance",
  "jobType": "any",
  "workplaceType": "any",
  "experienceLevel": "any",
  "maxPagesPerSearch": 2,
  "excludeCompanies": "",
  "titleMustInclude": "",
  "titleExclude": "",
  "saveOnlyUniqueItems": true,
  "balanceKeywordCoverage": true,
  "fetchJobDetails": true,
  "requestDelayMillis": 500
}
```

# Actor output Schema

## `results` (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 = {
    "searchTerm": `software engineer
data analyst
product manager`,
    "startUrls": [],
    "saveOnlyUniqueItems": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("chronometrica/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 = {
    "searchTerm": """software engineer
data analyst
product manager""",
    "startUrls": [],
    "saveOnlyUniqueItems": True,
}

# Run the Actor and wait for it to finish
run = client.actor("chronometrica/linkedin-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchTerm": "software engineer\\ndata analyst\\nproduct manager",
  "startUrls": [],
  "saveOnlyUniqueItems": true
}' |
apify call chronometrica/linkedin-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=chronometrica/linkedin-jobs-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "LinkedIn Jobs Scraper",
        "description": "Scrape LinkedIn job listings by keyword, location, search URL, or job ID. Extract titles, companies, locations, posted dates, full descriptions when available, salary signals, criteria, applicant text, Easy Apply status, and job URLs. Export data, run via API, or schedule runs.",
        "version": "0.2",
        "x-build-id": "faZMRfuTfUeMUaQpC"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/chronometrica~linkedin-jobs-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-chronometrica-linkedin-jobs-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/chronometrica~linkedin-jobs-scraper/runs": {
            "post": {
                "operationId": "runs-sync-chronometrica-linkedin-jobs-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/chronometrica~linkedin-jobs-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-chronometrica-linkedin-jobs-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchTerm": {
                        "title": "Option 1: Keywords - search jobs",
                        "type": "string",
                        "description": "Search LinkedIn by job titles/keywords, optionally with locations."
                    },
                    "location": {
                        "title": "Locations",
                        "type": "string",
                        "description": "Optional for Keywords. If filled, LinkedIn searches for Keywords AND each Location. Enter one city, region, country, or Remote per line. Leave blank for broad LinkedIn results."
                    },
                    "startUrls": {
                        "title": "Option 2: LinkedIn search URLs - keep filters",
                        "type": "array",
                        "description": "Paste a LinkedIn Jobs search URL when you already configured filters in LinkedIn and want to preserve them.",
                        "default": [],
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "jobIds": {
                        "title": "Option 3: Job IDs or job URLs - exact listings",
                        "type": "array",
                        "description": "Provide known LinkedIn job IDs/URLs to enrich specific listings without search discovery.",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "maxItems": {
                        "title": "Job listings to collect (shared cap)",
                        "minimum": 1,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "This cap applies to all 3 ways: Keywords, LinkedIn search URLs, and Job IDs or job URLs. If mixed, the actor stops when this many job listings are saved.",
                        "default": 25
                    },
                    "postedWithin": {
                        "title": "Posted within",
                        "enum": [
                            "any",
                            "24h",
                            "3d",
                            "7d",
                            "14d",
                            "30d"
                        ],
                        "type": "string",
                        "description": "Only keep jobs posted in this time window. For URLs and job IDs, this is checked when LinkedIn shows a posted date.",
                        "default": "7d"
                    },
                    "distance": {
                        "title": "Search radius",
                        "minimum": 0,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Search distance in miles when you enter a location.",
                        "default": 25
                    },
                    "sortBy": {
                        "title": "Sort by",
                        "enum": [
                            "relevance",
                            "date"
                        ],
                        "type": "string",
                        "description": "Choose the order for keyword and location searches.",
                        "default": "relevance"
                    },
                    "jobType": {
                        "title": "Job type",
                        "enum": [
                            "any",
                            "fulltime",
                            "parttime",
                            "contract",
                            "temporary",
                            "internship",
                            "volunteer"
                        ],
                        "type": "string",
                        "description": "Choose one job type, or keep Any.",
                        "default": "any"
                    },
                    "workplaceType": {
                        "title": "Workplace",
                        "enum": [
                            "any",
                            "onsite",
                            "remote",
                            "hybrid"
                        ],
                        "type": "string",
                        "description": "Choose on-site, remote, hybrid, or keep Any.",
                        "default": "any"
                    },
                    "experienceLevel": {
                        "title": "Experience level",
                        "enum": [
                            "any",
                            "internship",
                            "entry",
                            "associate",
                            "midsenior",
                            "director",
                            "executive"
                        ],
                        "type": "string",
                        "description": "Choose one seniority level, or keep Any.",
                        "default": "any"
                    },
                    "maxPagesPerSearch": {
                        "title": "Page depth",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "How many result pages to check for each keyword/location or search URL. Increase slowly for larger runs.",
                        "default": 2
                    },
                    "excludeCompanies": {
                        "title": "Skip employers",
                        "type": "string",
                        "description": "Optional. Enter one employer per line. Matching jobs are skipped and counted in the run summary.",
                        "default": ""
                    },
                    "titleMustInclude": {
                        "title": "Title must include",
                        "type": "string",
                        "description": "Optional. Enter one word or phrase per line. A job is saved only if its title contains one of these.",
                        "default": ""
                    },
                    "titleExclude": {
                        "title": "Skip titles containing",
                        "type": "string",
                        "description": "Optional. Enter one word or phrase per line. Jobs with these words in the title are skipped.",
                        "default": ""
                    },
                    "saveOnlyUniqueItems": {
                        "title": "Unique jobs only (remove duplicates)",
                        "type": "boolean",
                        "description": "Save each LinkedIn job only once, even if it appears from more than one keyword, URL, or ID. Keep this on for normal runs.",
                        "default": true
                    },
                    "balanceKeywordCoverage": {
                        "title": "Balance keyword coverage",
                        "type": "boolean",
                        "description": "Give each keyword and location a turn before going deeper. Useful when you enter more than one keyword or location.",
                        "default": true
                    },
                    "fetchJobDetails": {
                        "title": "Full descriptions and details",
                        "type": "boolean",
                        "description": "Keep on to collect full descriptions, criteria, applicant text, and Easy Apply signals when LinkedIn shows them.",
                        "default": true
                    },
                    "requestDelayMillis": {
                        "title": "Delay between requests",
                        "minimum": 500,
                        "maximum": 60000,
                        "type": "integer",
                        "description": "Wait time between LinkedIn requests. Values below 500 ms are raised automatically.",
                        "default": 500
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
