LinkedIn Jobs scraper artworkPublic job postings

LinkedIn Jobs Scraper.

A job posting tells you something about what a company wants to build. Track the roles it's advertising and use the descriptions to research potential expansion or new technical priorities.

Run on Apify

Ways to use this scraper.

Try these examples for marketing, growth and competitor research.

01

Find accounts hiring for skills you work with

If you're a data consultancy, look for companies hiring analytics engineers in London. Read the descriptions for relevant tools, then research whether the company might need project support.

Keep a shortlist with the job link, the date you saw it and a reason to research the account.

02

Follow a competitor's hiring priorities

Watch public openings in sales, partnerships and engineering. Compare new postings over time to investigate changes in priorities or possible market expansion.

Keep a hiring timeline with your research notes.

03

Research demand for a technical skill

For a training business, track postings that mention Python, SQL or dbt in the same region. Review descriptions and seniority before planning course content.

Base the skill-demand study on the postings you collected and state the sample coverage.

FROM FIRST RUN TO REPEATABLE WORKFLOW

Your first run, step by step.

  1. Open the Actor on Apify, select its Input tab and switch to the JSON editor if you want to paste a configuration.
  2. Paste the example into the JSON editor. Change python developer and London to your role and location. If you use searchUrls instead, clear the form’s prefilled keywords and locations to avoid extra searches.
  3. Use a recent datePosted window and a global maxItems limit of 20. Set scrapeJobDetails false for a quick first run. Check the role and location matches before enabling descriptions or adding more filters.
  4. Start the run and watch the log. Check which targets and filters were actually read before assuming an empty result means nothing exists.
  5. Open Storage → Dataset, inspect several records and export JSON for nested data or CSV for a first spreadsheet review.
First-run configuration
{
  "keywords": ["python developer"],
  "locations": ["London"],
  "datePosted": "week",
  "maxItems": 20,
  "scrapeJobDetails": false
}

Paste this into the Actor’s JSON input editor. Replace the example targets with yours before running.

Check the current input form on Apify

Choose how to search.

You can build a search from keywords and locations or copy a filtered LinkedIn Jobs URL. Start with listing cards, then turn on job details when you need descriptions for skills research.

Search methodWhen to use itWhat changes
Keywords and locationsWhen to use itYou want to find relevant results before choosing specific targets.What changesJob titles or skills. Every keyword is paired with every location: three keywords and two locations create six searches. Overlapping jobs are delivered only once.
Search page URLsWhen to use itYou already configured the search on the source website.What changesPaste filtered LinkedIn job-search URLs. They preserve the site’s search filters. Company pages become name searches; individual job-detail URLs are not supported here. Clear prefilled keywords if you only want the pasted searches.
Company IDsWhen to use itYou know the exact entity you want to collect.What changesRestrict to numeric LinkedIn company IDs from the search URL’s f_C filter. A company’s page slug is not the same identifier.

The difference that matters

Each page contains 10 jobs. The public search has a ceiling around 1,000 results per search; raising page limits cannot remove it. Split large searches by location, date or job type.

Compare the related scraper

Every input, explained.

Use the exact field names below in JSON. In Apify’s form, enter list items separately, choose filters, and keep numbers and booleans in their proper types.

Default and prefill are different. A default applies when you omit a setting; a prefill is an example already entered in Apify’s form. Review prefilled targets and limits before every run. Some settings have no schema default. You still need to supply at least one supported target.

Targets and search inputs5
searchUrls
List

Paste filtered LinkedIn job-search URLs. They preserve the site’s search filters. Company pages become name searches; individual job-detail URLs are not supported here. Clear prefilled keywords if you only want the pasted searches.

keywords
ListForm prefill: ["python developer"]

Job titles or skills. Every keyword is paired with every location: three keywords and two locations create six searches. Overlapping jobs are delivered only once.

locations
ListForm prefill: ["London"]

City, region or country names recognized by LinkedIn. Each location adds searches, not a union within one search. Use geoId when a name could refer to several places.

geoId
Text

LinkedIn’s numeric location identifier, copied from geoId in a filtered search URL. It selects a specific place more reliably than a text name.

companyIds
List

Restrict to numeric LinkedIn company IDs from the search URL’s f_C filter. A company’s page slug is not the same identifier.

Markets, dates and filters6
datePosted
TextDefault: any

any, month, week or day. day means the past 24 hours, not a calendar date. For daily monitoring, combine day with sortBy date and retain job IDs between runs.

Suggested JSON values
any month week day
sortBy
TextDefault: relevance

relevance uses LinkedIn’s ranking; date returns the newest postings first. With a global result cap, sort order determines which jobs you collect before stopping.

Suggested JSON values
relevance date
experienceLevel
List

A list of seniority levels. Several selections broaden matching levels. Use the suggested spellings; unfamiliar values are skipped with a note rather than becoming a new level.

