LinkedIn Jobs Scraper
Reads the public job offers that LinkedIn shows without logging in, for a job title and a place, and returns them as JSON: title, company, location, posted date, the salary line when the card shows one, and the offer address.
You pay per offer returned, and you set a cost cap per run. This Actor is independent and not affiliated with, endorsed by or sponsored by LinkedIn.
Input
| query | Job title or keywords, required |
|---|---|
| location | City or country, required |
| maxItems | Maximum offers returned. Default 20, up to 100 |
| includeDescription | true opens the page of each offer to add its description and criteria. Default false |
| maxCostUsd | Cost cap per run in USD, start event included. Default 0.25, enough for 100 offers |
| proxyConfiguration | Optional Apify proxy settings. Unset by default |
Example input
{ "query": "data engineer", "location": "Toronto", "maxItems": 5, "includeDescription": false }
Output
| jobId | Always returned |
|---|---|
| title | Always returned |
| company | Always returned |
| location | Always returned |
| postedDate | YYYY-MM-DD, or null |
| salary | The salary line as displayed on the card, or null; most offers show none |
| url | Always returned |
| description | With includeDescription: plain text |
| seniorityLevel | With includeDescription |
| employmentType | With includeDescription |
| industries | With includeDescription |
With includeDescription set to true, the Actor also opens the public page of each offer and adds its description and its criteria. It is off by default, because it adds one request per offer.
Example output
Output, from a run of this Actor with that input: two of the five items. The offers, dates and companies are those the site showed at the time of the run and change from one run to the next.
[ { "jobId": "4412402859", "title": "Data Engineer", "company": "Lakeview Loan Servicing, LLC.", "location": "North York, Ontario, Canada", "postedDate": "2026-05-15", "salary": null, "url": "https://www.linkedin.com/jobs/view/4412402859" }, { "jobId": "4470030555", "title": "Data Engineer", "company": "Zurich Canada", "location": "Toronto, Ontario, Canada", "postedDate": "2026-10-16", "salary": null, "url": "https://www.linkedin.com/jobs/view/4470030555" } ]
Cost of a run
| 20 offers (the default) | 20 × $0.001 + $0.00005 = $0.02005 |
|---|---|
| 100 offers (the maximum) | 100 × $0.001 + $0.00005 = $0.10005 |
maxCostUsd stops the run when the cost of the offers returned, start event included, reaches it. Offers already returned are kept, and the run status says it stopped at the cost cap.
What it does not return
Anything about the person who published the offer: no name, no profile link, no job title of that person, no hiring-team block.
Email addresses and phone numbers: those recognised in a description (international numbers with a plus sign, North American numbers, five pairs of digits) and email addresses are replaced by [removed], as are links to personal profiles. A contact written in another way can remain; the pattern is a filter, not a guarantee.
Applicant counts, company pages and any field that is not listed above.
How the Actor reads LinkedIn
One request every 5 seconds, with a declared User-Agent that names this Actor. No login, no cookie, no account, no challenge solving, no disguise. If the site refuses two requests in a row (for example status 429 or 403, or a sign-in page), the run stops there and keeps what it already returned: it does not retry around the refusal. The first page of results gives about 60 offers; the next pages are read by offset. A run of 100 offers without descriptions took about 40 seconds in our measurement (6 list requests); with descriptions each offer adds one more request, so it takes much longer.
Other Actors by Tollprobe
Amazon Product Search Scraper: public Amazon search results for a keyword as JSON, billed per product.