How to scrape LinkedIn job postings without logging in

Last updated

Scrape LinkedIn jobs by running Datapika's job-board-scraper on Apify: type a job title, set a location, pick linkedin as the source, and the run streams rows into a dataset within 5 to 20 seconds. No LinkedIn account, session cookie, or partner API key is involved, because the scraper reads the same public search pages a logged-out visitor sees. Each row carries title, company, location, job URL, seniority level, and, with linkedinFetchDescription enabled, the full posting text and direct apply link. You pay $0.005 per job delivered, and the actor has 27,458 runs from 2,471 users with a 5.0 rating.

Can you scrape LinkedIn jobs without logging in or using cookies?

Yes, and that is the whole design of the LinkedIn source in Datapika's job-board-scraper. LinkedIn publishes its job search results on public pages that a signed-out visitor can open, and the scraper requests those pages directly. It never asks for a LinkedIn username, password, li_at session cookie, or browser extension, so nothing you own is exposed to a restriction notice, and there is no cookie to refresh when it expires. The scraper's documentation states that it does not log in to any account, does not touch private candidate or recruiter data, and does not circumvent authentication; it only collects postings employers published to be found. That also means it cannot reach anything a session unlocks, such as submitting an Easy Apply form or reading applicant details. What you get is the public posting: title, company, location, date, seniority, and the description text. For most sourcing, lead generation, and market research pipelines that is exactly the set that matters.

  • No LinkedIn account, password, or li_at cookie in the input; the only required field is searchTerm
  • Reads public job search pages, the same ones a signed-out visitor loads
  • Nothing behind a login is touched: no Easy Apply submission, applicant lists, or member profiles
  • No browser extension and no session to refresh when LinkedIn rotates cookies
  • The default residential proxy carries the requests, so your office IP is never shown to LinkedIn

What fields does a LinkedIn job scraper return?

Every LinkedIn row lands in the dataset with the same flat schema the other seven boards use, plus one field the README ties to LinkedIn alone: job_level, the seniority label LinkedIn attaches to a posting. Alongside it you get the source job id, title, company, location, date_posted, job_type, is_remote, the site value linkedin, and, when the posting shows them, job_function, listing_type, company_industry, company_url, and company_logo. Salary fields have a salary_source marker: direct_data when LinkedIn shows a range, or description when the number was parsed from the text, and enforceAnnualSalary converts hourly and monthly figures to yearly. Two fields depend on linkedinFetchDescription: description, delivered in Markdown by default or HTML on request, and job_url_direct, the employer's own apply page when one exists. Emails found in the description are pulled into their own array. Each row also records search_term, matched_search_term when you run several queries, and a scraped_at ISO timestamp. The table below marks which fields LinkedIn actually fills.

  • job_level is LinkedIn-only: the seniority tag LinkedIn shows on the posting
  • Core row: id, title, company, location, job_url, date_posted, job_type, is_remote, site
  • Salary: salary_min, salary_max, salary_currency, salary_interval, with salary_source telling you whether it came from board data or parsed text
  • linkedinFetchDescription adds description (Markdown or HTML) and job_url_direct
  • emails array extracted from the description text
  • search_term, matched_search_term, and scraped_at on every row

What are the quirks of scraping LinkedIn compared with other boards?

