If you've tried to pull job listings out of LinkedIn, you've probably hit at least one of these:
- The official API is only for approved partners, so it's not an option for a side project or a small recruiting tool.
- Scraping while logged in puts your own LinkedIn account at risk.
- In 2026 LinkedIn moved its public job search to an AI search that ignores the remote, job type and experience level filters in the URL (
f_WT,f_JT,f_E). I tested it: the same jobs come back with and without them. - Salaries come as raw strings like
$60.00/hr - $100.00/hr, which you can't sort or filter. - A daily schedule returns the same jobs every day, and you pay for them again.
I built an Apify Actor that handles all of that: LinkedIn Jobs Scraper. It only reads the public job pages LinkedIn shows to logged-out visitors, so there's no account, no cookies and nothing to get banned. This post shows how to use it from the browser, from Python and as a daily job alert in n8n.
What you get
One flat row per job. Here's a real row (description shortened):
{
"jobId": "4465379983",
"url": "https://www.linkedin.com/jobs/view/4465379983",
"title": "Senior Software Engineer - Python",
"company": "Venmo",
"companyId": "552278",
"location": "Austin, TX",
"countryCode": "US",
"workplaceType": "On-site",
"postedDate": "2026-10-22",
"employmentType": "Full-time",
"industries": ["Financial Services"],
"applicants": 200,
"applicantsText": "Over 200 applicants",
"easyApply": false,
"isRecruitingAgency": false,
"skills": ["Python", "Django", "Flask", "Git", "AWS", "Terraform", "SQL", "Redis"],
"experienceYears": 3,
"educationLevel": "bachelor",
"description": "The Company\nPayPal has been revolutionizing commerce globally..."
}
When the job lists pay, the salary is parsed into numbers, and hourly or monthly pay is converted to a yearly figure:
"salary": {"min": 60, "max": 100, "currency": "USD", "period": "hour",
"text": "$60.00/hr - $100.00/hr", "annualMin": 124800, "annualMax": 208000},
"salarySource": "employer"
Skills, years of experience, education level and visa sponsorship are read from the description text.
How the filters work when LinkedIn ignores them
Since LinkedIn's search no longer applies remote, job type or experience level, the Actor applies them itself. It reads each job page and keeps only the jobs that really match. It also adds the chosen value to the search words (for example "remote"), because that does change LinkedIn's results.
Workplace type comes from the title, the location or the description. When none of them says it, the field stays empty. With a workplace filter on, those jobs are left out unless you turn on Keep jobs with unknown workplace.
On top of that you can filter by minimum yearly salary, applicant count, title words, company, and leave out recruiting agencies. Jobs your filters drop are not charged.
Option 1: try it in the browser (2 minutes)
- Open the Actor page and click Try for free.
- Type a Search term such as
python developerand a Location such asUnited States. - Optional: pick Remote under workplace types and set a Minimum yearly salary.
- Click Start. The example run (20 jobs with full pages) takes about 20 seconds. Download the results as JSON, CSV or Excel.
You can also paste LinkedIn search URLs straight from your browser. Old filters inside the URL are applied exactly.
Option 2: Python
Install the client with pip install apify-client, then:
from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("panix/linkedin-jobs-scraper").call(run_input={
"searchTerms": ["software engineer"],
"locations": ["United States"],
"workplaceTypes": ["Remote"],
"minAnnualSalary": 120000,
"excludeRecruitingAgencies": True,
"maxJobsPerSearch": 200,
})
for job in client.dataset(run.default_dataset_id).iterate_items():
pay = (job.get("salary") or {}).get("annualMax")
print(job["title"], "|", job["company"], "|", job["location"], "|", pay)
Want every job at specific companies? Use their LinkedIn company IDs (the f_C= value in LinkedIn URLs, or companyId from an earlier run):
run_input = {"companyIds": ["1441", "1035"], "locations": ["United States"], "maxJobsPerSearch": 500}
LinkedIn shows at most 1,000 jobs per search. For bigger pulls, turn on Deep search: it runs date and Easy Apply variants of the same search and merges them without duplicates.
Option 3: a daily "new jobs only" alert in n8n
This is the setup I'd use for a personal job alert or a recruiting feed.
Schedule node: once a day.
HTTP Request node:
- Method:
POST - URL:
https://api.apify.com/v2/acts/panix~linkedin-jobs-scraper/run-sync-get-dataset-items - Header:
Authorization: Bearer <YOUR_APIFY_TOKEN> - Body (JSON):
{
"searchTerms": ["registered nurse"],
"locations": ["California, United States"],
"datePosted": "past24Hours",
"onlyNewJobs": true,
"monitorName": "nurse-california-daily",
"maxJobsPerSearch": 500
}
With onlyNewJobs, the Actor remembers which job IDs it delivered under that monitorName. The next run skips them before reading their pages, and skipped jobs are free. In my tests, a second run skipped 23 already-seen jobs and delivered 30 new ones.
Connect the output to Slack, email, Google Sheets or Airtable. Use a separate monitorName for every schedule.
What it costs
It's pay per job, no monthly fee:
- $0.80 per 1,000 jobs with the full job page on Apify's Starter plan ($1.00 on the free plan, down to $0.60 on Business).
- $0.30 per 1,000 if you only need the search-card fields (turn off Read job pages).
- A start fee of $0.001 per run.
- Filtered jobs, duplicates, removed jobs and already-seen jobs are free.
A daily alert that finds 15 new jobs costs about $0.013. Apify's free plan includes monthly credits, enough to try it on real searches.
Limitations
- Public pages only. There are no recruiter names, emails or applicant demographics, since those need a login. Contact details inside descriptions are removed.
- Salaries appear only when LinkedIn shows them, mostly in the US, Canada and the UK.
- Workplace type, skills and experience are read from text, so unusual wording can be missed. About half of all jobs never state their workplace type anywhere.
- LinkedIn's result order changes between visits. For monitoring, use Only new jobs instead of comparing two full runs.
- You're responsible for how you use the data, including LinkedIn's terms and privacy laws such as the GDPR.
If a search comes back wrong or you need a field that's missing, leave a comment here or open an issue on the Actor's Issues tab with the run ID. I read them all.
Top comments (0)