# Advanced LinkedIn Jobs Scraper - Applicants & Full Detail (`zyra/advanced-linkedin-jobs-scraper`) Actor

Every LinkedIn job behind any search URL: title, company, location, seniority, function, industries, employment type, applicant count, posted date, easy-apply and the full job description. 29 fields per job, straight from the search you already ran.

- **URL**: https://apify.com/zyra/advanced-linkedin-jobs-scraper.md
- **Developed by:** [Zyra](https://apify.com/zyra) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.00 / 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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## Advanced LinkedIn Jobs Scraper

**Every job behind a LinkedIn search — with the detail the search page hides.**

Search LinkedIn Jobs the way you normally would. Filter by keywords, location,
date posted, experience level, remote, salary. Paste the URL. Get every job
behind it as structured data, 29 fields each.

### Why this one

**The full job description, not a snippet.** Every row carries the complete
posting text as it appears on LinkedIn, alongside a short summary — so you can
search, classify or run a model over the actual requirements rather than a
truncated preview.

**How contested the job is.** `job_num_applicants` gives LinkedIn's live
applicant count, so you can tell a role with 4 applicants from one with 400.
That is the single most useful signal on a job board and most scrapers drop it.

**Structured, not free text.** Seniority level, job function, employment type
and industries come back as their own fields on every listing — already
normalised by LinkedIn, so filtering and grouping needs no parsing.

**Easy-apply flagged.** `is_easy_apply` and `application_availability` tell you
whether a job takes a one-click application and whether it is still open.

**Your search, your filters.** Keywords, location, date posted, experience
level, remote, salary — whatever you set on LinkedIn is respected. If the
search works in your browser, it works here.

### What you get

**The job** — title, full description, summary, LinkedIn URL, posting ID,
standardised title ID, and the date and relative time it was posted.

**The classification** — seniority level, job function, employment type and
industries, as separate fields.

**The company** — name, LinkedIn company ID, company page URL and logo.

**The competition** — number of applicants, whether applications are still
open, and whether it is an easy-apply listing.

**The location** — job location and two-letter country code.

**The pay, where LinkedIn publishes it** — the base pay range as text, a
structured `base_salary` with currency and pay period, and any employer pay
notes.

### Sample output

One real row, abridged:

```json
{
  "job_title": "Senior Software Engineer – Go (Golang)",
  "company_name": "General Motors",
  "job_location": "Warren, MI",
  "job_seniority_level": "Mid-Senior level",
  "job_employment_type": "Full-time",
  "job_function": "Engineering and Information Technology",
  "job_industries": "Motor Vehicle Manufacturing",
  "job_num_applicants": 137,
  "is_easy_apply": false,
  "application_availability": true,
  "country_code": "US",
  "url": "https://www.linkedin.com/jobs/view/...",
  "discovery_input": { "url": "https://www.linkedin.com/jobs/search?keywords=Software%20Engineer&location=United%20States" }
}
```

#### How completely listings are filled in

LinkedIn does not publish every field for every job, so neither does this. From
a 25-listing sample run:

| Field group | Present on |
| --- | --- |
| Title, company, location, description, seniority, function, industries, employment type, applicant count, posted date, easy-apply, country | **100%** |
| Pay range, structured salary and pay notes | ~24% |
| Job poster profile | not populated |

Pay is the field to be realistic about: roughly a quarter of listings carry it,
because only some employers and jurisdictions publish salary on LinkedIn.
Everything else you see above came back on every job in the sample.

Fields LinkedIn has no data for come back empty rather than guessed at. Export
to JSON, CSV, Excel or XML, or pull it straight from the API.

### How it works

1. Search jobs on LinkedIn and copy the URL from your address bar.
2. Paste it into **LinkedIn search URLs**. Add more URLs to run several
   searches at once.
3. Set a limit if you want one, and run it.

### Input

| Field | Required | What it does |
| --- | --- | --- |
| **LinkedIn search URLs** | yes | One or more LinkedIn jobs search URLs. Every job behind each one is collected. |
| **Max jobs per URL** | no | Stop after this many jobs from each search. **Prefilled at 10**, so a first run is a quick sample. Raise it up to 1,000, or clear the field to collect 1,000 per URL. |
| **Max jobs in total** | no | Stop the whole run after this many jobs, across all searches. Up to 10,000; empty means 10,000. |

Both limits are applied *during* collection rather than to the results
afterwards, so a limited run genuinely does less work and finishes sooner.
Every run is bounded, so a broad search can never run away with itself.

**Run it once to see the shape of the data, then open it up.** The prefilled 10
jobs per URL keeps a first run quick and cheap.

### Built to be trusted with real work

**Stop a run at any time and keep what it found.** Aborting stops the
collection and delivers every job completed up to that moment. Nothing is
abandoned and nothing half-fetched is passed off as a result.

**You are never charged for a job you did not receive.** Listings that failed
to fetch are reported separately and never reach your dataset.

**Runs are self-limiting.** Time budgets scale with the size of the request.

**Clean, stable output.** Field names come straight from the source schema and
are not renamed or reshaped between runs.

**No invented data.** A field LinkedIn does not publish comes back empty.
Nothing is inferred, averaged or filled in to make a row look complete.

### What people use it for

- **Recruiting intelligence** — track who is hiring, for what, where, and how
  much competition each role has.
- **Talent market research** — measure demand by function, seniority and
  industry across regions over time.
- **Competitor monitoring** — watch a company's hiring as a leading indicator
  of where it is investing.
- **Pay benchmarking** — collect the listings that do publish salary and
  compare by title, level and location.
- **Lead generation** — find companies hiring for roles that signal they need
  what you sell.

### Free accounts

On a free Apify plan a run collects up to 10 job listings, whatever the limits
above say. Nothing beyond that is collected, so a capped run finishes quickly.
Upgrade to a paid plan and the limits above apply in full.

### Good to know

- A search URL is checked for shape, not for results. Whether a search returns
  any jobs is not knowable until collection runs.
- Repeated search URLs are collected once, so a duplicate never costs twice.
- How long a run waits is worked out from how many jobs it could collect — both
  limits and the number of search URLs. There is no setting to guess at.
- If a search cannot be crawled, it is reported in the log and counted in the
  run summary rather than silently dropped.

# Actor input Schema

## `searchUrls` (type: `array`):

One or more LinkedIn jobs search URLs. Every job found behind each URL is collected. Paste the URL straight from the address bar after searching on LinkedIn — the filters already on it (keywords, location, date posted, experience level, remote, salary) are kept.

## `maxJobsPerUrl` (type: `integer`):

Stop after this many jobs from each search URL. Prefilled at 10 so a first run is a quick sample; raise it for a full collection, up to 1,000. Clearing the field collects up to 1,000 per URL.

## `maxJobsTotal` (type: `integer`):

Stop the whole run after this many jobs, across all search URLs together. Leave empty for the maximum of 10,000.

## Actor input object example

```json
{
  "searchUrls": [
    "https://www.linkedin.com/jobs/search?keywords=Software%20Engineer&location=United%20States"
  ],
  "maxJobsPerUrl": 10,
  "maxJobsTotal": 10000
}
```

# Actor output Schema

## `jobs` (type: `string`):

Every job listing collected, one item per job with its company attached.

## `runSummary` (type: `string`):

What was requested, what arrived, and the collection id to resume from if the run stopped waiting.

# 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 = {
    "searchUrls": [
        "https://www.linkedin.com/jobs/search?keywords=Software%20Engineer&location=United%20States"
    ],
    "maxJobsPerUrl": 10
};

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

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

```

## MCP server setup

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