# LinkedIn Jobs Search (`deepmine/linkedin-jobs-search`) Actor

Search LinkedIn jobs by keyword, location and date, or paste search URLs; filter by company, Easy Apply and under 10 applicants. Newest first, past the 1,000-result limit, with description, job type and industry, plus seniority, applicants, pay and job poster when shown. Optional company data.

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

## Pricing

from $0.17 / 1,000 jobs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## LinkedIn Jobs Search

Search LinkedIn jobs by **keywords** (several at once), **location** (several at once) and **posting time**, or paste **LinkedIn job search URLs**, **job URLs** (one row per job) or **company pages** (that company's jobs). Every job comes with its **description**, **job type**, **seniority level**, **industry**, LinkedIn's **applicants** line, **Easy Apply** flag, **company id**, **company logo** and the **search URL** it came from; the **pay range** (with currency, from LinkedIn's pay box, the description or the title), **benefits** and **job poster** (name, headline, LinkedIn profile) come when LinkedIn shows them. Turn on **company details** for each company's website, industry, size, employees, followers, headquarters address, specialties, offices and recent posts. Filter by title words, company (or companies to leave out), job type, experience level, staffing agencies, Easy Apply, under 10 applicants and distance, keep only jobs with pay or a job poster (when LinkedIn shows them), and skip jobs you already have. Most relevant first, like LinkedIn's own search, or newest first past LinkedIn's 1,000-result limit.

| 💼 Title | 🏢 Company | 📍 Location | 🕒 Job Type | 🏭 Industry | 🎓 Level | 📅 Posted |
|---|---|---|---|---|---|---|
| Senior Software Development Engineer, AWS IAM Data Plane | Amazon Web Services (AWS) | Denver, CO | Full-time | IT Services and IT Consulting | Mid-Senior level | 2026-10-01T14:19:00Z |
| Senior Software Engineer - Python | Venmo | Austin, TX | Full-time | Financial Services | Not Applicable | 2026-10-01T10:19:00Z |
| Software Development Engineer, AWS IAM Distributed Database System | Amazon Web Services (AWS) | Seattle, WA | Full-time | IT Services and IT Consulting | Mid-Senior level | 2026-10-01T18:19:00Z |

<sub>Collected 2026-10-01 at 19:19 UTC from the prefilled run ("software engineer", United States, past 24 hours, most relevant first; Apify run xXQPwkgfnsCA8DEfI, build 0.3.40): 100 jobs with details in 12.2 seconds. 98 of the 100 titles name a software, engineering or developer role; these are the first three (first title shortened). A real seniority level was on 87% of the jobs ("Not Applicable" on the rest), the applicant count as a number on 51% and a pay range on 46% (14% from LinkedIn's pay box, the rest written in the description).</sub>

**$0.35 per 1,000 jobs with details** on the Starter plan ($0.39 Free, $0.31 Scale, $0.27 Business), or $0.25 per 1,000 for search cards only ($0.29 Free, $0.21 Scale, $0.17 Business). The prefilled run (100 jobs with details) costs about $0.035. Company details are an optional add-on: $0.07 per 1,000 jobs on every plan.

No LinkedIn account, no cookies, no login.

### Why this one

- **Job posters.** When LinkedIn shows who posted a job ("Direct message the job poster"), you get their name, headline and LinkedIn profile, and those jobs also land in a separate **🧑‍💼 Job Posters** dataset: a ready list of recruiters and hiring managers who are hiring right now. LinkedIn shows a job poster on some jobs: 39 of 1,000 in our 2026-10-01 past-week run, 4 to 15 of 100 in our prefilled runs that day.
- **Details included.** Description, job type, seniority level, industries, LinkedIn's applicants line ("Be among the first 25 applicants", "57 applicants", "Over 200 applicants"), Easy Apply and the company id for every job whose page loads. The level is read from the job's own page: a real level (Entry level, Mid-Senior level, ...) on 87% of the jobs in the prefilled run above. LinkedIn's job panel, which other LinkedIn job scrapers read, says "Not Applicable" far more often: other LinkedIn jobs Actors gave a real level on 27-38% of the jobs in nine of their runs we saved on 2026-10-01 (US searches). Plus what only some jobs show: the pay range (LinkedIn's pay box, else a range written in the description or stated in the title: 46% in the prefilled run above, 39% in the one before it on 2026-10-01; 8-14% from the pay box alone; since build 0.3.44 it also reads ranges written as "142,800.00 - 193,200.00 USD annually", Amazon's form, which takes the prefilled run's 100 jobs from 46% to 85% with pay), benefits (a few %) and the job poster. One price per job. Need only the search cards? Turn details off for a lower price.
- **Company details, when you want them.** Turn on `includeCompanyDetails` and each job with a LinkedIn company page also gets its company's website, industry, size, employees on LinkedIn, followers, headquarters, type, About text and company id (year founded when the page gives it), read from the company's LinkedIn page once per run. It's an add-on you pay only for jobs whose company page was read, and a **🏢 Companies** view lays them out for lead lists.
- **Past the 1,000-result limit.** LinkedIn's job search stops at 1,000 results for any query. For searches with a time period, this Actor goes on past it, so you can get more than 1,000 jobs: in the default **Most relevant** order, LinkedIn's best 1,000 matches come first and then the newest of the rest, window by window; with **Newest first**, the newest jobs window by window from the start. The summary tells you how far back every job is included.
- **Every filter LinkedIn still honours, plus the ones it doesn't.** Company (by name or id), Easy Apply only, under 10 applicants and distance around a city go to LinkedIn. Job type, experience level, "shows pay", "names a job poster" and "no staffing agencies" are read from each job's own page, because LinkedIn's logged-out search ignores them; jobs they leave out aren't charged. Title must / must not include, companies to leave out and job ids to skip work on the search cards, so skipped jobs cost nothing. Several keywords times several locations, or any number of LinkedIn job search URLs, each run as its own search; a job that two searches find comes once, and `searchUrl` says which search found it.
- **Paste jobs or companies.** Job URLs (`linkedin.com/jobs/view/...`) or job ids give one row per job with its details, in the order you pasted them; a job that's no longer on LinkedIn is skipped and not charged. Company pages (`linkedin.com/company/microsoft/`) give that company's jobs anywhere in the world, newest first, read by its LinkedIn company id. Each row's `searchUrl` is the URL you pasted.
- **Most relevant or newest first.** By default jobs come in LinkedIn's own order for your keywords, its best matches first (on "data analyst", US, past 24 hours: 98 of 100 titles named an analyst, 2026-10-01). Pick **Newest first** for alerts and job feeds: rows sorted by posting time, which comes from LinkedIn's "12 minutes ago" / "4 hours ago", so it's exact to the minute for jobs under an hour old and to the hour for jobs under a day old.
- **Fair price, wide rows.** $0.35 per 1,000 jobs with details on Starter, no start fee: under the leading LinkedIn jobs Actors on the Store on every plan (checked 2026-10-01). 43 fields per job with details (62 with company details), from pay currency and benefits to the company's address, offices and recent posts.
- **Honest coverage.** Every run saves a summary (`OUTPUT`) with LinkedIn's own result count, how many jobs you got, and why the run stopped. A run that gets no jobs because LinkedIn refused it, or loses most job details, fails with a clear message instead of passing as a success.
- **Fast and light.** Plain HTTP requests, no browser. The prefilled run (100 jobs with details) took 8.2-12.2 seconds in three runs on 2026-10-01, the first job reaching the dataset 4.3-6.8 seconds after the start; 1,000 jobs with details took 57 seconds (2026-10-01).

### Input

| Field | What it does | Default |
|---|---|---|
| `keywords` | Job title, skill or company, as you'd type it on LinkedIn. Empty = all jobs in the location. | – |
| `location` | Country, state or city, e.g. `United States`, `Texas, United States`, `London, England, United Kingdom`. | `United States` |
| `postedWithin` | `pastHour`, `past24Hours`, `pastWeek`, `pastMonth` or `anyTime`. | `past24Hours` |
| `maxResults` | Stop after this many jobs per search. You pay per job. | 100 |
| `sortBy` | `relevance`: LinkedIn's own order for your keywords, best matches first (up to LinkedIn's 1,000 per search; past that the newest of the rest). `newest`: newest jobs first, window by window past the 1,000 limit; LinkedIn matches keywords more loosely there. Without keywords, jobs always come newest first. | `relevance` |
| `titleIncludes`, `titleExcludes` | Keep only titles naming one of these words or phrases / leave out titles naming any of them (whole words, any case). Not charged. | – |
| `excludeCompanies` | Leave out jobs from these companies (name as LinkedIn shows it, any case, or the company's LinkedIn URL name). Not charged. | – |
| `employmentTypes` | Keep only `Full-time`, `Part-time`, `Contract`, `Temporary`, `Internship`, `Volunteer` or `Other` jobs, read from each job's page (LinkedIn's logged-out search ignores this filter). Jobs left out aren't charged, but the run reads their pages, so it takes longer. | – |
| `experienceLevels` | Keep only `Internship`, `Entry level`, `Associate`, `Mid-Senior level`, `Director`, `Executive` or `Not Applicable` jobs, read from each job's page like `employmentTypes`. | – |
| `requireSalary`, `requireJobPoster`, `excludeStaffingAgencies` | Keep only jobs that show a pay range / name a job poster, or leave out jobs whose industry is Staffing and Recruiting. Read from each job's page; jobs left out aren't charged. | off |
| `includeDetails` | Open each job for its description, job type, industries and Easy Apply, plus seniority, applicants, pay range, benefits and job poster when LinkedIn shows them. Off = search-card fields only, faster and at the lower card price (see Pricing). | on |
| `includeCompanyDetails` | Also open each company's LinkedIn page: website, industry, size, employees on LinkedIn, followers, headquarters (and its street address), type, year founded, slogan, specialties, About text, office locations, affiliated pages, the 5 newest posts and company id. Add-on, $0.07 per 1,000 jobs (see Pricing). | off |
| `easyApply` | Filter: only jobs you can apply to with LinkedIn Easy Apply. | off |
| `under10Applicants` | Filter: only jobs with fewer than 10 applicants so far. | off |
| `companies` | Filter: only these companies. Company names as LinkedIn spells them (`Google`, `Randstad USA`), LinkedIn company ids (the `f_C` number in a LinkedIn jobs URL) or company page URLs. Searched with your keywords and location. A name LinkedIn doesn't know is skipped and named in the run's status. | – |
| `distance` | Filter: miles around the location (a city works best), e.g. `25`. | – |
| `moreKeywords`, `moreLocations` | More keywords and places: each keyword is searched in each place as its own search (`Max results` applies to each, up to 100 searches). | – |
| `searchUrls` | Paste LinkedIn job search URLs (search on linkedin.com/jobs, then copy the address). Each URL is its own search with its own keywords, place, period and filters; the fields above are then not used. LinkedIn's logged-out search doesn't apply job type, experience level or remote/on-site filters, so those parts of a URL are left out (the log says so). | – |
| `companyUrls` | Paste LinkedIn company page URLs (`https://www.linkedin.com/company/microsoft/`). Each company's jobs anywhere in the world, listed in the `postedWithin` period (pick `anyTime` for every open job, up to LinkedIn's 1,000), newest first; `maxResults` applies to each company. `keywords`, `location`, `companies`, `moreKeywords` and `moreLocations` are then not used. A page that doesn't load is skipped and named in the run's status. | – |
| `jobUrls` | Paste LinkedIn job URLs (`https://www.linkedin.com/jobs/view/...`) or job ids: one row per job, read from its page, in the order given, charged as a job with details (details are turned on for the run). A job that's no longer on LinkedIn, or whose page didn't load after retries, is skipped and not charged (`OUTPUT.jobUrls` counts them). The search fields aren't used, and the filters don't apply to these jobs. | – |
| `matchKeywords` | Advanced: skills or words to look for in each job's title and description, e.g. `Python`, `React \| ReactJS` (a `\|` separates spellings of the same skill). Adds `matchedKeywords`, `unmatchedKeywords` and `keywordMatchScore` (% found) to every row. No extra charge. | – |
| `skipJobIds` | Advanced: job ids (or job URLs) you already have, e.g. an earlier run's `jobId` column. Skipped and not charged: handy for scheduled runs that should bring only new jobs. | – |
| `includeHtml` | Advanced: also return the description with LinkedIn's formatting (`descriptionHtml`). | off |
| `geoId` | Advanced: LinkedIn's numeric location id (from a LinkedIn jobs URL). Overrides `location`. | – |
| `proxyConfiguration` | Advanced: leave as is. Apify's automatic (datacenter) proxies, with US residential proxies used only to retry a request LinkedIn refused. If you pick Apify residential, the run still starts on datacenter and uses your residential setup for the retries; any other group or your own proxy URLs are used as given. | Apify automatic |

