LinkedIn Jobs Scraper API avatar

LinkedIn Jobs Scraper API

Pricing

from $2.00 / 1,000 results

Go to Apify Store
LinkedIn Jobs Scraper API

LinkedIn Jobs Scraper API

Scrape unlimited LinkedIn jobs with no 1,000-result limit. Extract job titles, companies, locations, salaries, full descriptions and apply URLs to JSON, CSV or Excel. No login required.

Pricing

from $2.00 / 1,000 results

Rating

5.0

(1)

Developer

Mukesh Kumar

Mukesh Kumar

Maintained by Community

Actor stats

4

Bookmarked

50

Total users

9

Monthly active users

6 days ago

Last modified

Share

Scrape LinkedIn jobs without the 1,000-result limit. Search by keyword, company, location, work type, seniority, or date posted and get back clean, structured LinkedIn job listings — job title, company, location, salary, the full description, and the apply URL.

No LinkedIn account, no cookies, no API key. The Actor reads LinkedIn's public guest job pages, so there's nothing to log into and no account of yours at risk.

Why the limit matters. LinkedIn caps every job search at ~1,000 results — that's LinkedIn's own ceiling, not a scraper limitation. Most LinkedIn job scrapers stop there and hand you a sample. This one detects the cap, splits your query into narrower time windows and seniority slices, then merges and deduplicates the results, so a search that would have returned 1,000 jobs returns all of them instead.

Try it in 30 seconds: type a job title like python developer, pick a location, and hit Start. Your first ~2,500 jobs are free on Apify's free plan, and results export to JSON, CSV, or Excel.

Teams use this LinkedIn jobs data to power job boards, source candidates, generate B2B sales leads from hiring intent, track competitor hiring, and benchmark salaries.

InputJob keywords, location or geoId, company name/ID, date posted, work type, job type, experience level
OutputJob title, company, location, salary, full description, apply URL, seniority, employment type, posted date
FormatsJSON, CSV, Excel, XML, HTML, RSS — or live via the Apify API
LimitNone. Set maxResults: 0 for unlimited LinkedIn job data
LoginNot required — public LinkedIn guest endpoints only
Price$2.00 per 1,000 jobs, proxies and compute included. First ~2,500 free

What this LinkedIn jobs scraper does

  • Unlimited LinkedIn job listings — automatic query slicing bypasses LinkedIn's 1,000-result search cap.
  • No login or cookies — scrapes public LinkedIn guest job endpoints, so there's no account to get restricted.
  • Full job descriptions — the complete posting text, not just the search-results snippet.
  • Scrape LinkedIn jobs by company — filter by employer name or exact LinkedIn company ID.
  • Remote, hybrid, and on-site filters — plus employment type and seniority level.
  • Automatic deduplication — one row per jobId, even across overlapping query slices.
  • Anti-block by default — real Chrome TLS fingerprints via curl_cffi, residential proxies, and a fresh proxy IP per detail request.
  • Tunable rate limits — set concurrency and request delays to match how aggressive you want to be.

How to scrape LinkedIn jobs in 3 steps

  1. Enter your search. Fill in Job title (e.g. data engineer) and Job location (e.g. United States). Everything else is an optional filter.
  2. Set your result limit. Leave maxResults at 100 for a test run, or set it to 0 to scrape every matching LinkedIn job posting.
  3. Run and export. Click Start, then download the dataset as JSON, CSV, or Excel — or pull it live from the Apify API.

How the 1,000-result LinkedIn limit is bypassed

LinkedIn's job search returns at most ~1,000 results for any single query, no matter how many jobs actually match. This scraper works around that ceiling automatically:

  1. It runs your search once and measures how close the result count is to the cap.
  2. If the query is capped, it splits the search into progressively finer time windows — one month, two weeks, one week, three days, one day, twelve hours, six hours, down to a single hour.
  3. Windows that still cap are split further by experience level, cutting the result space again.
  4. Every slice is fetched, then deduplicated by LinkedIn jobId so overlapping windows never produce duplicate rows.

You get one complete, clean dataset of LinkedIn job postings — well past what the LinkedIn UI itself will show you.

LinkedIn job search filters (input)

Only Job title is needed for a basic run. Everything else narrows the search.

