LinkedIn Jobs Scraper – Job Postings by Keyword & Place avatar

LinkedIn Jobs Scraper – Job Postings by Keyword & Place

Pricing

from $0.30 / 1,000 job returneds

Go to Apify Store
LinkedIn Jobs Scraper – Job Postings by Keyword & Place

LinkedIn Jobs Scraper – Job Postings by Keyword & Place

Scrape public LinkedIn job postings for any keyword and place: title, company, location, posted date, link, full description, seniority, employment type, industries, applicants and salary. Filter by date posted, company, Easy Apply and under-10 applicants. No login, no key, no browser. Unofficial.

Pricing

from $0.30 / 1,000 job returneds

Rating

0.0

(0)

Developer

Simple Actor

Simple Actor

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

a day ago

Last modified

Share

Scrape public LinkedIn job postings as structured data. Give it a keyword and a place — "software engineer" in "United States", "registered nurse" in "Texas, United States", "marketing manager" in "London, England, United Kingdom" — and every job LinkedIn lists for the search comes back as a row: title, company, location, posted date, link and, by default, the full description with seniority level, employment type, industries, applicant count and the salary where the posting states one. In LinkedIn's own order, up to the 1,000 jobs LinkedIn shows for any search.

Built for job-market research, recruiting, lead generation (a company that is hiring is a company that is buying) and job boards: every open role of a kind in a place, with the text to read and the id to deduplicate on.

No login, no cookies, no API key, no browser, no account of yours involved. It reads what LinkedIn shows to anyone who opens a job search without signing in.

$0.30 per 1,000 jobs — $0.03 for a default 100-job search — plus Apify's standard $0.00005 per run start. Apify platform usage included, nothing else to pay. A search that cannot be read, a job that is not delivered and a job you told it to skip are never charged.

Unofficial. Not affiliated with, endorsed by, or sponsored by LinkedIn.

Features

  • The whole posting, per job — description as text and as HTML, seniority level, employment type, industries, applicant count, pay range when stated, whether it applies on LinkedIn or on the employer's site, and whether it has closed.
  • Everything LinkedIn lists — paged automatically to the end of LinkedIn's own results, up to the 1,000 jobs LinkedIn shows for a search, with no job twice.
  • The filters LinkedIn still honours — posted within any window down to a minute, one or more companies by name or id, Easy Apply only, under 10 applicants only, and a distance around a city.
  • Places resolved and echoed — every place goes through LinkedIn's own place lookup, and each row says which place and which LinkedIn geoId it was searched in. A place LinkedIn does not know is an error row, never a silent search of somewhere else.
  • Trim before you pay — title must-include and must-not-include lists, and a list of job ids you already hold, are applied before a job is read, so a job they drop costs nothing.
  • Specific jobs by link — paste job links or ids and get each as a row, with its description.
  • Many searches in one run — several keywords, several places, every combination searched.
  • Runs stay green. A place or company LinkedIn does not know, a job LinkedIn no longer has, a page it would not serve — each becomes an error row with a short code and a sentence, the run's status message counts them, and the run itself succeeds. The error rows are where to look for what could not be done.
  • Cheap to run — plain HTTP at 128 MB, about one request per job, paced so LinkedIn keeps answering.

Input