Example:

```json
{
  "keywords": "software engineer",
  "location": "Texas, United States",
  "postedWithin": "past24Hours",
  "maxResults": 500
}
```

### Output

Two datasets:

- **💼 All Jobs** (default), one row per job. Views: **📊 Overview** (🖼️ Logo, 💼 Title, 🏢 Company, 📍 Location, 💰 Salary, 🕒 Job Type, 🧑‍💼 Job Poster, 📅 Posted, 🔗 LinkedIn, 🌐 Company Page), **📝 Details** (💼 Title, 🏢 Company, 🎓 Level, 🕒 Job Type, 🏭 Industries, 💰 Salary, ✅ Easy Apply, 👥 Applicants, 📝 Description, 🔗 LinkedIn). With company details on, **🏢 Companies (company details on)** (🖼️ Logo, 🏢 Company, 🌍 Website, 🏭 Industry, 📏 Size, 👥 Employees, 📣 Followers, 🏙️ Headquarters, 💼 Title, 🔗 LinkedIn). Salary numbers (`salaryMin`, `salaryMax`, `salaryPeriod`) and `applicants` are in every row and in exports.
- **🧑‍💼 Job Posters**: the same rows, only the jobs that show their job poster (about 4% of jobs in our 2026-10-01 run), in the same order, at no extra charge. View: 🖼️ Logo, 🧑‍💼 Job Poster, 🏷️ Poster Title, 👤 Profile, 💼 Title, 🏢 Company, 📍 Location, 📅 Posted, 🔗 LinkedIn.

