LinkedIn Jobs Scraper avatar

LinkedIn Jobs Scraper

Pricing

from $0.70 / 1,000 public job delivereds

Go to Apify Store
LinkedIn Jobs Scraper

LinkedIn Jobs Scraper

Scrape current public LinkedIn job search cards with job IDs, titles, companies, locations, posted dates, and source links without login.

Pricing

from $0.70 / 1,000 public job delivereds

Rating

0.0

(0)

Developer

Tim Zinin

Tim Zinin

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

Find current public LinkedIn job listings by keyword and location and receive clean, source-linked rows ready for recruiting research, market analysis, and alerts. Enter one to five searches such as software engineer in United States, choose up to three observed result pages per search, and set a total row limit. Each useful Dataset row contains the numeric LinkedIn job ID, title, company, location, displayed posting age, source-provided calendar date, canonical job URL, exact search URL, query attribution, page offset, observation timestamp, and a source reference.

The Actor reads LinkedIn's public guest job-search HTML directly. It does not require LinkedIn login credentials, cookies, an upstream Actor, or a proxy. It parses search cards only: it does not claim to collect job descriptions, applicant counts, recruiter details, or a complete historical archive. Source failures and incomplete coverage are reported separately from a valid empty search.

Pricing is pay per result: $0.001 per delivered job at the base tier, with plan-tier prices of $0.0009 for Bronze, $0.0008 for Silver, and $0.0007 for Gold, Platinum, and Diamond. There is no Actor-start fee and no Dataset-item fee. Only a confirmed useful row triggers result-found; diagnostics and zero-result runs carry no Actor result charge. Repeated current listings are billable again because each run is a new observation. Set a positive Max total charge. The Apify API treats a literal zero as the platform default rather than a zero-dollar cap; use a small positive value below one result price when you need a no-source budget check.

LinkedIn Jobs Scraper workflow

Input

{
"searches": [
{ "keywords": "software engineer", "location": "United States" }
],
"maxItems": 30,
"maxPagesPerSearch": 3
}
FieldContract
searchesRequired array of 1–5 unique { keywords, location } objects. Both values are required, trimmed, and limited to 100 characters.
maxItemsTotal useful rows across all searches, 1–100. Default: 20. Collection is reduced to the number of rows the verified run budget can afford.
maxPagesPerSearch1–3 guest-search pages. Observed offsets are 0, 10, and 20. Default: 1.

Unknown input fields, duplicate searches, invalid limits, and control characters are rejected before collection.

Output

One Dataset item represents one current public job card. This compact row was parsed from the captured software engineer / United States source page on September 12, 2026:

{
"schemaVersion": "1.0",
"recordType": "linkedin_public_job",
"jobId": "4419969671",
"jobURL": "https://www.linkedin.com/jobs/view/senior-software-engineer-%E2%80%93-go-golang-at-general-motors-4419969671",
"title": "Senior Software Engineer – Go (Golang)",
"company": "General Motors",
"location": "Warren, MI",
"postedTimeText": "2 weeks ago",
"postedDate": "2026-08-22",
"keywords": "software engineer",
"searchLocation": "United States",
"pageStart": 0
}

postedDate is copied from the card's datetime attribute. The Actor does not infer a timestamp from phrases such as “2 weeks ago.” jobURL is accepted only when the source anchor uses LinkedIn HTTPS and its path ends in the same numeric jobId.

Coverage and run summary

OUTPUT in the default key-value store records the outcome, requested scope, number of delivered jobs, confirmed event count, per-search page observations, failure details, and a bounded snapshot of delivered rows. coverage.complete remains false: the source is a bounded view of current guest-search cards, not an assertion that LinkedIn has no other matching jobs.

Outcomes have distinct meanings:

  • completed: one or more rows were delivered within the chosen bounds.
  • empty: the source responded normally but exposed no qualifying cards.
  • partial: at least one source request failed after some useful data was collected.
  • source_failed: every attempted search failed and no job row was delivered.
  • budget_stopped: the verified charge limit could not fund all requested output.

A missing job from a later observation is not classified as deleted or closed.

Source and pagination boundaries

The source endpoint is https://www.linkedin.com/jobs-guest/jobs/api/seeMoreJobPostings/search with exact keywords, location, and start parameters. On the captured source, offsets 0, 10, and 20 returned 10 cards each and 30 distinct numeric job IDs. This supports the three-page release limit. LinkedIn can change availability, markup, ranking, and returned counts at any time.