LinkedIn behaves differently from Indeed in four ways that shape how you configure a run. First, LinkedIn rate-limits search traffic at roughly 100 results per IP address, which is why the proxy configuration defaults to Apify residential proxies; a single fixed IP hits that ceiling quickly on a large sweep, while rotating residential IPs spread the requests. Second, the search listing does not include the posting body, so linkedinFetchDescription triggers extra requests per job to collect the description and direct apply URL, making LinkedIn runs slower than the same query on Indeed. Leave it off when titles and companies are enough. Third, LinkedIn rejects the combination of hoursOld and easyApply in one search; pick one, or run two searches. Fourth, LinkedIn is the only board with company targeting, so linkedinCompanyIds can restrict results to named employers. Because LinkedIn is global, countryIndeed has no effect on it; steer by location and distance, which defaults to 50 miles. Rows still stream into the dataset 5 to 20 seconds after the run starts.

  • Rate limit: about 100 results per IP, so residential proxies are the default and the right choice for large runs
  • linkedinFetchDescription is off by default; enabling it adds requests and time but returns description and job_url_direct
  • hoursOld and easyApply cannot be combined on LinkedIn; Indeed has its own filter conflicts
  • linkedinCompanyIds restricts a search to specific employers, a LinkedIn-only feature
  • countryIndeed is ignored for LinkedIn; use location and distance (default 50 miles)
  • maxResults caps at 100 per board per search term, and searchTerms allows up to 5 queries per run

How do you monitor specific companies' LinkedIn job postings?

Recruiters, sales teams, and analysts often care about a handful of employers rather than a keyword. LinkedIn is the one board where the scraper can pin a search to named companies: pass the numeric IDs LinkedIn assigns to their company pages in linkedinCompanyIds, and the run ignores every other employer. The documented example is ["1441", "2382910"] with searchTerm product manager and location San Francisco. Pair that with hoursOld set to 24 or 168 and a daily Apify schedule, and each run returns only the roles those companies opened since the last one, which is the raw material for a competitor hiring tracker or a buying-signal feed. Use searchTerms with up to five titles to cover a whole function, since every row is tagged with matched_search_term. Because output is deduplicated across boards, adding Indeed to the same run brings in the company size, revenue, and rating columns shown in the README's sample Indeed row without doubling the row count. The full board list is at datapika.com/scrape.

  • linkedinCompanyIds accepts a list of numeric company IDs, for example ["1441", "2382910"]
  • hoursOld 24 on a daily schedule returns only postings opened since yesterday
  • searchTerms takes up to 5 titles and stamps matched_search_term on every row
  • Cross-board deduplication means a posting found on both LinkedIn and Indeed appears once in the dataset
  • Attach a webhook to push each finished run into Slack, Sheets, or a CRM

How do developers and AI agents pull LinkedIn jobs from Datapika?

Three paths lead to the same dataset. In the Apify Console you fill the form, run, and download JSON, CSV, Excel, XML, or RSS from the Output tab. From code, POST your input to the run endpoint for openclawai~job-board-scraper with your Apify token, or call run-sync-get-dataset-items to receive the job rows in a single response; the Python and Node clients wrap both in one call. For agents, add https://mcp.apify.com/?tools=fetch-actor-details,openclawai/job-board-scraper to Claude Desktop, Cursor, or any MCP client, and the assistant can ask for remote senior React roles posted on LinkedIn in the last 24 hours and reason over typed rows instead of HTML. Set a maximum total charge on the run in Console and keep maxResults low while testing. Runs default to 4 GB of memory, which matters only when you add the browser-driven boards; a LinkedIn-only run finishes quickly. Zapier, Make, and n8n can trigger scheduled runs and route rows onward.

  • Console: form in, dataset out as JSON, CSV, Excel, XML, or RSS
  • REST: POST to api.apify.com/v2/acts/openclawai~job-board-scraper/runs, or run-sync-get-dataset-items for one call
  • Python: pip install apify-client, then client.actor("openclawai/job-board-scraper").call(run_input={...})
  • MCP: mcp.apify.com with the job-board-scraper tool enabled for Claude, ChatGPT, or Cursor
  • Schedules plus webhooks turn one query into a daily LinkedIn feed