Fields, in row order (empty = `null`):

| Field | Example |
|---|---|
| `companyLogo` | `https://media.licdn.com/dms/image/v2/.../company-logo_100_100/...` (doesn't expire) |
| `title` | `Director Of Finance - Hybrid 1 day` |
| `company` | `Randstad USA` |
| `location` | `West Chester, PA` |
| `salary` | `$165,000 - $210,000 per year`: LinkedIn's pay box, else a range written in the description, else pay stated in the title (46% of the jobs in the prefilled run above, 39% in the one before it; 8-14% from the pay box alone) |
| `salaryMin`, `salaryMax` | `165000`, `210000` (numbers, per `salaryPeriod`) |
| `salaryPeriod` | `year`, `month`, `week`, `day` or `hour` |
| `salaryCurrency` | `USD`, `CAD`, `GBP`, `EUR`, ...: from the pay range's symbol and the job's country |
| `salarySource` | `employer` when LinkedIn's pay box says the company provided the range, `linkedin` for LinkedIn's own estimate, `description` when the range was written in the job description, `title` when the title states it (travel-nursing posts like "Travel ICU RN - $1,593 per week") |
| `employmentType` | `Full-time`, `Contract`, `Part-time`, `Internship` |
| `seniority` | `Entry level`, `Associate`, `Mid-Senior level`, `Director`, from the job's own page; `Not Applicable` when the employer gave no level (13% of jobs in the prefilled run) |
| `workplaceType` | `Remote`, `Hybrid` or `On-site` when the job's title or location says so (LinkedIn's logged-out pages don't show the workplace filter's value); else empty |
| `applicants` | `43`; `200` for "Over 200 applicants"; empty for "Be among the first 25 applicants" (a number on 51% of jobs in the prefilled run) |
| `applicantsText` | LinkedIn's applicants line as shown: `Be among the first 25 applicants`, `57 applicants`, `Over 200 applicants` |
| `isEasyApply` | `true`: LinkedIn Easy Apply; `false`: apply on the company's site (closed jobs included) |
| `applyUrl` | Easy Apply jobs: where to apply, their LinkedIn page. Empty for jobs that apply on the company's site: LinkedIn doesn't show that link to logged-out visitors |
| `postedAt` | `2026-09-27T18:13:00Z`: UTC time for jobs under a day old, worked out from LinkedIn's "46 minutes ago" / "4 hours ago" (so exact to the minute under an hour, to the hour under a day); else the date (`2026-09-25`) |
| `postedTimeAgo` | `4 hours ago`: LinkedIn's own wording |
| `isReposted` | `true` when LinkedIn labels the job "Reposted". LinkedIn rarely shows that label logged out (none of the 1,000 jobs in our 2026-10-01 run), so expect `false` |
| `jobState` | `open`, or `closed` when LinkedIn says it's no longer accepting applications |
| `jobUrl` | `https://www.linkedin.com/jobs/view/director-of-finance-hybrid-1-day-at-randstad-usa-4469785573` |
| `companyUrl` | `https://www.linkedin.com/company/randstadusa`; empty when the company has no LinkedIn page |
| `companyWebsite` | Only with `includeCompanyDetails` (examples from Kaiser Permanente's page): `http://kp.org` |
| `companyIndustry` | `Hospitals and Health Care` |
| `companySize` | `10,001+ employees` (LinkedIn's range) |
| `companyEmployeesOnLinkedIn` | `139271`: people on LinkedIn who list the company as their employer |
| `companyFollowers` | `1129824` |
| `companyHeadquarters` | `Oakland, California` |
| `companyType` | `Nonprofit`, `Public Company`, `Privately Held`, ... |
| `companyFounded` | `1945`, when the company gives it |
| `companySlogan` | The company's tagline on LinkedIn, when it has one |
| `companySpecialties` | `["Cars", "Trucks", "Manufacturing", ...]` (General Motors) |
| `companyDescription` | The company's About text on LinkedIn |
| `companyStreetAddress`, `companyCity`, `companyRegion`, `companyPostalCode`, `companyCountry` | The main location's address, e.g. `100 Renaissance Center`, `Detroit`, `Michigan`, `48243`, `US` (General Motors' page) |
| `companyOfficeLocations` | Every location on the company page, main one first: `["100 Renaissance Center Detroit, Michigan 48243, US", ...]` |
| `companyAffiliatedPages` | `[{"name": "Chevrolet", "url": "https://www.linkedin.com/company/chevrolet"}, ...]`: subsidiaries and brands (General Motors) |
| `companyRecentPosts` | The company's 5 newest LinkedIn posts: `[{"postedAt", "text", "likes", "url"}]` |
| `jobPosterName` | Name of the person who posted the job, when LinkedIn shows it |
| `jobPosterTitle` | Their LinkedIn headline, e.g. `Talent Acquisition Partner at Example Co` (made-up example) |
| `jobPosterUrl` | `https://www.linkedin.com/in/...` |
| `jobPosterPhoto` | Their LinkedIn photo, when LinkedIn shows it logged out (rare) |
| `industries` | `Staffing and Recruiting` |
| `benefits` | `["Medical insurance", "401(k)"]`: the benefits the job lists on LinkedIn (a few % of jobs) |
| `jobInsights` | `["Be an early applicant"]`: the search card's badges |
| `yearsOfExperience` | `3` for "3+ years of experience" in the description, when it says (the employer's own history, like "our over 15 years of experience", doesn't count) |
| `contactEmail` | The first email address written in the description |
| `descriptionSnippet` | `We are conducting a confidential search for a Dire…` (first 50 characters) |
| `description` | Full description as plain text: a line per paragraph, `•` list items |
| `descriptionHtml` | Only with `includeHtml`: the description with LinkedIn's formatting |
| `locationCity`, `locationState`, `locationCountry` | The job location split up: `Orlando`, `Florida`, `United States` (only the parts the location names) |
| `jobId` | `4469785573` |
| `companyId` | `1550`: LinkedIn's company id (the `f_C` value in LinkedIn job URLs), from the job's page (or the company page with `includeCompanyDetails`) |
| `searchKeywords` | `data analyst` (empty when you searched all jobs) |
| `searchLocation` | `United States` (or the geoId you gave) |
| `searchUrl` | The search this job came from: the URL you pasted, or your form search as a LinkedIn address, e.g. `https://www.linkedin.com/jobs/search?keywords=data+analyst&location=United+States&f_TPR=r86400` |
| `scrapedAt` | `2026-09-27T18:59:47Z` |

With `includeDetails` off, rows have only `companyLogo`, `title`, `company`, `location`, `workplaceType`, `postedAt`, `postedTimeAgo`, `jobUrl`, `companyUrl`, `jobInsights`, `locationCity`, `locationState`, `locationCountry`, `jobId`, `searchKeywords`, `searchLocation`, `searchUrl` and `scrapedAt` (plus the company fields and `companyId` when `includeCompanyDetails` is on). With `matchKeywords`, `matchedKeywords`, `unmatchedKeywords` and `keywordMatchScore` come right before `descriptionSnippet`. With `includeCompanyDetails` off, the company fields aren't in the rows at all. The company fields are empty for a job without a LinkedIn company page.

LinkedIn doesn't show the company's own application link or its "verified" badge to logged-out visitors (we checked the job page, its mobile and Googlebot versions, LinkedIn's country sites and a US home IP on 2026-10-01), so they aren't included; `isEasyApply` says whether the job takes LinkedIn Easy Apply or sends you to the company's site, and `jobUrl` opens the job on LinkedIn.

#### Run summary (`OUTPUT`)

```json
{
  "results": 200,
  "totalEstimate": 2000,
  "totalIsLowerBound": true,
  "stopReason": "maxResults",
  "complete": false,
  "newestCompleteSeconds": null,
  "resolvedGeoId": "103644278",
  "withJobPoster": 18,
  "withSalary": 14,
  "detailsOk": 200,
  "detailsFailed": 0,
  "detailsRefused": false
}
```

With several searches (more keywords or locations, or search URLs), the summary adds `searches` (each search with its own `results`, `stopReason` and LinkedIn count), `duplicates` (jobs a later search found again, delivered once) and takes the least complete `stopReason`. `unresolvedCompanies` lists company names (and company pages) LinkedIn didn't know. With `jobUrls`, `jobUrls` in the summary counts the URLs given, delivered, no longer on LinkedIn (`notFound`) and not loaded (`failed`).

`stopReason` is one of:

- `complete`: you got every job LinkedIn lists for the search: the jobs read match LinkedIn's count and no page was left unread.
- `maxResults`: you asked for fewer jobs than there are.
- `cap`: the search holds more jobs than LinkedIn will serve. Older jobs are covered as far as LinkedIn allows. `newestCompleteSeconds` says how much of the newest part is complete: every job listed since `newestCompleteSince` is included. It's empty when no part could be confirmed complete, and always empty for `anyTime`, where LinkedIn serves its own top 1,000 rather than the newest. To get more, narrow the search (a state instead of a country, more specific keywords) or use a shorter period and run it on a schedule.
- `incomplete`: some pages didn't load after several retries on other IPs, or the jobs read fell short of LinkedIn's count; the rest was delivered.
- `requestBudget`: the run hit its request limit (it scales with `maxResults`); the jobs found so far were delivered.
- `emitStopped`: your spending limit for the run was reached.
- `timeLimit`: the run was about to reach its timeout (Run options), so it stopped reading new pages shortly before it (90 seconds on a normal timeout, a quarter of the time on a short one) and ended cleanly: every job found until then is in the dataset and charged, and the run counts as succeeded. Give it a longer timeout or lower `maxResults` to get more.

`detailsFailed` counts jobs whose details didn't load after retries on other IPs (their detail fields are empty); `detailsGone` counts postings LinkedIn took down between the search and the detail request. With company details on, `companiesOk`, `companiesFailed` and `companiesGone` count company pages the same way, `companiesWithoutAbout` counts pages that loaded without their About facts (those jobs keep what was read and don't pay the company add-on), and `withCompanyDetails` counts the jobs delivered with the add-on. `timeLimit` is `soft` or `hard` when the run stopped before its timeout. `requestsByProxy` shows how many requests went out on datacenter and how many retries on residential proxies. A request goes to residential only after three datacenter IPs refused it, and only while the run's jobs pay for it (a run never costs more than it earns); `residential` shows their cost, what the run netted (`earnedNetUsd`, at your plan's price) and its other costs, and `keptOnDatacenter`, the retries that stayed on datacenter because the jobs couldn't pay for them (the status message says so too).