FieldWhat it does
keywordsOne search per line, as you would type it into LinkedIn's job search. Each is searched in each place. Leave empty to list every job in a place.
locationsA city, region or country as LinkedIn names it, or a LinkedIn geoId. Leave empty to search worldwide.
maxJobsJobs per search, default 100, ceiling 1,000 (LinkedIn's own).
includeDescriptionOn by default: every job is read in full. Off, rows carry only what the search list shows — about ten times fewer requests. Same price per job either way.
postedWithin"24 hours", "3 days", "2 weeks", "90 minutes" — any window.
companiesOnly these companies, by name or LinkedIn id.
easyApplyOnlyOnly jobs that take applications on LinkedIn.
underTenApplicantsOnlyOnly jobs LinkedIn marks as having fewer than ten applicants.
distanceMiles5 to 100 miles around a city.
titleMustInclude / titleMustNotIncludeWords or phrases a job's title must or must not contain, applied before the job is read.
skipJobIdsJob ids or links you already have; left out before anything is read.
jobUrlsSpecific jobs to read directly, as links or ids, one row each.
{
"keywords": ["software engineer"],
"locations": ["United States"],
"maxJobs": 100,
"includeDescription": true,
"postedWithin": "24 hours"
}

Output

One item per job, in LinkedIn's order for each search. Rows are pushed as each job completes, so a run's dataset grows while it runs.

FieldWhat it holds
typejob, or error for a search or job that could not be answered
searchKeywords, searchLocation, searchGeoIdThe search this row answers: the keywords, the place as LinkedIn resolved it, and LinkedIn's id for that place
searchTotalJobsHow many jobs LinkedIn says the search has (exact when small, capped near 12,000 when large)
positionThe job's rank in LinkedIn's order, 1 first
jobIdLinkedIn's numeric id for the posting — stable and unique
jobUrlThe posting's public page, without tracking parameters
titleThe job title
companyName, companyUrl, companyLogoUrl, companyIdThe employer: name, LinkedIn page, logo, numeric id (the id and the logo need a description read)
locationWhere the job is, as posted
postedDateYYYY-MM-DD, as LinkedIn's search list states it
postedTimeAgoLinkedIn's wording: "1 week ago", "3 days ago", "Just now"
badgeThe search card's label when it has one: "Be an early applicant", "Actively Hiring", "Medical insurance +3 benefits"
descriptionTextThe full description as plain text, paragraphs and bullet points on their own lines
descriptionHtmlThe same description as LinkedIn's HTML
seniorityLevel"Entry level", "Associate", "Mid-Senior level", "Director", "Executive" or "Not Applicable"
employmentType"Full-time", "Part-time", "Contract", "Temporary", "Internship", "Volunteer" or "Other"
industriesThe employer's industries, as one string
applicants, applicantCountLinkedIn's wording ("189 applicants", "Over 200 applicants", "Be among the first 25 applicants") and the number: exact, 200 for "over 200", null for "first 25"
salaryText, salaryMin, salaryMax, salaryCurrency, salaryPeriodThe pay range exactly as posted, and as numbers with a currency code and a period ("year", "hour"). Null when the posting states none, which is most of them
applyTypelinkedin (Easy Apply) or external (the employer's own site)
isClosedTrue when LinkedIn says the posting is no longer accepting applications
hasDescription, descriptionErrorWhether the description was read, and if not, why (rate_limited, read_failed, not_found, parse_failed)
scrapedAtWhen the run read the row

A real row, for a search of "software engineer" in "United States" (description shortened here):

{
"type": "job",
"searchKeywords": "software engineer",
"searchLocation": "United States",
"searchGeoId": "103644278",
"searchTotalJobs": 11940,
"position": 1,
"jobId": "4419969671",
"jobUrl": "https://www.linkedin.com/jobs/view/senior-software-engineer-%E2%80%93-go-golang-at-general-motors-4419969671",
"title": "Senior Software Engineer – Go (Golang)",
"companyName": "General Motors",
"companyUrl": "https://www.linkedin.com/company/general-motors",
"companyLogoUrl": "https://media.licdn.com/dms/image/v2/D4E0BAQEfAZWzerj03w/company-logo_100_100/B4EZdkPGXYGcAQ-/0/1749733370529/general_motors_logo?e=2147483647&v=beta&t=ycfbgxUnJw_BkI-JSrXwekaeYZ6rWNAlvxirgJ7o00Q",
"location": "Warren, MI",
"postedDate": "2026-10-04",
"postedTimeAgo": "1 week ago",
"badge": "Actively Hiring",
"companyId": "1472",
"descriptionText": "Job Description\n\nAs a Senior Software Engineer – Go (Golang), you will design, develop, and deliver high-performance middleware and application software solutions supporting GM's next-generation in-vehicle infotainment platforms and connected vehicle systems. …",
"descriptionHtml": "<strong>Job Description<br><br></strong>As a Senior Software Engineer – Go (Golang), you will design, develop, and deliver …",
"seniorityLevel": "Not Applicable",
"employmentType": "Full-time",
"industries": "Motor Vehicle Manufacturing, Appliances, Electrical, and Electronics Manufacturing, and IT Services and IT Consulting",
"applicants": "189 applicants",
"applicantCount": 189,
"salaryText": null,
"salaryMin": null,
"salaryMax": null,
"salaryCurrency": null,
"salaryPeriod": null,
"applyType": "external",
"isClosed": false,
"hasDescription": true,
"descriptionError": null,
"scrapedAt": "2026-10-11T16:29:34.603Z"
}

A row with a stated salary carries it both ways:

"salaryText": "$123,500.00/yr - $150,000.00/yr",
"salaryMin": 123500,
"salaryMax": 150000,
"salaryCurrency": "USD",
"salaryPeriod": "year"

Error rows

The run succeeds whatever a search or a job does; what could not be done is a row with type: "error", a short error code and an errorDescription sentence, and the run's status message says how many there are. Error rows are never charged.

errorWhen
bad_inputNothing to search, a window or distance that could not be read, or a job link that is not one
location_not_foundLinkedIn's place lookup has no match for the place given
company_not_foundLinkedIn's company lookup has no match for a company given
not_foundA job id LinkedIn answers 404 for — never issued, or removed
rate_limitedLinkedIn answered every attempt with its challenge page
read_failedThe page could not be read for another reason, on every attempt
parse_failedLinkedIn answered with a page this Actor could not read a job from
incompleteThe search was cut short — the run's timeout or maximum charge was reached, or LinkedIn withheld a page of results on every read — and the row says how many jobs were delivered

An empty dataset therefore means one thing: every search was read and LinkedIn lists no jobs for it.

Pricing

$0.30 per 1,000 jobs, the same on every Apify plan, charged per job row as it is delivered. Apify's standard apify-actor-start event adds $0.00005 per run.

RunJobsPrice
Default: one search, 100 jobs with descriptions100$0.030
Ten searches of 1001,000$0.30
One search to LinkedIn's limit, list only1,000$0.30
A search that finds nothing, or an unknown place0$0.00005

Apify platform usage — compute, proxy, storage — is included in the price. A job whose description could not be read is still delivered with the listing's fields, says why under descriptionError, and is charged as a job; a job that is not delivered at all is not. Jobs removed by titleMustInclude, titleMustNotInclude or skipJobIds are never read and never charged.

How it works, and what it cannot do

Where the data comes from. LinkedIn serves a job search, its paging and each job's description to readers who are not signed in. This Actor reads those pages, nothing else: no account, no cookie, no browser. About one request in ten is answered with LinkedIn's "too many requests" page; it is retried and clears. Requests are paced at about two and a half a second, which LinkedIn has sustained for runs of over a thousand jobs.

1,000 jobs per search is LinkedIn's limit, not this Actor's. LinkedIn shows at most 1,000 jobs for any search, however many it counts (searchTotalJobs says how many). To get more, split the search — by city instead of country, by "posted within", by company — and the Actor deduplicates across searches in a run.

Some things LinkedIn does not show to a reader who is not signed in, so no row carries them: the employer's own apply link (only whether the job applies on LinkedIn or externally), whether a job is remote, hybrid or on-site (it is usually in the title or the description), the job function, and an exact posting time (the date is given).

Job type, experience level, remote, salary and sort-order filters are not offered, because LinkedIn dropped them from its public search in August 2026: they return the same jobs as no filter at all. Filter the rows on employmentType and seniorityLevel instead, or put the word in the keywords ("contract software engineer", "software engineer intern") and use the title lists.

LinkedIn's search matches loosely. "nurse" returns nursing jobs of every kind; a quoted phrase and NOT are not honoured. The titleMustInclude and titleMustNotInclude lists are the precise tool, and they cost nothing because they run before a job is read.

No person's data. Some postings show a "message the job poster" block with a named person. This Actor does not read it; a row describes the job.

FAQ

How long does a run take? A default 100-job search with descriptions takes about a minute and a half; a 1,000-job search with descriptions about a quarter of an hour; a 1,000-job list-only search about three minutes. Rows arrive as each job completes, so the dataset fills while the run goes.

Why does a row say descriptionError? LinkedIn answered that job's description page with its challenge page on every attempt, or the posting was removed between the search and the read. The listing's fields are real; run the job again under jobUrls to fetch the description.

Can I poll for new jobs? Yes: run the same search on a schedule with postedWithin set to the interval, and pass the ids you already hold as skipJobIds so only new jobs are read and charged.

What is a geoId? LinkedIn's numeric id for a place; every row carries the one it was searched in as searchGeoId. Pass it back as a location to search exactly the same place again.

Why did a company filter return an error row? The name did not match a company in LinkedIn's lookup. Check the spelling, or give the company's numeric id (companyId on any of its job rows).

Why no proxy setting? The Actor reads LinkedIn through Apify's datacenter proxy, which was measured to work as well as residential for these pages, and the price includes it.

This Actor reads only pages LinkedIn serves to the public without a login, and only job postings — not profiles. Use the data in line with LinkedIn's terms and the law where you are, and give people the rights they have over their data; a job posting is an employer's public notice, not a person's record.