FieldTypeDefaultWhat it does
keywordsstring"python developer"Job search keywords — e.g. "data engineer", "product manager", "react developer".
locationstring"United States"Free-text location — e.g. "San Francisco", "Remote", "London, UK".
geoIdstringLinkedIn geoId for exact location targeting. Overrides location. Copy it from any LinkedIn job-search URL.
companyNamearray[]Scrape LinkedIn jobs by company name — e.g. ["Google", "Microsoft"].
companyIdarray[]Filter by numeric LinkedIn company ID — e.g. ["1441", "1035"]. More precise than name.
datePostedenum"anyTime"anyTime, pastMonth, pastWeek, past24Hours.
workTypearray[]onSite, remote, hybrid — use ["remote"] to scrape remote jobs only.
jobTypearray[]fullTime, partTime, contract, temporary, volunteer, internship.
experienceLevelarray[]internship, entryLevel, associate, midSenior, director, executive.
maxResultsinteger100Maximum jobs to scrape. Set 0 for unlimited.
scrapeJobDetailsbooleantrueFetch the full job description for every listing.
maxConcurrencyinteger5Parallel detail-page requests (1–20).
minDelay / maxDelayinteger1000 / 3000Random delay window between requests, in milliseconds.
proxyConfigobjectResidentialApify Proxy settings. Residential is strongly recommended.

Example input: remote senior Python jobs at Google and Microsoft

{
"keywords": "python developer",
"location": "United States",
"companyName": ["Google", "Microsoft"],
"datePosted": "pastWeek",
"workType": ["remote", "hybrid"],
"jobType": ["fullTime"],
"experienceLevel": ["midSenior", "director"],
"maxResults": 0,
"scrapeJobDetails": true,
"proxyConfig": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}

LinkedIn jobs data fields (output)

Every job is one flat JSON object in the Apify dataset:

FieldTypeDescription
jobIdstringLinkedIn's unique job ID — use it as your primary key.
titlestringJob title.
companyNamestring | nullEmployer name.
companyIdstring | nullNumeric LinkedIn company ID.
companyUrlstring | nullCompany's LinkedIn page.
locationstring | nullJob location, e.g. "San Francisco, CA".
postedTimestring | nullRelative posting time, e.g. "2 days ago".
publishedAtstring | nullISO 8601 timestamp of first posting.
applicationsCountstring | nullApplicant count when LinkedIn exposes it.
workTypestring | nullRemote, Hybrid, or On-site.
experienceLevelstring | nullSeniority, e.g. "Mid-Senior level".
contractTypestring | nullEmployment type, e.g. "Full-time".
descriptionstring | nullFull job description text (when scrapeJobDetails is on).
jobUrlstringCanonical LinkedIn job URL.
applyUrlstring | nullApply link. LinkedIn's guest pages often omit the employer's real URL, in which case this falls back to the canonical jobUrl.
applyTypestring | nullExactly one of "Easy Apply" or "External".
benefitsstring | nullBenefits text when listed.
sectorstring | nullIndustry / sector.
salarystring | nullSalary range when the employer publishes one.

Example output

{
"jobId": "3912345678",
"title": "Senior Python Developer",
"companyName": "Acme Corp",
"companyId": "1441",
"companyUrl": "https://www.linkedin.com/company/acme",
"location": "San Francisco, CA",
"postedTime": "2 days ago",
"publishedAt": "2026-05-20T10:14:00.000Z",
"applicationsCount": "42 applicants",
"workType": "Remote",
"experienceLevel": "Mid-Senior level",
"contractType": "Full-time",
"description": "We are looking for a Senior Python Developer to join our platform team...",
"jobUrl": "https://www.linkedin.com/jobs/view/3912345678",
"applyUrl": "https://acme.com/careers/senior-python-developer",
"applyType": "External",
"benefits": "Medical, dental, 401(k), unlimited PTO",
"sector": "Software Development",
"salary": "$160,000 – $210,000/yr"
}

Pricing

$2.00 per 1,000 jobs — that's $0.002 per job, charged only for results you actually receive. There's no monthly subscription and no charge for a run that returns nothing.

What you're doingJobs scrapedCost
Trial run to check the output100$0.20
Daily monitor on one search500/day$1.00/day
Weekly competitor hiring report2,000$4.00
Full market snapshot (maxResults: 0)10,000$20.00

What's included: everything. Residential proxies, compute, and the detail-page requests for full job descriptions are all covered by the per-job price — there are no separate platform charges to calculate on top. (There's a $0.00005 charge each time a run starts, which works out to five cents per thousand runs.)

Apify's free plan includes $5 of monthly usage, so you can scrape your first ~2,500 LinkedIn jobs without paying anything.

