LinkedIn Jobs Scraper – No Login
Pricing
$0.60 / 1,000 scraped jobs
LinkedIn Jobs Scraper – No Login
Scrape public LinkedIn jobs by keyword and location. Filter by date, job type, experience, workplace, Easy Apply, or under 10 applicants. Extract company, salary, applicant count, seniority, employment type, description, and job URL when available.
Pricing
$0.60 / 1,000 scraped jobs
Rating
0.0
(0)
Developer
DataScraperES
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Search public LinkedIn job listings by keyword and location and export one structured dataset item per unique job. Use filters for publication date, employment type, experience level, workplace type, Easy Apply, and jobs shown with fewer than 10 applicants.
The Actor can return lightweight search-card data or visit each public job page to add the full description, applicant text, seniority, employment type, job function, and industries.
What can you use it for?
- Build or refresh a job board.
- Monitor which roles competitors are hiring for.
- Track remote, hybrid, or on-site demand by market.
- Analyze salary, seniority, and employment-type trends.
- Find newly published roles for recruiting or job-search workflows.
- Send fresh job listings to a spreadsheet, database, CRM, webhook, or automation.
What data can you collect?
Each result can contain:
- LinkedIn job ID and public job URL
- Job title and location
- Company name, LinkedIn company page, and logo
- Publication date and relative posting age
- Salary text when LinkedIn displays it
- Applicant text when publicly available
- Full public job description
- Seniority level and employment type
- Job function and industries
- The keyword and location that discovered the job
- Detail status and request metadata for transparent quality checks
Field availability depends on what LinkedIn publishes for each job. Missing optional values are returned as null; the Actor does not invent unavailable data.
Pricing
The Actor costs $0.0006 per unique job written to the dataset, equivalent to $0.60 per 1,000 jobs.
| Dataset results | Price |
|---|---|
| 25 | $0.015 |
| 100 | $0.06 |
| 500 | $0.30 |
| 1,000 | $0.60 |
| 5,000 | $3.00 |
There is no Actor start fee. You are not charged for duplicate jobs, retries, failed search requests, or searches that produce no dataset items.
A valid job card is still a billable result when optional detail fields cannot be recovered. In that case, the item is saved with status: "partial" and a detailStatus explaining which optional detail request failed.
Quick start
- Open the Actor's Input tab.
- Add one or more job-search keywords.
- Enter a location such as
Spain,Madrid,United States, orWorldwide. - Choose the maximum number of jobs for each keyword.
- Add optional filters.
- Keep Fetch full job details enabled when you need descriptions and job criteria.
- Click Start.
- Open the run's Dataset to preview or download the results.
No proxy, LinkedIn account, or cookie configuration is required from the user.
Input reference
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
keywords | string array | Yes | — | One independent search per keyword. Accepts 1–50 unique values. |
location | string | Yes | — | Free-text location understood by LinkedIn, such as a country, city, region, or Worldwide. |
geoId | string | No | Empty | Numeric LinkedIn geographic ID. Use it when you need more exact geographic targeting. |
maxItemsPerQuery | integer | No | 25 | Maximum jobs collected for each keyword, from 1 to 1,000. This is a limit, not a guaranteed result count. |
datePosted | string | No | any | Publication-age filter: any, past24Hours, pastWeek, or pastMonth. |
jobTypes | string array | No | All | Filter by full-time, part-time, contract, temporary, volunteer, internship, or other. |
experienceLevels | string array | No | All | Filter from internship through executive level. |
workplaceTypes | string array | No | All | Filter by on-site, remote, or hybrid work. |
easyApplyOnly | boolean | No | false | Return only jobs marked with LinkedIn Easy Apply. |
under10ApplicantsOnly | boolean | No | false | Return only jobs shown as having fewer than 10 applicants. |
includeJobDetails | boolean | No | true | Fetch each public detail page. Disable it for faster search-card-only collection. |
Accepted filter values
jobTypes:
fullTime, partTime, contract, temporary, volunteer, internship, other
experienceLevels:
internship, entryLevel, associate, midSenior, director, executive
workplaceTypes:
onSite, remote, hybrid
Input examples
Basic job search
Collect up to 25 software engineering jobs in Spain with full details:
{"keywords": ["software engineer"],"location": "Spain","maxItemsPerQuery": 25,"includeJobDetails": true}
Recent remote and hybrid jobs
Search two roles and keep jobs posted during the past week:
{"keywords": ["data engineer", "analytics engineer"],"location": "Europe","maxItemsPerQuery": 100,"datePosted": "pastWeek","jobTypes": ["fullTime", "contract"],"experienceLevels": ["associate", "midSenior"],"workplaceTypes": ["remote", "hybrid"],"includeJobDetails": true}
Easy Apply with fewer applicants
{"keywords": ["SEO specialist"],"location": "Madrid, Spain","maxItemsPerQuery": 50,"datePosted": "past24Hours","easyApplyOnly": true,"under10ApplicantsOnly": true,"includeJobDetails": true}
Faster card-only collection
Disable job details when you only need job discovery fields such as title, company, location, posting date, salary text, and URL:
{"keywords": ["product manager", "project manager"],"location": "United States","maxItemsPerQuery": 250,"datePosted": "pastMonth","includeJobDetails": false}
With includeJobDetails: false, these fields normally remain null: applicantsText, descriptionText, seniorityLevel, employmentType, jobFunction, and industries.
How limits and duplicates work
maxItemsPerQuery applies separately to every keyword. For example, three keywords with maxItemsPerQuery: 100 can inspect up to 300 job cards.
The final number can be lower because:
- LinkedIn returned fewer matching public jobs.
- The selected filters narrowed the search.
- The same job appeared under multiple keywords.
- A public search page was temporarily unavailable.
Jobs are deduplicated by LinkedIn job ID across the entire run. When the same job matches multiple keywords, it is written once and keeps the first searchKeyword that discovered it.
Output example
Each dataset item represents one unique LinkedIn job:
{"success": true,"status": "success","searchKeyword": "software engineer","searchLocation": "Spain","jobId": "1234567890","jobUrl": "https://www.linkedin.com/jobs/view/1234567890","title": "Software Engineer","companyName": "Example Corp","companyUrl": "https://www.linkedin.com/company/example","companyLogoUrl": "https://media.licdn.com/example-logo.png","location": "Madrid, Spain","postedDate": "2026-07-12","postedText": "1 day ago","salary": null,"applicantsText": "47 applicants","descriptionText": "Build and maintain reliable services...","seniorityLevel": "Mid-Senior level","employmentType": "Full-time","jobFunction": "Engineering and Information Technology","industries": "Software Development","criteria": {"seniorityLevel": "Mid-Senior level","employmentType": "Full-time"},"detailStatus": "success","detailHttpStatus": 200,"detailAttempts": 1,"scrapedAt": "2026-07-13T12:00:00Z"}
Output field reference
| Field | Description |
|---|---|
success | true when all requested data for the item was collected successfully. |
status | success or partial. |
searchKeyword | First keyword that discovered the job. |
searchLocation | Location supplied in the Actor input. |
jobId | LinkedIn's unique job identifier. |
jobUrl | Canonical public LinkedIn job URL. |
title | Job title. |
companyName | Hiring company name. |
companyUrl | Public LinkedIn company page when available. |
companyLogoUrl | Company logo URL when available. |
location | Job location displayed by LinkedIn. |
postedDate | Parsed publication date when available. |
postedText | Relative posting age, for example 1 day ago. |
salary | Public salary text when shown on the search card. |
applicantsText | Public applicant text from the job detail page. |
descriptionText | Full public job description as plain text. |
seniorityLevel | LinkedIn seniority criterion. |
employmentType | Full-time, part-time, contract, internship, or another published type. |
jobFunction | Published job function. |
industries | Published industry information. |
criteria | All parsed job criteria as key-value pairs. |
detailStatus | Result of the optional job-detail request. |
detailHttpStatus | HTTP status returned by the detail request when available. |
detailAttempts | Number of attempts used for the detail request. |
scrapedAt | UTC timestamp when the item was created. |
The external application destination is not guaranteed because LinkedIn does not consistently expose it in public job responses. jobUrl always points to the public LinkedIn job posting.
Understanding result status
status: "success": the requested result was collected successfully.status: "partial": the valid search card was saved, but the optional detail page did not recover after bounded retries.detailStatus: "not_requested":includeJobDetailswas disabled.detailStatus: "success": the public detail page was fetched and parsed.- Other
detailStatusvalues identify temporary blocking, rate limiting, network failure, an unavailable job, an upstream error, or an unrecognized response.
Partial results retain the core job fields and can still be useful in job-discovery pipelines.
Downloading and integrating results
Open the run's Dataset tab to preview the results. Apify can export the dataset as JSON, JSONL, CSV, Excel, XML, RSS, or an HTML table.
The Actor output also provides:
results: API URL for the default dataset items.summary: API URL for the non-sensitiveSUMMARYrecord.
The summary contains query counts, output totals, successful and partial item counts, skipped duplicates, pagination totals, retries, and total duration.
Run with the Apify API
Replace YOUR_APIFY_TOKEN and the example input values as needed.
cURL
Run the Actor synchronously and return its dataset items:
curl -X POST \"https://api.apify.com/v2/acts/datascraperes~linkedin-jobs-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"keywords": ["software engineer"],"location": "Spain","maxItemsPerQuery": 25,"datePosted": "pastWeek","includeJobDetails": true}'
Python
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("datascraperes/linkedin-jobs-scraper").call(run_input={"keywords": ["software engineer", "data engineer"],"location": "Spain","maxItemsPerQuery": 50,"datePosted": "pastWeek","workplaceTypes": ["remote", "hybrid"],"includeJobDetails": True,})for job in client.dataset(run["defaultDatasetId"]).iterate_items():print(job["title"], job["companyName"], job["jobUrl"])
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });const run = await client.actor('datascraperes/linkedin-jobs-scraper').call({keywords: ['software engineer', 'data engineer'],location: 'Spain',maxItemsPerQuery: 50,datePosted: 'pastWeek',workplaceTypes: ['remote', 'hybrid'],includeJobDetails: true,});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const job of items) {console.log(job.title, job.companyName, job.jobUrl);}
Apify CLI
Save your input as input.json, then run:
apify actors call datascraperes/linkedin-jobs-scraper \--input-file input.json \--output-dataset
The Actor's API tab in Apify Store also generates ready-to-run examples for the current Actor version.
Scheduling recurring searches
Use an Apify Schedule when you need fresh jobs every hour, day, or week:
- Save the desired Actor input as a Task.
- Create a Schedule for that Task.
- Use
past24HoursorpastWeekto focus on fresh listings. - Send completed-run results through a webhook or an Apify integration.
- Deduplicate across scheduled runs in your destination using
jobId.
Deduplication inside the Actor applies to one run and its resurrection. Separate scheduled runs use separate datasets, so persistent monitoring systems should keep previously seen jobId values in their own database or automation.
Reliability and resuming runs
The Actor uses controlled concurrency, request pacing, retries with backoff, fresh proxy sessions after transient failures, pagination safety limits, and deduplication by job ID.
If an Apify run is resurrected with the same input, it restores its saved progress and avoids writing completed jobs again. Changing the input creates a new progress fingerprint and starts a new search.
Tips for better results
- Use specific keywords such as
senior React developerinstead of a broad term such asdeveloper. - Run separate searches for important title variations.
- Use a precise location or
geoIdwhen the free-text location is ambiguous. - Use
past24HoursorpastWeekfor recurring monitoring. - Disable
includeJobDetailswhen you only need discovery fields and want a faster run. - Keep full details enabled when descriptions, applicant text, seniority, job function, or industries are required.
- Remember that salary and applicant information are not published for every job.
Troubleshooting
| Situation | Explanation and action |
|---|---|
| No results | Broaden the keyword, location, or date filters and confirm that the same search has public LinkedIn results. |
| Fewer jobs than requested | maxItemsPerQuery is a maximum. LinkedIn may expose fewer jobs, and duplicates are removed. |
Some fields are null | The employer or LinkedIn did not publish those optional fields, or full details were disabled. |
Results have status: "partial" | The core job card is valid, but an optional detail request failed after retries. Check detailStatus. |
| The run reports failed queries | Review the SUMMARY record. Retry later or split a large multi-keyword input into smaller runs. |
| Results repeat across scheduled runs | Deduplicate in your destination using jobId; each scheduled run has its own dataset. |
| Location is inaccurate | Use the full location name or provide a numeric LinkedIn geoId. |
| The input is rejected | Check the exact enum values in the Input reference and keep maxItemsPerQuery between 1 and 1,000. |
Limits and important notes
- A maximum of 50 unique keywords is accepted per run.
- Each keyword can request up to 1,000 public job cards.
- The maximum is not guaranteed because it depends on public availability and selected filters.
- Public page structure and field availability can change.
- Closed or removed jobs can disappear between search and detail retrieval.
- Salary, applicants, company page, logo, and job criteria are best-effort fields.
- This Actor collects job-posting data, not private LinkedIn account data.
Local development
Clone the repository and create a Python 3.13 virtual environment:
git clone https://github.com/datacrawler-edu/actor-linkedin-jobs.gitcd actor-linkedin-jobspython -m venv .venv
On Windows PowerShell:
.\.venv\Scripts\Activate.ps1python -m pip install -r requirements-dev.txt
Run the local quality gate:
python -m ruff check .python -m ruff format --check .python -m compileall -q src testspython -m pytest -qapify validate-schema
Real HTTP validation requires the private proxy URL at runtime. Never store a real credential in .env, source files, fixtures, logs, or Git history. See docs/PRODUCTION_RUNBOOK.md for the release procedure.
Project documentation
- docs/PRODUCTION_RUNBOOK.md: secrets, release gate, deployment, monetization, and incident signals.
- docs/VALIDATION_2026-07-13.md: local and remote validation evidence.
- docs/HTTP_RESEARCH_2026-07-13.md: researched public endpoint and parser contract.
- CHANGELOG.md: release history.
Responsible use
This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by LinkedIn Corporation. LinkedIn is a registered trademark of its owner.
Use the data responsibly and ensure that your use complies with applicable laws, data-protection requirements, and the terms that apply to the source and your intended use case.