Responses must remain on the exact requested URL, be HTML, fit within 2 MiB, and arrive within the shared 110-second run deadline. Requests do not redirect or retry. A challenge page, unexpected content type, HTTP error, timeout, or malformed card set is reported as a source failure. The error summary retains only a safe endpoint path, attempt count, and status when present.

Deduplication and repeat runs

Within one run, jobId is the identity key across pages and searches. If the same job appears more than once, it is emitted once. The first matching search remains its attribution. Separate runs do not share storage or silently suppress output. This makes scheduled repeat observations transparent: current rows are delivered and charged again, and you can compare snapshots in your own database.

Pricing and budgets

TierPrice per confirmed result-found
Free$0.0010
Bronze$0.0009
Silver$0.0008
Gold, Platinum, Diamond$0.0007

The Actor verifies the live pricing map and raw run charge limit before requesting LinkedIn. Nonzero start, Dataset, or unknown event prices are rejected. A one-row budget limits source collection to one potential row. Storage and charge acknowledgement are treated as one delivery operation; uncertain delivery stops without an automatic retry.

Task recipes

Quick current search uses one page and up to 10 rows:

{"searches":[{"keywords":"software engineer","location":"United States"}],"maxItems":10,"maxPagesPerSearch":1}

Three observed pages uses the source-proven offsets and a 30-row bound:

{"searches":[{"keywords":"software engineer","location":"United States"}],"maxItems":30,"maxPagesPerSearch":3}

Repeat observation uses the same three-page input later. Compare jobId, postedDate, and your observation time; do not interpret absence as a closure signal.

API integration

Start the Actor with your Apify API token in the Authorization header, wait for at most 60 seconds in the POST request, then poll the returned run ID with bounded GET requests if it is still running. Never retry a timed-out POST automatically because the server may have accepted it. Read clean Dataset items from the defaultDatasetId in the terminal run object and read OUTPUT from defaultKeyValueStoreId.

const actorId = 'ACTOR_ID_AFTER_PUBLICATION';
const response = await fetch(`https://api.apify.com/v2/acts/${actorId}/runs?waitForFinish=60`, {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.APIFY_TOKEN}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ searches: [{ keywords: 'software engineer', location: 'United States' }], maxItems: 10, maxPagesPerSearch: 1 }),
signal: AbortSignal.timeout(75_000)
});
if (!response.ok) throw new Error(`Run start failed: ${response.status}`);
const run = (await response.json()).data;

Keep the token outside source code and logs. Check every HTTP status and terminal run status before treating data as complete.

Field dictionary

FieldMeaning
jobIdNumeric ID from urn:li:jobPosting on the card.
jobURLCanonical source anchor after query parameters are removed.
title, company, locationVisible card text, whitespace normalized.
postedTimeTextSource-visible relative age such as 23 hours ago.
postedDateExact YYYY-MM-DD card attribute; no inferred time of day.
keywords, searchLocationQuery that first produced the job in this run.
pageStartGuest-search offset: 0, 10, or 20.
sourceURLExact requested public guest-search URL.
observedAtUTC time when the page was parsed.
source.htmlSha256SHA-256 fingerprint of the bounded HTML response.

Practical uses

Recruiting teams can monitor newly visible roles for a fixed set of competitors. Labor-market analysts can compare current title and location mixes. Sales teams can use company/title signals as research inputs while keeping the LinkedIn source URL for verification. Each use should retain observation timestamps and treat the feed as a bounded sample of current public search cards.

Limits and responsible use

The Actor works only with public guest-search pages. It does not log in, bypass access controls, collect profiles, contact people, or enrich personal data. Source availability is outside the Actor's control. Use results in line with LinkedIn's terms and applicable law, and avoid decisions about individuals based only on a search card.

FAQ

Does it fetch full job descriptions? No. This release parses search cards only.

Does three pages mean all matching jobs? No. It means up to three observed offsets. Ranking and availability can change.

Why did a run return fewer than 10 rows? The source may expose fewer cards, duplicate a job, provide a malformed card, hit the row limit, or encounter a source failure. Inspect OUTPUT.coverage.

Are repeated jobs free? No. Every useful row delivered in a new observation is billable.

Does an absent job mean it closed? No. Absence from a bounded search result is not closure evidence.

From query to verified job rows