Deduplication runs before results are written to the dataset, so you're never billed twice for the same jobId — even when the Actor slices a large query into dozens of overlapping searches.

Use cases for LinkedIn job data

Each of these is a real workflow with the filter recipe that produces it.

Recruiting and candidate sourcing

See every open role in your niche the day it posts. Recruiters and staffing agencies use LinkedIn job data to map who's hiring for a given skill, spot teams that are scaling, and find roles that have been open a long time — a strong signal the company is struggling to fill them and might welcome outside help.

Recipe: keywords: "site reliability engineer", datePosted: "pastWeek", workType: ["remote"]. Sort by publishedAt to see who just came into market, and watch applicationsCount to find roles with little competition.

Sales prospecting and B2B lead generation

A job posting is the cleanest buying signal a company emits. Hiring means budget was approved, a team is growing, and someone owns a problem they've just been given money to solve — exactly the moment to reach out.

Because every row carries companyName, companyId, companyUrl, location, and sector, each result is already a qualified account record — no enrichment step needed to know who the company is.

What you sellWhat to searchThe signal
Developer tooling / DevOpskeywords: "kubernetes engineer"They're scaling infrastructure and hiring for it
Data platforms / ETLkeywords: "analytics engineer"They're building a data team and have budget
Recruiting services / ATSany role, datePosted: past24HoursHigh hiring volume means hiring pain
Sales enablement / CRMkeywords: "SDR" or "account executive"Sales team is expanding right now
Security / compliancekeywords: "security engineer"Security is funded and a priority this quarter

Recipe: search your ICP's roles with datePosted: "past24Hours" and maxResults: 0, schedule it daily so new postings arrive as a fresh lead feed, deduplicate on companyId to collapse multiple postings into one account, then webhook it to your CRM, Google Sheets, or Clay/Apollo. Use description for the personalisation line — it tells you their stack, their team structure, and the problem they're hiring to fix.

Because there's no 1,000-result cap, you get the whole addressable market for a role rather than the first page of it — the difference between a sample and a territory.

Building a job board or job aggregator

Every field a listing page needs, in a single row. title, companyName, companyUrl, location, description, salary, applyUrl, and publishedAt are enough to render a complete listing without a second data source. jobId gives you a stable primary key, so a nightly refresh upserts cleanly instead of duplicating.

Recipe: one run per vertical or city with maxResults: 0, scheduled nightly. Upsert on jobId and use publishedAt to expire stale listings. Send outbound clicks to applyUrl — but expect it to be the LinkedIn job URL rather than the employer's ATS on many postings, since the guest pages frequently don't expose the real destination.

Competitor hiring intelligence

Headcount plans become public before they're announced. A competitor opening five backend roles in a city they've never hired in is an office launch you're reading months before the press release. Sustained hiring in one function is the earliest public signal of where a company is placing its bets.

Recipe: companyId: ["1441", "1035"] with datePosted: "pastWeek", scheduled weekly. Diff each run against the last to see what's new, group by location to catch geographic expansion, and group by title and sector to see which function is being funded.

Salary benchmarking and labour-market research

Thousands of current, employer-published salary ranges — far more current than annual survey data, and specific to title, seniority, and city.

One caveat worth planning around: salary is only populated when the employer discloses it. Coverage is much higher in jurisdictions with pay-transparency laws (California, Colorado, New York, Washington, and much of the EU), so filter to those geoIds if you need dense salary data rather than a sparse sample.

Recipe: run per metro geoId with maxResults: 0, keep rows where salary is non-null, and segment by experienceLevel and contractType.

AI and ML training data

Large, clean, structured job-posting corpora for skill extraction, title normalisation, résumé matching, and labour-market models.

The output is unusually well-suited to supervised training because it arrives pre-labelled: description is the text, while sector, experienceLevel, contractType, and workType are ready-made labels that would otherwise cost you an annotation pass.

Recipe: maxResults: 0 with scrapeJobDetails: true for the full description text. Run broad keyword sweeps across several geoIds to avoid geographic bias in the corpus.

Job seekers and custom job alerts

Build the job alert LinkedIn won't give you. Filter far more precisely than the LinkedIn UI allows, across multiple keywords and locations at once, and get the results wherever you actually read them.

Recipe: narrow keywords plus datePosted: "past24Hours", scheduled daily, with a webhook to Slack or email. Filter on applyType: "External" if you'd rather apply directly on company sites than through Easy Apply.