LinkedIn field coverage in the job-board-scraper dataset, derived from the README field list and per-board notes
FieldPopulated on LinkedIn?Notes
id, title, company, location, job_urlYesSource job ID plus the core posting data and the link to the LinkedIn listing
site, date_postedYessite is always linkedin for these rows; date_posted is the date LinkedIn shows
job_type, is_remoteWhen shownfulltime, parttime, contract, internship, temporary and a boolean remote flag; filter with jobType and isRemote
job_levelYes, LinkedIn onlySeniority label; the README attributes this field to LinkedIn alone
job_function, listing_type, company_industryWhen shownRole category, sponsored marker, and industry as LinkedIn displays them
company_url, company_logoWhen shownLinkedIn company page and logo URL
salary_min, salary_max, salary_currency, salary_intervalWhen shown or parsedsalary_source is direct_data or description; enforceAnnualSalary normalizes to yearly
description, job_url_directWith linkedinFetchDescriptionFull posting in Markdown (or HTML via descriptionFormat) and the employer's apply page when available
emailsWhen presentAddresses parsed from the description text
company_num_employees, company_revenue, company_rating, company_reviews_count, company_countryNot documented for LinkedInThe README's sample row shows these on Indeed, marks company_country as Indeed only, and lists company_rating for Naukri
skills, experience_range, vacancy_count, work_from_home_typeNoNaukri only
search_term, matched_search_term, scraped_atYesQuery attribution and ISO scrape timestamp

How to do it

  1. 1.Open apify.com/openclawai/job-board-scraper, enter a searchTerm such as "software engineer" and a location, and set sites to ["linkedin"].
  2. 2.Turn on linkedinFetchDescription if you need the full posting and direct apply URL, add linkedinCompanyIds or hoursOld to narrow the sweep, and keep the default residential proxy.
  3. 3.Run it; LinkedIn rows start landing in the dataset within 5 to 20 seconds, and you can export JSON, CSV, or Excel or read them through the API.
  4. 4.For agents, connect https://mcp.apify.com/?tools=fetch-actor-details,openclawai/job-board-scraper in your MCP client so the assistant can run LinkedIn searches on demand.
Run a search

Questions, answered

Does LinkedIn have an official API for job listings?

Not for reading or searching postings. LinkedIn's developer documentation, updated June 2026, lists only three self-serve permissions: sign-in profile, email, and sharing posts. Every talent product, including Premium Job Posting, Apply Connect, and Recruiter System Connect, requires a partner application through LinkedIn Talent Solutions, and those integrations are built for posting jobs to LinkedIn or syncing applicants with an ATS, not for querying the job inventory. One August 2026 analysis puts Talent-track approval at 4 to 6 months minimum. Scraping the public search pages is the practical path for developers.

Do I need a LinkedIn login or cookies to scrape jobs with Datapika?

No. The input has no field for a username, password, or session cookie, and the scraper never signs in. It reads the public job search pages that any signed-out visitor can open, through the default residential proxy, so your own LinkedIn account and IP address are never involved. The trade-off is scope: only what LinkedIn shows publicly is returned, which covers title, company, location, seniority, salary when listed, and the full description.

How much does it cost to scrape LinkedIn jobs?

$0.005 per job delivered, so 1,000 LinkedIn postings cost $5, billed only for rows that reach your dataset; a search that returns nothing costs nothing beyond Apify's small run start fee. The ceiling for a run is maxResults times the number of boards times the number of search terms, so a LinkedIn-only sweep with maxResults 100 and 3 terms tops out at 300 rows. LinkedIn's per-IP limit and filter matches usually bring the actual count lower.

Why does a LinkedIn run return fewer than 100 results?

Three causes cover most cases. LinkedIn throttles at roughly 100 results per IP, so a single fixed IP can hit the ceiling early; keep the residential default. Filter conflicts are the second: LinkedIn will not combine hoursOld with easyApply, so drop one. Third, the query simply has fewer matches within the distance radius, which defaults to 50 miles. Widen location, add searchTerms, or paginate with offset to reach more postings.

Is it legal to scrape LinkedIn job postings?

The scraper collects only public postings that employers published to be found; it does not log in, bypass authentication, or read member profiles or applicant data. Job listings are business information, though a description may include a recruiter's email, which lands in the emails array and falls under privacy law such as GDPR. You are responsible for using the output in line with LinkedIn's terms and the laws that apply to you, and for handling any personal contact details accordingly.

Keep reading