A run that ends with 0 jobs fails, unless LinkedIn confirmed on two IPs that the search has no jobs (then it's `complete`). A run with details on where more than half of the job pages didn't load also fails (`detailsRefused: true`), with a message saying so: its jobs are still in the dataset, charged the job-card price (no details add-on). The same goes for company details (`companiesRefused: true`; no company add-on for those jobs).

### How far past 1,000 can it go?

It depends on how big the search is. In our 2026-09-26 test, "python developer" in the United States over the past 24 hours (LinkedIn showed "3,000+") returned 1,100 unique jobs, with the newest ~5 hours complete (811 of the 814 jobs LinkedIn counted for them). In our simulations, a search with ~6,000 matches returns ~2,300 jobs and one with ~30,000 returns ~3,400; for huge searches (all jobs in a country for a month) narrow the location or keywords, or schedule a `pastHour` / `past24Hours` run.

**Tip: job feeds.** Schedule the Actor every hour with `postedWithin: pastHour` (or daily with `past24Hours`) to collect almost every new job in your niche as it's listed. Each run covers the last ~59 minutes (a little under the period), so jobs listed in the short gap between two runs, plus any delay in the scheduled start, can be missed. Runs don't remember each other, so a run with a longer period than the schedule returns some jobs again; dedupe on `jobId`.

### Pricing

Pay per job, no start fee and no minimum. Example: 1,000 jobs with details cost $0.35 on Starter; the prefilled run (100 jobs) costs about $0.035.

| Your Apify plan | Job with details, per 1,000 | Job card only (`includeDetails` off), per 1,000 |
|---|---|---|
| Free | $0.39 | $0.29 |
| Starter | $0.35 | $0.25 |
| Scale | $0.31 | $0.21 |
| Business | $0.27 | $0.17 |

Platinum and Diamond plans pay the Business prices.

Every job in your dataset is charged the job-card price (the **Job** event). A job whose page was read also pays the **Job details** add-on, $0.10 per 1,000 on every plan, whether or not LinkedIn showed a pay range or a job poster on it. So a job with details costs the two together, as in the table. When details are on but a job page couldn't be read (the posting was taken down, or it didn't load after retries; its detail fields are empty and `OUTPUT.detailsFailed` / `detailsGone` count them), that job pays only the card price. A row from a pasted job URL is a job with details (both events); a job URL whose page didn't load isn't delivered or charged. **Company details** (`includeCompanyDetails`, off by default) are a second add-on, the **Company details** event: $0.07 per 1,000 jobs on every plan, charged only for jobs whose company page was read and showed its About facts. A job without a company page, or whose company page didn't load, doesn't pay it. For example, 1,000 jobs with details and company details cost $0.42 on Starter. The 🧑‍💼 Job Posters dataset is free (the same rows again). You're billed only for rows that reach your dataset: the run stops before it would go past your spending limit, and `OUTPUT.results` counts exactly the rows you got; `OUTPUT.rowsByEvent` shows how many jobs were charged (`apify-default-dataset-item`), how many of them with details (`job-details`) and with company details (`company-details`).