Export formats and integrations

Download your LinkedIn jobs dataset as JSON, CSV, Excel (XLSX), XML, HTML, or RSS — or skip the download entirely and push results straight into your stack. The Apify platform connects the dataset to Google Sheets, Google Drive, Amazon S3, Slack, Zapier, Make, GitHub, and webhooks, and the Apify API lets you trigger runs and stream job data programmatically from Python, Node.js, or plain HTTP.

Tips for scraping more LinkedIn jobs reliably

  • Use geoId instead of free-text location when precision matters — text locations occasionally resolve to the wrong city.
  • Set maxResults: 0 for a complete market snapshot; the slicing logic handles the 1,000-result cap for you.
  • Combine companyName with datePosted: pastWeek for lightweight competitor hiring monitors you can schedule daily.
  • Turn off scrapeJobDetails when you only need titles, companies, and links — it's dramatically faster and cheaper.
  • If you hit rate limits, lower maxConcurrency and raise minDelay/maxDelay before anything else.
  • Always keep residential proxies on for large runs — datacenter IPs get blocked by LinkedIn quickly.
  • Schedule it. Apify Schedules can run this scraper hourly or daily so your LinkedIn job data stays fresh without you touching it.

Frequently asked questions

Do I need a LinkedIn account or cookies to use this scraper?

No. It reads LinkedIn's public guest job endpoints — the same pages a logged-out visitor sees. There's no login, no session cookie, and no LinkedIn API key, so there is no account of yours that can be restricted or banned.

How does it scrape more than 1,000 LinkedIn jobs?

LinkedIn caps every search at ~1,000 results. When the Actor detects a capped query it splits the search into progressively narrower time windows — down to a single hour — and, if a window still caps, splits it again by experience level. Every slice is merged and deduplicated by jobId. See How the 1,000-result LinkedIn limit is bypassed.

How is this different from other LinkedIn job scrapers?

Three things, in order of how much they matter:

  1. No 1,000-result ceiling. Most LinkedIn job scrapers return whatever a single search gives them, which LinkedIn caps at ~1,000. For any broad query that's a sample, not a dataset.
  2. Full job descriptions, not snippets. The Actor fetches each job's detail page, so you get the complete posting text plus salary, benefits, apply URL, and seniority.
  3. All-inclusive pricing. Proxies and compute are covered by the per-result price, so there's no separate platform bill to model.

Why not just use the official LinkedIn Jobs API?

LinkedIn has no public jobs API. Access to its Talent Solutions and partner APIs requires an approved partnership, and job search is not among the endpoints generally available to developers. Scraping the public guest pages is the practical route to LinkedIn job data, which is why this Actor exists.

Can I scrape LinkedIn jobs from a specific company?

Yes. Use companyName (e.g. ["Google", "Stripe"]) for name matching, or companyId (e.g. ["1441"]) for exact matching. The numeric ID appears in the company's LinkedIn URL and is the more reliable of the two — company names are ambiguous and match loosely.

Can I scrape LinkedIn jobs from a specific country or city?

Yes. Set location to free text like "Germany" or "Austin, TX". For guaranteed precision use geoId, which overrides location — open a LinkedIn job search filtered to the place you want and copy the geoId parameter out of the URL. The Actor works for any country LinkedIn serves.

Can I scrape remote-only or hybrid LinkedIn jobs?

Yes. Set workType to ["remote"], ["hybrid"], or ["remote", "hybrid"].

Does it return full job descriptions and salaries?

Yes, when scrapeJobDetails is true (the default). You get the complete description text plus salary, benefits, apply URL, seniority, and employment type — for the fields LinkedIn actually publishes. Salary is null on the many postings where the employer didn't disclose one; that's a gap in the source data, not in the scraper.

Does it include Easy Apply jobs?

