# LinkedIn Jobs Scraper — Search, Company Jobs & Job Details (`sian.agency/linkedin-jobs-scraper`) Actor

Scrape LinkedIn job postings with the exact posting date, employer logo and LinkedIn URL, apply links, seniority, job function, industries, applicant count and structured salary. Search by keyword, list every open job at up to 10 companies, or batch full details for up to 20 job ids.

- **URL**: https://apify.com/sian.agency/linkedin-jobs-scraper.md
- **Developed by:** [SIÁN OÜ](https://apify.com/sian.agency) (community)
- **Categories:** Jobs, Lead generation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.64 / 1,000 search 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 — Jobs, Salaries & Exact Posting Dates 🚀

[![Store SIÁN Agency](https://img.shields.io/badge/Store-SI%C3%81N%20Agency-1AE392)](https://apify.com/sian.agency?fpr=sian) [![Store Jobs Search API](https://img.shields.io/badge/Store-Jobs%20Search%20API-1AE392)](https://apify.com/sian.agency/jsearch-jobs-scraper?fpr=sian) [![Store Glassdoor Scraper](https://img.shields.io/badge/Store-Glassdoor%20Scraper-0CAA41)](https://apify.com/sian.agency/glassdoor-data-scraper?fpr=sian) [![Store Active Job Postings](https://img.shields.io/badge/Store-Active%20Job%20Postings-0077B5)](https://apify.com/sian.agency/active-job-postings-scraper?fpr=sian)

#### 🎉 Every job carries its exact posting date — not "2 weeks ago"

##### Built for recruiters, job boards and anyone whose analysis breaks on a relative date

***

### 🔎 What is the LinkedIn Jobs Scraper — and when should you use it?

The **LinkedIn Jobs Scraper** turns public LinkedIn job postings, with the exact date each one went up into clean, structured rows you can filter, export and feed straight into a spreadsheet, database or AI agent. No account, no portal API key, no browser automation to maintain.

**Use it when you need:** LinkedIn job postings as rows: title, employer and the employer's LinkedIn company page, location, the exact posting date rather than a relative label, and the full description with working apply links. Each row also carries seniority level, job function, industries, applicant count, hiring badges, and a structured salary range wherever LinkedIn publishes one. Every job names its employer's numeric LinkedIn company id too, so jumping from one interesting posting to that company's whole open-role list is a single follow-up run.

**Use something else when:** the roles are not on LinkedIn, or one job board is not enough. Use [Jobs Search API](https://apify.com/sian.agency/jsearch-jobs-scraper?fpr=sian) for Indeed, Glassdoor and other boards aggregated into this same row shape. Use [Active Job Postings Scraper](https://apify.com/sian.agency/active-job-postings-scraper?fpr=sian) for roles read straight from 90,000+ employer applicant-tracking systems instead of a job board. Use [Glassdoor Scraper](https://apify.com/sian.agency/glassdoor-data-scraper?fpr=sian) for employer reviews, salary reports and interview notes rather than open roles. This actor covers LinkedIn's public, logged-out jobs surface. It cannot return anything that lives behind a LinkedIn login: there is no job-poster profile, no recruiter contact, no applicant insight and no employer applicant-tracking link. LinkedIn also caps any single result set at 1,000 jobs for everyone, so a broader pull has to be split by city or by narrower keywords.

### 🤖 Use with AI agents

Already connected to the [Apify MCP server](https://mcp.apify.com)? Just ask for this Actor by name: sian.agency/linkedin-jobs-scraper

**Your agent can pay for its own runs.** This Actor is eligible for [agentic payments](https://docs.apify.com/platform/actors/publishing/monetize), so an agent can discover it, run it and settle the bill over [x402](https://www.x402.org/) (USDC on Base) or [Skyfire](https://www.skyfire.xyz/) — without an Apify account or API token of its own. Billing is the same either way: per successful row, never for errors.

Otherwise copy this prompt into Claude, ChatGPT, Cursor or any MCP-enabled assistant:

```text
I want LinkedIn job postings, salaries and exact posting dates using the Apify Actor `sian.agency/linkedin-jobs-scraper`.

Use it when I need: LinkedIn job postings as rows: title, employer and the employer's LinkedIn company page, location, the exact posting date rather than a relative label, and the full description with working apply links. Each row also carries seniority level, job function, industries, applicant count, hiring badges, and a structured salary range wherever LinkedIn publishes one. Every job names its employer's numeric LinkedIn company id too, so jumping from one interesting posting to that company's whole open-role list is a single follow-up run.

Don't use it when: the roles are not on LinkedIn, or one job board is not enough — use jsearch-jobs-scraper or active-job-postings-scraper or glassdoor-data-scraper instead.

How to call it: pick one `operation` per run. `search` finds jobs by keyword: give it `query`, optionally a free-text `location` such as "Berlin, Germany", and `maxResults`. `companyJobs` returns every open role at up to 10 companies at once, named in `companyIds` as numeric ids or in `companies` as vanity slugs and company page URLs. `jobDetails` re-fetches up to 20 already-known jobs per call from `jobIds`; it is billed per job id, so it is for refreshing a shortlist rather than bulk collection. `datePosted` narrows to the last day, three days, week or month and is applied by LinkedIn itself, so it costs nothing extra. `employmentTypes` and `seniorityLevels` are applied after fetching instead, because LinkedIn ignores its own versions when logged out; they return fewer rows and cost more to run. `radiusKm` needs `geoId`, since LinkedIn ignores a radius on a free-text location. `includeDetails` is on by default and fills the description, salary, seniority, function and industries; turning it off is about 3x faster and leaves those empty. A search page returns 10 fully-detailed jobs for the price of one request, so collecting descriptions and salaries through `search` costs far less per job than looping `jobDetails`..

Start with this input:
{
  "operation": "search",
  "query": "software engineer",
  "location": "United States",
  "datePosted": "week",
  "maxResults": 50
}

Ask me which role or keyword they want, which location, and whether they need the full description and salary or only the faster card-level fields, then run the Actor and summarise the results as a table.
```

**Things you can ask your agent for:**

- *Find senior backend roles posted in Berlin this week and show which ones publish a salary range.*
- *List every open job at Microsoft, Stripe and Datadog, grouped by job function and seniority.*
- *Re-check these job ids and tell me which postings have closed since last month.*

Machine-readable API, MCP config and OpenAPI definition for this Actor are published at [apify.com/sian.agency/linkedin-jobs-scraper.md](https://apify.com/sian.agency/linkedin-jobs-scraper.md).

### 📋 Overview

**LinkedIn publishes a date. Most scrapers hand you a shrug.** This Actor returns LinkedIn job postings as structured rows, with the real calendar date on every search result, so freshness is something you can compute instead of estimate.

**Why professionals choose us:**

- ✅ **Exact posting dates**: every search row carries the real date and a midnight-UTC timestamp, plus LinkedIn's own label if you still want it
- ⚡ **Three jobs in one Actor**: keyword search, every open role at up to 10 companies, and batch detail for up to 20 job ids
- 🎯 **47 fields per job**: description, salary range, seniority, job function, industries, applicant count, hiring badges, employer logo and company page
- 💰 **Charged per job, never per attempt**: a search that matches nothing and a closed posting both cost you nothing
- 💎 **Drop-in compatible**: the row shape matches our [Jobs Search API](https://apify.com/sian.agency/jsearch-jobs-scraper?fpr=sian), so adding LinkedIn to an existing pipeline needs no re-mapping
- 🔓 **No login, ever**: reads LinkedIn's public pages, so there is no account of yours to restrict and no credential to hand over

***

### ✨ Features

- 🔍 **Keyword search**: job title, skill or free text, anywhere in the world
- 🏢 **Company job lists**: up to 10 companies per run, by numeric id, vanity slug or plain company URL
- 📋 **Batch job details**: refresh up to 20 known job ids in one call, for keeping a saved shortlist current
- 🗓️ **Real dates**: exact posting date, UTC timestamp, and LinkedIn's relative label side by side
- 💰 **Structured salary**: minimum, maximum, period and currency as separate numeric fields
- 📈 **Seniority and function**: LinkedIn's own vocabulary, not a guessed years-of-experience number
- 👥 **Applicant counts**: find roles that are open but not yet crowded
- 🌍 **Global coverage**: free-text locations worldwide, or a LinkedIn geo id with a radius in kilometres
- 🎚️ **Freshness filter**: last 24 hours, 3 days, week or month, applied by LinkedIn itself
- 📄 **Run report**: every run writes an HTML summary with your rows, your costs and a fix for anything that failed

***

### 🎬 Quick Start

Pick an operation, give it a keyword or a company, and run. Results land in your dataset as JSON, CSV or Excel. A free run returns up to 25 jobs so you can see the shape before you spend anything.

```bash
curl -X POST "https://api.apify.com/v2/acts/sian.agency~linkedin-jobs-scraper/runs?token=YOUR_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"operation": "search", "query": "software engineer", "location": "United States"}'
```

***

### 🚀 Getting Started (3 Simple Steps)

#### Step 1: Choose an operation

**Search Jobs** for keyword discovery, **Company Jobs** to list everything open at named companies, or **Job Details** to refresh job ids you already hold.

#### Step 2: Fill in the one field that operation needs

A keyword for search, a company id or slug for company jobs, a list of job ids for details. Everything else has a working default.

#### Step 3: Run it and open your dataset

Export to JSON, CSV or Excel, or read it straight from the API.

**That's it. In under a minute, you'll have:**

- Structured job rows with employers, locations and exact posting dates
- Salary ranges wherever LinkedIn published one
- Working apply links and employer LinkedIn pages

***

### 📥 Input Configuration

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `operation` | string | Yes | `search`, `companyJobs` or `jobDetails` |
| `query` | string | For search | Job title, skill or free text |
| `location` | string | No | Free-text location, e.g. "Berlin, Germany" |
| `geoId` | string | No | LinkedIn numeric geo id, needed for a radius |
| `radiusKm` | integer | No | Radius in kilometres around the geo id |
| `datePosted` | string | No | `all`, `today`, `3days`, `week`, `month` |
| `employmentTypes` | array | No | Full-time, part-time, contract, internship |
| `seniorityLevels` | array | No | LinkedIn's seniority vocabulary |
| `remoteOnly` | boolean | No | Only postings with an explicit remote marker |
| `companyIds` | array | For companyJobs | Up to 10 LinkedIn company ids |
| `companies` | array | For companyJobs | Up to 10 company slugs or page URLs |
| `jobIds` | array | For jobDetails | Up to 20 job ids per call |
| `includeDetails` | boolean | No | Fetch each job's detail page (default `true`) |
| `sortBy` | string | No | `relevance` or `date` |
| `maxResults` | integer | No | Upper bound on jobs returned (max 1000) |
| `country` | string | No | Two-letter country code, default `us` |

**Search example:**

```json
{
  "operation": "search",
  "query": "data engineer",
  "location": "Berlin, Germany",
  "datePosted": "week",
  "maxResults": 100
}
```

**Company jobs example:**

```json
{
  "operation": "companyJobs",
  "companies": ["microsoft", "stripe"],
  "datePosted": "month"
}
```

**Job details example:**

```json
{
  "operation": "jobDetails",
  "jobIds": ["bGlua2VkaW46NDQ1MzY3MDk3Mw"]
}
```

***

### 📤 Output

Every job is written to the dataset with **47 fields**. The most-used ones:

| Field | Type | Description |
|-------|------|-------------|
| `jobTitle` | string | The posting's title |
| `employerName` | string | Company name |
| `employerLogo` | string | Company logo image |
| `employerLinkedinUrl` | string | The employer's LinkedIn company page |
| `linkedinCompanyId` | string | Numeric company id, feeds straight into Company Jobs |
| `location` | string | LinkedIn's location string, verbatim |
| `postedAtDate` | string | **The exact posting date** |
| `postedAtTimestamp` | integer | Midnight UTC of the posting date |
| `salaryString` | string | Salary as LinkedIn prints it |
| `minSalary` / `maxSalary` | number | Structured salary range |
| `salaryPeriod` | string | `YEAR`, `MONTH`, `HOUR` |
| `seniorityLevel` | string | LinkedIn's seniority label |
| `jobFunction` | string | e.g. "Engineering and Information Technology" |
| `industries` | array | Employer industries |
| `applicantsCount` | integer | How many people have applied |
| `applyLink` | string | Public LinkedIn posting URL |
| `jobDescription` | string | Full posting text, typically 5,000–10,000 characters |

**Example row (trimmed):**

```json
{
  "jobId": "bGlua2VkaW46NDQ1MzY3MDk3Mw",
  "jobTitle": "Software Engineer III (Java/AWS)",
  "employerName": "JPMorganChase",
  "employerLinkedinUrl": "https://www.linkedin.com/company/jpmorganchase",
  "linkedinCompanyId": "1068",
  "location": "New York, NY",
  "postedAtDate": "2026-09-03",
  "postedAtTimestamp": 1788393600,
  "salaryString": "$137,750.00/yr - $185,000.00/yr",
  "minSalary": 137750,
  "maxSalary": 185000,
  "salaryPeriod": "YEAR",
  "seniorityLevel": "Not Applicable",
  "jobFunction": "Engineering and Information Technology",
  "industries": ["Financial Services"],
  "applicantsCount": 194,
  "applyLink": "https://www.linkedin.com/jobs/view/software-engineer-iii-java-aws-at-jpmorganchase-4453670973"
}
```

***

### 💼 Use Cases & Examples

#### 1. Recruiting Pipeline and Talent Sourcing

**Recruiters and agencies tracking which roles are open, and how contested they are.**

**Input:** a job title and a location, on a daily schedule
**Output:** open postings with exact dates, seniority and applicant counts
**Use:** pitch candidates at roles that are fresh and not yet crowded, using posting age and applicant count together.

#### 2. Competitor Hiring Intelligence

**Strategy and product teams watching where a rival is investing.**

**Input:** up to 10 competitor companies in one Company Jobs run
**Output:** every open role at each, with function, seniority and location
**Use:** spot a team scaling, a new office opening, or a hiring freeze starting, weeks before it is announced.

#### 3. Compensation Benchmarking

**Comp analysts and founders setting bands they can defend.**

**Input:** a job function and market, collected weekly
**Output:** structured minimum, maximum, period and currency per posting
**Use:** build a real salary time series, because exact dates make weekly cohorts trustworthy.

#### 4. Job Board and Aggregator Content

**Operators filling a niche board without a content team.**

**Input:** a keyword set with `datePosted` set to `today`
**Output:** fresh postings with employer logo, company URL and apply link
**Use:** import only genuinely new roles each day instead of re-importing the same backlog.

#### 5. Labor Market and Hiring Trend Analytics

**Researchers and data teams measuring demand over time.**

**Input:** broad queries across industries and seniority levels
**Output:** posting volume tagged by function, industry and seniority
**Use:** build monthly hiring indices that hold up, which relative labels such as "2 weeks ago" cannot support.

#### 6. Lead Generation from Hiring Signals

**Sales teams selling tools to a specific role.**

**Input:** the job title your product serves
**Output:** employers hiring for it, with LinkedIn company page and id
**Use:** a company hiring a data engineer is a company buying data tooling, so reach out while the req is open.

#### 7. Refreshing a Saved Job Shortlist

**Anyone maintaining a curated list of roles.**

**Input:** up to 20 stored job ids per call
**Output:** current detail for each, with closed postings simply absent
**Use:** detect filled roles: a missing id is a closed req. Billed per job id, so use it to refresh a shortlist rather than to collect in bulk.

***

### 🔗 Integration Examples

#### JavaScript/Node.js

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });

const run = await client.actor('sian.agency/linkedin-jobs-scraper').call({
  operation: 'search',
  query: 'software engineer',
  location: 'United States',
  datePosted: 'week',
});

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

#### Python

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')

run = client.actor('sian.agency/linkedin-jobs-scraper').call(
    run_input={
        'operation': 'search',
        'query': 'software engineer',
        'location': 'United States',
        'datePosted': 'week',
    }
)

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

#### cURL

```bash
curl -X POST 'https://api.apify.com/v2/acts/sian.agency~linkedin-jobs-scraper/runs?token=YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"operation": "search", "query": "software engineer", "location": "United States"}'
```

#### Automation Workflows (N8N / Zapier / Make)

1. **Trigger**: a daily schedule
2. **HTTP Request**: run the Actor with `datePosted: "today"`
3. **Process**: filter the rows on seniority or salary
4. **Action**: append to a sheet, post to Slack, or create CRM records

***

### 📊 Performance & Pricing

#### FREE Tier (Try It Now)

- **25 jobs** per run, every field, same quality
- No credit card required
- Enough to see the row shape and check the fields you need

#### PAID Tier (Production Ready)

- **Unlimited** jobs per run, up to LinkedIn's own 1,000-per-search ceiling
- Pay per job written to your dataset. A search that matches nothing costs nothing

💰 **You are charged for jobs, not attempts.** Failed inputs, closed postings and empty searches are all free.

🔗 [View current pricing](https://apify.com/sian.agency/linkedin-jobs-scraper?fpr=sian)

***

### ❓ Frequently Asked Questions

**Q: Do I need a LinkedIn account, cookies or a session?**
A: No. This Actor reads LinkedIn's public, logged-out job pages. There is no account to connect and nothing of yours at risk.

**Q: Is the posting date the real date, or LinkedIn's "2 weeks ago"?**
A: The real date. Every search row carries the calendar date and a midnight-UTC timestamp, and LinkedIn's own label is kept alongside it. On Job Details the date is derived from the relative label and can be a few days out, so Search Jobs is the authoritative source for exact dates.

**Q: How many jobs can one search return?**
A: Up to 1,000. LinkedIn serves 10 per page and caps any single result set at 100 pages, for everyone. Split by city or narrower keywords to go further.

**Q: Why did "Remote jobs only" return almost nothing?**
A: LinkedIn's public payload has no workplace-type field, so the remote flag is matched from wording in the title or location. It under-returns on purpose: a row marked remote really is remote, but many remote jobs are never marked.

**Q: Can I get every open job at a specific company?**
A: Yes, that is the Company Jobs operation. Give it up to 10 companies as ids, slugs such as "microsoft", or company page URLs.

**Q: Why are description, salary and seniority empty on some runs?**
A: Those live on a job's detail page, not on a search card. They fill whenever "Fetch full job details" is on, which is the default. Turning it off makes a run roughly 3x faster and leaves them empty.

**Q: Does this return the employer's own application link?**
A: No. The apply link is the public LinkedIn posting URL. The employer's own system sits behind LinkedIn's login wall and is not in the public payload.

**Q: What export formats are available?**
A: JSON, CSV and Excel, straight from the Apify dataset, or over the API.

**Q: Which operation is cheapest per job?**
A: Search Jobs and Company Jobs, by a wide margin. A single search page returns 10 fully-detailed jobs for one unit of cost, while Job Details is billed per job id. Collect with Search Jobs; use Job Details only to refresh ids you already hold.

***

### 🐛 Troubleshooting

**A search returned zero jobs**

- Widen `datePosted`: `today` is a narrow window
- Drop `employmentTypes` and `seniorityLevels`: LinkedIn ignores its own versions of these, so they are applied afterwards and cut results hard
- Try the location as free text ("Berlin, Germany") rather than a geo id

**Company Jobs returned nothing**

- A numeric company id that does not exist returns the same empty result as a real company with no open roles
- Pass the slug instead (`microsoft`), which fails loudly and names itself

**"Radius needs a LinkedIn Geo ID"**

- LinkedIn ignores a radius when the location is free text, so the pair is rejected rather than silently dropped
- Copy the `geoId=` value from a linkedin.com/jobs search URL, or remove the radius

**One of the companies in my list broke the whole run**

- One unknown slug fails the request. Remove it, or use numeric ids, which cannot fail to resolve

***

### ⚖️ Is it legal to scrape data?

Our actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our actors, when used for ethical purposes by Apify users, are safe.

However, you should be aware that your results could contain personal data. Personal data is protected by the **GDPR** in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

You can also read Apify's blog post on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

LinkedIn is a trademark of LinkedIn Corporation, a Microsoft subsidiary. This Actor is not affiliated with, endorsed by, or sponsored by LinkedIn.

***

### 🤝 Support

**Join our active support community**

- For issues or questions, open an issue in the actor's repository
- Check [SIÁN Agency Store](https://apify.com/sian.agency?fpr=sian) for more automation tools
- 📧 <apify@sian-agency.online>

***

**Built by [SIÁN Agency](https://www.sian-agency.online)** | **[More Tools](https://apify.com/sian.agency?fpr=sian)**

# Changelog

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

# Actor input Schema

## `operation` (type: `string`):

Pick one operation per run. Search Jobs and Company Jobs both page LinkedIn 10 jobs at a time; Job Details refreshes up to 20 known job ids in a single call.

## `query` (type: `string`):

Job title, skill or free-text phrase to search for, exactly as you would type it into LinkedIn's own keyword box. Required by Search Jobs. Optional for Company Jobs, where it narrows the results to matching postings within the selected companies — leave it empty there to get the company's whole job list.

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

Free-text location, written the way LinkedIn writes it: "United States", "London, United Kingdom", "Berlin, Germany". Works worldwide with no geo id. LinkedIn ignores a search radius when the location is free text, so pair Geo ID with Radius if you need a radius.

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

LinkedIn's own numeric location id, for example 102571732 (New York City) or 103644278 (United States). Take it from the geoId= parameter of a linkedin.com/jobs search URL. Required if you want Radius to take effect; LinkedIn has no geo-id lookup on this surface.

## `radiusKm` (type: `integer`):

Search radius in kilometres around the Geo ID, converted to the miles LinkedIn expects. Needs Geo ID — a radius with a free-text location is rejected, because LinkedIn silently ignores it.

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

Freshness window, applied by LinkedIn itself rather than filtered afterwards, so it does not cost extra pages. Maps exactly onto LinkedIn's own windows: 24 hours, 72 hours, 7 days, 30 days.

## `employmentTypes` (type: `array`):

Keep only these employment types. Pick any combination; leave empty for every type. LinkedIn ignores its own job-type filter on the logged-out surface, so this is applied after fetching: it over-fetches up to 3x the pages to refill the results, which costs more to run and returns fewer rows than an unfiltered run.

## `seniorityLevels` (type: `array`):

Keep only these seniority levels, in LinkedIn's own vocabulary. Pick any combination; leave empty for every level. Applied after fetching with the same extra cost as Employment types. Deliberately LinkedIn's wording rather than a years-of-experience number, because there is no honest mapping from "Mid-Senior level" to a year count.

## `remoteOnly` (type: `boolean`):

Keep only postings carrying an explicit remote marker. Best-effort and deliberately low-recall: LinkedIn's logged-out payload has no workplace-type field, so this matches wording in the title or location. It under-returns rather than over-returns, and many queries return few or no rows with it on.

## `companyIds` (type: `array`):

Used by Company Jobs. LinkedIn numeric company ids, up to 10, combined as OR. Every job this actor returns carries its employer's id as linkedinCompanyId, so "more jobs at this company" is one follow-up run. LinkedIn ranks the union by relevance, so a small company paired with a large one can be missing from the first page.

## `companies` (type: `array`):

Used by Company Jobs. LinkedIn company vanity slugs or company page URLs, up to 10 — "microsoft", "/company/microsoft" and the full URL all work. Each one is resolved to an id live, which adds one extra lookup per slug. An unknown slug fails the whole run, which is the fastest way to catch a typo.

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

Used by Job Details. Up to 20 job ids per call, as returned in the jobId field of any search. The raw numeric LinkedIn posting id (jobUid) is accepted too. Duplicates are collapsed before the 20 cap applies. An id LinkedIn has taken down is simply absent from the results rather than returned as an empty shell.

## `includeDetails` (type: `boolean`):

Open each job's detail page to fill the fields a search card cannot carry: full description, employment type, salary, seniority level, job function, industries, applicant count and the employer's LinkedIn company id. Turn it off for a roughly 3x faster, card-only run. It is forced back on whenever Employment types or Seniority levels are in use.

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

Date sorts the jobs inside this run's results newest-first. It cannot re-rank LinkedIn's result set, because LinkedIn ignores its own sort on the logged-out surface — pair it with Date posted, or with a larger result cap, for a genuinely fresh list.

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

Upper bound on jobs returned by Search Jobs and Company Jobs. LinkedIn serves 10 per page and caps any single result set at 1000, so this is rounded up to whole pages. Job Details ignores it and returns one row per job id you supply.

## `country` (type: `string`):

Two-letter country code. It picks which country the request is made from and fills in the country on a posting whose own location does not name one. It is not the geography filter — use Location or Geo ID for that.

## Actor input object example

```json
{
  "operation": "search",
  "query": "software engineer",
  "location": "United States",
  "geoId": "102571732",
  "datePosted": "all",
  "remoteOnly": false,
  "includeDetails": true,
  "sortBy": "relevance",
  "maxResults": 50,
  "country": "us"
}
```

# Actor output Schema

## `linkedinJobs` (type: `string`):

Every job this run returned.

## `scrapingSummary` (type: `string`):

HTML summary showing successful and failed results with key metrics

# 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 = {
    "operation": "search",
    "query": "software engineer",
    "location": "United States",
    "datePosted": "all",
    "remoteOnly": false,
    "includeDetails": true,
    "sortBy": "relevance",
    "maxResults": 50,
    "country": "us"
};

// Run the Actor and wait for it to finish
const run = await client.actor("sian.agency/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 = {
    "operation": "search",
    "query": "software engineer",
    "location": "United States",
    "datePosted": "all",
    "remoteOnly": False,
    "includeDetails": True,
    "sortBy": "relevance",
    "maxResults": 50,
    "country": "us",
}

# Run the Actor and wait for it to finish
run = client.actor("sian.agency/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 '{
  "operation": "search",
  "query": "software engineer",
  "location": "United States",
  "datePosted": "all",
  "remoteOnly": false,
  "includeDetails": true,
  "sortBy": "relevance",
  "maxResults": 50,
  "country": "us"
}' |
apify call sian.agency/linkedin-jobs-scraper --silent --output-dataset

```

## MCP server setup

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