### FAQ

**Do I need a LinkedIn account?** No. The Actor only reads what LinkedIn shows logged-out visitors.

**Why do only some jobs have a job poster or a salary?** LinkedIn shows a job poster only when the poster chose to (4% of jobs in our 1,000-job run on 2026-10-01). Pay comes from LinkedIn's pay box or, when there's none, from a range written in the description or stated in the title (`salarySource` says which); jobs that state no pay anywhere have none.

**Why is the applicant count empty on some jobs?** LinkedIn shows a number only past 25 applicants; below that it says "Be among the first 25 applicants", which `applicantsText` keeps word for word. `seniority` says `Not Applicable` when the employer gave no level.

**Where's the job function?** LinkedIn stopped showing it to logged-out visitors on 2026-10-01, so it's no longer in the rows, and LinkedIn's job-function search filter is ignored logged out too (checked 2026-10-01). The leading LinkedIn job scrapers we checked don't return it for new jobs either (2026-10-01). The industries are still there.

**Which locations work?** Anything LinkedIn's own location box understands. `OUTPUT.resolvedGeoId` shows the place LinkedIn picked; if a name is ambiguous, spell it out or pass `geoId`. For example "Washington, United States" means the D.C. area to LinkedIn; the state is "Washington State, United States".

**Why do some jobs have no company page?** Some postings (often staffing agencies) have no LinkedIn company page; `companyUrl` is empty for them.