Suggested JSON values
internship entry associate mid-senior director executive
jobType
List

Employment types such as full-time, contract or internship. These are job-search filters, distinct from workplaceType, which describes remote, hybrid or on-site work.

Suggested JSON values
full-time part-time contract temporary volunteer internship other
workplaceType
List

Select on-site, remote, hybrid, or several as a list. A remote filter is not a promise that the employer accepts applicants from every country.

Suggested JSON values
on-site remote hybrid
distance
Integer

Search radius in miles, from 0 to 100. Relevant to location-based searches; it does not change whether a role is classified as remote.

Limits, details and proxies6
scrapeJobDetails
True or falseDefault: true

Adds descriptions, seniority, employment type, functions, industries and applicant counts with one extra request per job. Turn off for a fast hiring watchlist; use a proxy when on.

maxItems
IntegerForm prefill: 50

Hard cap on unique jobs across all keywords, locations and pasted searches. It is not per search. Empty removes the cap; maxPagesPerSearch still limits each search.

maxPagesPerSearch
Integer

Each page contains 10 jobs. The public search has a ceiling around 1,000 results per search; raising page limits cannot remove it. Split large searches by location, date or job type.

maxConcurrency
IntegerDefault: 2

1-10 independent searches at once, default 2. More workers can increase throttling. Keep it modest unless you have enough proxy exits for the workload.

delayMs
IntegerDefault: 1000

Pause between page requests, in milliseconds. Increase it when the source throttles you; reducing it does not remove network delays or the source’s rate limits.

proxyConfiguration
ObjectDefault: {"useApifyProxy":true}Form prefill: {"useApifyProxy":true}

Strongly recommended for search and especially full descriptions. LinkedIn can stop serving details before it stops serving search cards, so partial descriptions are not evidence that the postings lack them.

Advanced settings and recovery4
proxyRotations
IntegerDefault: 3

Retries refused work with a new proxy session. More retries can recover temporary blocks but add time and traffic. Keep the default until the log shows a reason to change it.

resume
True or falseDefault: true

Saves progress about every 30 seconds so an Apify restart or migration can continue the current run. Leave it on for normal use.

continueFromLastRun
True or falseDefault: false

Continues unfinished work from the previous run with matching input. Earlier results remain in that run’s dataset. Keep false for a fresh collection or a recurring snapshot.

impersonate
TextDefault: chrome131

The browser identity used for requests. Keep the Actor’s default unless you are diagnosing immediate blocks. It changes the request fingerprint, not the data you ask for.

This reference follows the Actor’s published input fields. Check the live form before changing a production workflow. Check the current input form on Apify.

Configurations you can copy.

Each example is a separate run. Start small, inspect the results, then increase coverage. Update the targets, countries and dates to match your question.

A daily hiring watchlist

Collect recently posted data-engineering roles in London without fetching descriptions. Schedule daily and keep job IDs plus collection dates to distinguish newly found roles from jobs seen yesterday.

A daily hiring watchlist
{
  "keywords": ["data engineer"],
  "locations": ["London"],
  "datePosted": "day",
  "sortBy": "date",
  "maxItems": 50,
  "scrapeJobDetails": false
}

Read the skills employers ask for

Collect full-time hybrid jobs mentioning dbt or BigQuery, with descriptions enabled. Extract repeated skill terms in SQL or ask Claude to group them. The 50-job cap covers both keyword searches together.

Read the skills employers ask for
{
  "keywords": ["dbt", "BigQuery"],
  "locations": ["London"],
  "datePosted": "week",
  "jobType": ["full-time"],
  "workplaceType": ["hybrid"],
  "maxItems": 50,
  "scrapeJobDetails": true,
  "maxConcurrency": 2
}

Research remote roles in one market

Look at entry and associate Python roles advertised as remote in Germany. Remote does not mean worldwide hiring eligibility. Read the description for residence, time-zone and work-authorization requirements.

Research remote roles in one market
{
  "keywords": ["python developer"],
  "locations": ["Germany"],
  "datePosted": "week",
  "experienceLevel": ["entry", "associate"],
  "workplaceType": ["remote"],
  "maxItems": 50,
  "scrapeJobDetails": true
}

Run, check, export, repeat.

Keep job IDs, company, location, posting time and source links. Detailed descriptions let you extract skills, seniority and employment terms, but salaries and applicant fields can be absent. This is a public job dataset, not recruiter contact data. For hiring trends, deduplicate within a snapshot and keep repeated observations over time.

  1. Check the dataset and the run’s SUMMARY record. Compare the number collected with your cap, inspect failed or skipped inputs, and verify a few original source links.
  2. Keep the original IDs and add collected_at and run_id when saving results. Export CSV for flat columns; retain JSON when arrays or nested details matter.
  3. Save the tested configuration as an Apify Task and schedule it. For repeated snapshots, leave continueFromLastRun false. Deduplicate new records by source ID while retaining each observation date.
  4. In Make or n8n, wait for a successful run, fetch its dataset and map fields into Sheets or your warehouse. Send records to Looker Studio through a reporting table; use dbt to flatten and test warehouse models.
  5. The same JSON works with Apify’s Actor API. In Claude with Apify MCP, name this Actor, ask it to inspect the live schema, and give explicit targets, markets and result limits before it runs.