Both. Every result carries an applyType field alongside applyUrl, so you can filter to either kind after the run. The value is exactly one of "Easy Apply" or "External" (or null when the page doesn't say) — note the space in "Easy Apply", since an exact-match filter on "EasyApply" will silently match nothing.

How long does a run take?

At default settings (maxConcurrency: 5, 1–3 second delays, details on) expect roughly 5–10 minutes per 1,000 jobs. Turning scrapeJobDetails off is dramatically faster because it skips one request per job. Note the default run timeout is 1 hour — raise it in the run options before starting a very large unlimited run, or the run will stop early.

Can I schedule it to run automatically?

Yes. Use Apify Schedules to run the Actor hourly, daily, or on any cron expression. Pair a daily schedule with datePosted: "past24Hours" to maintain a rolling feed of new postings instead of re-scraping the same jobs.

Can I run it from Python, Node.js, or the API?

Yes. Every Apify Actor is callable over the Apify API, with official Python and JavaScript clients. You can start a run, pass input, poll for completion, and pull the dataset programmatically — which is how most people wire this into an existing pipeline.

How do I export LinkedIn jobs to Excel, CSV, or Google Sheets?

Run the Actor, open the dataset, and choose your format — JSON, CSV, Excel, XML, HTML, or RSS. For Google Sheets, S3, BigQuery, or Slack, use Apify Integrations or a webhook rather than downloading by hand.

How much does it cost to scrape LinkedIn jobs?

$2.00 per 1,000 jobs — $0.002 each, billed only on results you actually receive. Proxies and compute are included, so there's nothing to add on top. Apify's free plan covers your first ~2,500 jobs at no cost. See Pricing.

Can I cap how much a single run costs?

Yes. Set a maximum charge for the run in Apify's run options, and the run stops once it reaches that ceiling. This is the safe way to experiment with maxResults: 0 on a broad query without an open-ended bill.

Why am I getting fewer results than expected?

Usually the filters are narrower than intended. Work through these in order:

  • maxResults is still 100 — the default. Set it to 0 for unlimited.
  • location resolved to the wrong place. Free-text locations match loosely; use geoId to be certain.
  • Stacked filters. Combining a narrow experienceLevel, jobType, and datePosted can leave very few genuine matches.
  • Fewer jobs exist publicly than in the logged-in UI. LinkedIn shows guests a smaller set for some queries. This is a real ceiling, not a bug.

My run is slow or hitting rate limits — what should I change?

Lower maxConcurrency first (try 3), then raise minDelay and maxDelay (try 2000/5000). Make sure residential proxies are enabled — datacenter IPs get rate-limited quickly. Slower settings finish more reliably than fast ones that stall on retries.

Will I get duplicate jobs in my dataset?

No. Deduplication runs before anything is written to the dataset, so overlapping time-window slices never produce duplicate rows — and you're never billed twice for the same job. It works in two passes: first on LinkedIn jobId, then on a content fingerprint, which also catches the same posting re-listed under a new ID. If you want one row per company rather than per posting, deduplicate on companyId yourself afterwards.

Will LinkedIn block me?

There's no account to block, since the Actor never logs in. Blocking shows up as failed requests instead, which the Actor mitigates with real Chrome TLS fingerprints, Apify Residential Proxy, and a fresh IP per detail request. If you do see failures, slow the run down as described above.

This Actor collects only publicly accessible job listings from LinkedIn's guest endpoints — the same pages any logged-out visitor can see — and gathers no personal profile data. Public-data scraping has been upheld in cases such as hiQ Labs v. LinkedIn, but that is not blanket permission: review LinkedIn's Terms of Service and your obligations under GDPR, CCPA, and local law before running large or ongoing collections. If you're unsure, talk to a lawyer. Nothing here is legal advice.

Does it collect personal data?

No. The output is company and job data — job titles, descriptions, employers, locations, salaries, and apply URLs. The Actor does not scrape LinkedIn member profiles, names, emails, or contact details.

Can I use LinkedIn job postings for sales prospecting?

Yes — it's one of the most common uses. Every result carries companyName, companyId, companyUrl, location, and sector, so a run doubles as a hiring-intent lead list of companies with approved budget. Schedule a daily run filtered to your ICP's roles, deduplicate on companyId, and pipe it into your CRM. See Sales prospecting and B2B lead generation.

What happens if LinkedIn changes its page structure?

Scrapers depend on the structure of the pages they read, so LinkedIn changes can break extraction. If you see fields coming back empty that used to be populated, report it on the Actor's issues page — that's the fastest way to get a fix shipped.

Can I get a custom version, extra fields, or a different output format?

Yes. Open an issue on the Actor's page describing the fields, filters, or output shape you need. Requests from paying users are prioritised.

Support and feedback

Found a bug, need a new filter, or want a custom output schema? Open an issue on the Actor page and it'll get looked at. Feature requests from paying users go to the front of the queue.

Local development

pip install -e ".[dev]"
make lint # ruff check
make typecheck # mypy --strict
make test # pytest
make all # lint + typecheck + test