### Feedback

Missing a field, or a search that doesn't come back the way you expect? Open an issue on the **Issues** tab and we'll look into it. If the data helps you, a short review on this page helps other people find it.

# Actor input Schema

## `keywords` (type: `string`):

As you'd type it in LinkedIn's job search, e.g. software engineer, nurse, Python. Empty = all jobs in the location. More keywords: see Search more below.

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

Country, state or city, e.g. United States, Texas, United States or London, England, United Kingdom.

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

With a time period, a search goes past LinkedIn's 1,000-result limit, window by window. Any time stops at 1,000.

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

Each keyword × location (or each pasted URL) is one search. You pay per job.

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

Opens each job: description, job type, seniority, industries, applicants, Easy Apply, pay range, benefits and the job poster (name, headline, profile) when LinkedIn shows them. A small add-on per job (see Pricing). Off: search-card fields only, faster.

## `includeCompanyDetails` (type: `boolean`):

Opens each company page once: website, industry, size, employees on LinkedIn, followers, headquarters and address, specialties, description, locations and newest posts. A small add-on, charged only for jobs whose company page was read (see Pricing).

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

Search on linkedin.com/jobs, then copy the address. Each URL is its own search with its own keywords, place and period; the fields above are then not used. Job type, experience and remote filters in a URL are left out (LinkedIn's logged-out search ignores them; use the filters below).

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

Most relevant: LinkedIn's best matches first, as on linkedin.com. Newest first: matches keywords more loosely. Without keywords, always newest first.

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

Pick one or more. Read from each job's page, so the run takes longer.

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

Pick one or more. Read from each job's page.

## `requireSalary` (type: `boolean`):

A pay range in LinkedIn's pay box, the description or the title.

## `requireJobPoster` (type: `boolean`):

The recruiter or hiring manager who posted it.

## `excludeStaffingAgencies` (type: `boolean`):

Jobs whose page lists the industry Staffing and Recruiting.

## `easyApply` (type: `boolean`):

Only jobs you can apply to with LinkedIn Easy Apply.

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

Only jobs with fewer than 10 applicants so far.

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

Only jobs within this distance of the location (a city works best).

## `titleIncludes` (type: `array`):

At least one of these words or phrases (whole words, any case), e.g. analyst or "data scientist".

## `titleExcludes` (type: `array`):

Any of these words or phrases, e.g. senior, intern, manager.

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

The name as LinkedIn shows it (any case) or the company's LinkedIn URL name, e.g. randstad-usa.

## `moreKeywords` (type: `array`):

Each one is searched in each location, e.g. data analyst, business analyst. Max jobs applies to each search; a job found twice comes once.

## `moreLocations` (type: `array`):

Searched with each keyword, e.g. Austin, Texas, United States or Canada.

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

Searched with your keywords and location: names as LinkedIn spells them (Google, Randstad USA), company ids (f_C in a LinkedIn jobs URL) or company page URLs. A name LinkedIn doesn't know is skipped and named in the run's status.

## `companyUrls` (type: `array`):

Company page URLs, e.g. https://www.linkedin.com/company/microsoft/: each company's jobs worldwide in the Posted within period (Any time = every open job, up to 1,000), newest first. Keyword and location fields are then not used.

## `jobUrls` (type: `array`):

https://www.linkedin.com/jobs/view/... links or job ids: one row per job, with details. A job no longer on LinkedIn is skipped and not charged. Search fields and filters don't apply.

## `includeHtml` (type: `boolean`):

Adds descriptionHtml with LinkedIn's formatting. The plain-text description is always there. Free.

## `matchKeywords` (type: `array`):

Skills to look for in each job, e.g. Python or React | ReactJS (| separates spellings). Adds matchedKeywords, unmatchedKeywords and keywordMatchScore (% found). Free.

## `skipJobIds` (type: `array`):

Job ids or URLs you already have (an earlier run's jobId column): skipped and not charged. For scheduled runs that should bring only new jobs.

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

The numeric geoId from a LinkedIn jobs URL. Overrides Location.

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

Leave as is: Apify datacenter proxies, with US residential used only to retry a request LinkedIn refused.

## Actor input object example

```json
{
  "keywords": "software engineer",
  "location": "United States",
  "postedWithin": "past24Hours",
  "maxResults": 100,
  "includeDetails": true,
  "includeCompanyDetails": false,
  "sortBy": "relevance",
  "requireSalary": false,
  "requireJobPoster": false,
  "excludeStaffingAgencies": false,
  "easyApply": false,
  "under10Applicants": false,
  "includeHtml": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

## `jobPostersUrl` (type: `string`):

No description

## `summary` (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 = {
    "keywords": "software engineer",
    "maxResults": 100,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("deepmine/linkedin-jobs-search").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 = {
    "keywords": "software engineer",
    "maxResults": 100,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("deepmine/linkedin-jobs-search").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 '{
  "keywords": "software engineer",
  "maxResults": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call deepmine/linkedin-jobs-search --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,deepmine/linkedin-jobs-search"
        }
    }
}
```

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/0IXbIKrdAJaQ1rQVM/builds/lTprmNV86TVAsGeBg/openapi.json