Resume is not a fresh snapshot

resume protects the current run if Apify restarts it. continueFromLastRun continues an earlier run with the same configuration; earlier records stay in the earlier dataset. Combine both datasets for the complete collection, and raise a previously reached result cap when continuing. Start fresh when you want to see what changed today.

Follow the Sheets, Claude, Looker and BigQuery setup guides
Run this Actor from the API

Save one configuration above as input.json. Set APIFY_TOKEN to your Apify API token in your terminal, then send the file as the request body.

Start the run
curl --fail-with-body --request POST \
  --url "https://api.apify.com/v2/actors/jmlp~linkedin-jobs-scraper/runs" \
  --header "Authorization: Bearer $APIFY_TOKEN" \
  --header "Content-Type: application/json" \
  --data-binary @input.json

The response contains a run ID and defaultDatasetId, not finished results. Wait for the run to succeed, set DATASET_ID to that dataset ID, then fetch its items. For large datasets, use limit and offset to page through the export.

Fetch the dataset
curl --fail-with-body \
  --url "https://api.apify.com/v2/datasets/$DATASET_ID/items?format=json" \
  --header "Authorization: Bearer $APIFY_TOKEN"

Apify’s run and export API reference
Dataset export options

When the results look wrong.

Change one setting at a time, keep a small cap, and check the run summary before scaling up.

The listing exists, but detailed fields are missing.

Adds descriptions, seniority, employment type, functions, industries and applicant counts with one extra request per job. Turn off for a fast hiring watchlist; use a proxy when on.

Detailed requests start getting blocked.

Strongly recommended for search and especially full descriptions. LinkedIn can stop serving details before it stops serving search cards, so partial descriptions are not evidence that the postings lack them.

The location matched a different place.

LinkedIn’s numeric location identifier, copied from geoId in a filtered search URL. It selects a specific place more reliably than a text name.

The run succeeded but returned nothing

Success means the Actor finished handling the request, not that the source returned data. Check SUMMARY.inputProblem, SUMMARY.problem and the log for missing targets, unsupported filters or refused requests. Test one known target with fewer filters.

Fewer records than expected

Check the global limit, per-search or per-page limits, platform coverage and deduplication. Several searches can find the same record. A source’s headline count can include records the public endpoint does not return. Review unfinished jobs before treating the dataset as complete.

Use the results in your tools.

Google Sheets

Keep company, role, posted_date and job_url in an account research sheet. Add your reviewed signal category and a separate column for what your team does next.

Read the setup
Claude + MCP

Ask Claude to find explicit skill and tooling mentions in descriptions and cite the job URLs. Have it label any suggestion of commercial demand as a hypothesis.

Read the setup
Looker Studio

Chart new posting IDs by company, location and role category. Use the same search criteria over time and show what your sample covers.

Read the setup
BigQuery + dbt

Keep raw observations and a current job table keyed by job_id. Verify company identities before joining jobs to CRM accounts for account research.

Read the setup
Copy a prompt for Claude
Prompt for Claude + Apify MCP
Check jmlp/linkedin-jobs-scraper, then collect up to 50 analytics engineer postings in London from the past week with details. Identify explicit Python, SQL or dbt mentions, cite each job_url, and build an account research shortlist. Label service-demand interpretations as hypotheses.

The fields you’ll get.

Keep the collection time and original IDs with your records. You’ll need them to check where a result came from or compare it with a later run.

Before you draw conclusions

A vacancy shows hiring intent. It doesn't confirm a completed hire, a budget or expansion. Salary and applicant counts may be missing. Check for reposts and duplicate roles before drawing conclusions about growth, and keep the job IDs and observation dates.

job_id / job_url
A stable posting ID and a source link.
title / company / company_url
The role and public company identity.
location / posted_date
Location and the published posting date.
description
Job text when detailed collection is enabled.
seniority_level / employment_type
Available role classifications.
salary / applicants
Only populated when the source publishes them.

Common questions.

Do I need to share a LinkedIn account or cookie?

No. This scraper uses publicly accessible job postings and does not require your LinkedIn login or session cookie. An Apify account is needed to run it.

Can it confirm that a company is growing?

No. Public vacancies can suggest priorities, but they do not establish completed hires or company growth. Use them as a prompt for further research.

Source and current product details: JMLP’s LinkedIn Jobs Actor on Apify.

Other scrapers
you might use.

Let’s talk about
your project.

Tell me what you need to collect or understand. I can help with a custom scraper, a pipeline or the analysis.

Start a project