# Linkedin Job Scraper - No Login (`prs_scraper/linkedin-job-scraper`) Actor

Scrape LinkedIn job postings by keyword, location and date. No login, account or cookies needed. Get title, company, salary, skills, experience, applicant count, recruiter and apply link. Filter by job type, seniority, remote/hybrid and Easy Apply. Duplicates removed.

- **URL**: https://apify.com/prs_scraper/linkedin-job-scraper.md
- **Developed by:** [PRS](https://apify.com/prs_scraper) (community)
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## 💼 LinkedIn Jobs Scraper

Pull fresh job postings from LinkedIn into a clean spreadsheet-ready dataset. Type in the roles you care about and the places you want to search, pick how recent the jobs should be, and get back every matching posting with its full description, company, salary, skills, applicant count and apply link.

No LinkedIn account, no login and no cookies needed. The Actor only reads job postings that LinkedIn shows publicly.

### 🚀 What can you use it for?

- **Job hunting on autopilot**: run a daily search for "Python Developer" in Bangalore, Pune and Remote, and get only the jobs posted in the last 24 hours.
- **Recruitment and sales leads**: find out which companies are hiring right now, for which roles and in which cities, and reach the person who posted the job.
- **Hiring-market research**: see which skills employers ask for most, how much experience they expect, and how crowded each role is.
- **Competitor watch**: track what positions a competitor is opening and where they are building teams.
- **Job boards and newsletters**: keep your own job feed filled with fresh, de-duplicated postings.

### 📦 What data do you get?

| | |
|---|---|
| 💼 Job title and LinkedIn job link | 🏢 Company name, logo and LinkedIn page |
| 📍 Location | 📝 Full job description (plain text and formatted HTML) |
| 🧠 Skills mentioned in the description | 🎓 Experience asked for: minimum and maximum years, plus the exact line from the posting |
| 💰 Salary range, currency and period (when the employer shows it) | 📅 Posting date and "posted X days ago" |
| 👥 Number of applicants and how crowded the job is (low / medium / high) | ⚡ Easy Apply or external application, with the apply link |
| 👔 Employment type (full-time, contract, internship…) | 📊 Seniority level, plus a level worked out from the years of experience |
| 🏭 Industry | 🏠 Remote / hybrid / on-site, when it can be determined |
| 🙋 Name, title and profile of the person who posted the job (when shown) | 🔎 Which of your searches found the job, with a link to that search on LinkedIn |

### 🎯 How to use it

1. Open the Actor and go to the **Input** tab.
2. Add one or more **Keywords**, e.g. `Python Developer`, `Data Analyst`.
3. Add one or more **Locations**, e.g. `India`, `Bangalore`, `London`, `Worldwide`.
4. Choose **Date posted** and how many jobs you want.
5. Click **Start**. When the run finishes, download your jobs as JSON, CSV, Excel, XML or HTML, or view them as a table.

Every keyword is searched in every location. Two keywords and three locations give you six searches. A job that shows up in more than one search is saved only once, and you can see every search that found it.

### ⬇️ Input

#### Keywords and locations

| Field | What it does |
|---|---|
| **Keywords** | Job titles or search terms. Examples: `Backend Developer`, `Product Manager`, `React Native`, `SAP FICO`. |
| **Locations** | Countries, states, cities or `Worldwide`. Examples: `India`, `Maharashtra, India`, `Berlin, Germany`, `United States`. |
| **Date posted** | Any time, past 24 hours, past 7 days or past 30 days. |

#### How many jobs

| Field | What it does |
|---|---|
| **Max jobs** | Stop after this many unique jobs in total. Leave empty to collect everything the pages allow. |
| **Pages per search** | Each page holds 10 jobs. LinkedIn shows up to 100 pages (1,000 jobs) per search. |
| **Start page** | Skip the first pages, for example to continue where a previous run stopped. |

#### Filters applied by LinkedIn

These narrow the search before any job is collected, so you only get, and pay for, jobs that match.

- **Job type**: full-time, part-time, contract, temporary, internship, volunteer, other
- **Experience level**: internship, entry level, associate, mid-senior, director, executive
- **Workplace type**: on-site, remote, hybrid
- **Easy Apply only**
- **Fewer than 10 applicants**
- **Only these companies**: LinkedIn company IDs, or company names
- **Sort by**: most recent or most relevant

#### Exclusions

- **Exclude companies**: skip employers you are not interested in, such as staffing agencies or your current employer.
- **Exclude title words**: skip titles containing words like `Senior`, `Lead` or `Intern`.
- **Exclude locations**: skip jobs in cities you don't want, e.g. `Gurugram`.

#### Extra options

| Field | Default | What it does |
|---|---|---|
| **Fetch job details** | On | Adds the full description, salary, skills, experience, applicants, seniority, industry and recruiter. Turn it off for a quick list of titles, companies and links only. |
| **Include description HTML** | On | Keeps the formatted version of the description (bullets, bold text) next to the plain text. |
| **Save only unique jobs** | On | Turn off to save a job once for every search that found it. |

#### Example input

```json
{
  "keyword": ["Python Developer", "Backend Developer"],
  "location": ["India"],
  "date": "past7days",
  "maxItems": 100,
  "maxPages": 5,
  "experienceLevel": ["entry", "associate"],
  "jobTitleExclude": ["Senior", "Lead"]
}
```

### ⬆️ Output

Results are saved to the run's dataset. Open the **Output** tab to browse them as a table, or export them in the format you need. Two ready-made views are included:

- **Overview**: title, company, location, workplace, type, seniority, years of experience, salary, posting date, applicants, how to apply and the job link.
- **Skills and requirements**: skills, the experience line from the posting, industry, competition, who posted the job, the apply link and which searches found it.

#### Example job

```json
{
  "jobId": "4475773826",
  "jobTitle": "Back End Developer (Pune, Chennai, Bangalore)",
  "jobUrl": "https://www.linkedin.com/jobs/view/4475773826/",
  "companyName": "Creospan Inc.",
  "companyId": "503768",
  "companyUrl": "https://www.linkedin.com/company/creospan/",
  "companyLogo": "https://media.licdn.com/dms/image/v2/C560BAQF-Mj9YDWoTVw/company-logo_100_100/...",
  "location": "Pune City, Maharashtra, India",
  "workplaceType": null,
  "employmentType": "Full-time",
  "seniorityLevel": "Associate",
  "experience": {
    "minYears": 3,
    "maxYears": null,
    "level": "Associate",
    "text": "Experience: 3+ Years"
  },
  "industry": "IT Services and IT Consulting",
  "salary": null,
  "postedDate": "2026-10-08",
  "postedTimeAgo": "8 hours ago",
  "applyType": "Easy Apply",
  "applyUrl": "https://www.linkedin.com/jobs/view/4475773826/",
  "applicants": {
    "count": 200,
    "competition": "high",
    "text": "Over 200 applicants"
  },
  "isClosed": false,
  "skills": ["Java", "Microservices", "Spring Boot", "REST", "SQL", "OOPS", "Multithreading", "Agile", "Scrum"],
  "insights": ["Actively Hiring"],
  "recruiter": {
    "name": "…",
    "title": "Senior Talent Acquisition Specialist",
    "profileUrl": "https://www.linkedin.com/in/…/"
  },
  "jobDescription": "Java Developer – Java, Microservices & Spring Boot\n\nExperience: 3+ Years\n\nLocation: Pune, Bangalore, Chennai ...",
  "jobDescriptionHtml": "<p>Java Developer – Java, Microservices &amp; Spring Boot</p><p><strong>Experience:</strong> 3+ Years</p> ...",
  "searchQuery": "Backend Developer - India",
  "matchedSearches": ["Backend Developer - India"],
  "sourceSearchUrl": "https://www.linkedin.com/jobs/search/?keywords=Backend%20Developer&location=India&f_TPR=r604800",
  "detailsFetched": true,
  "scrapedAt": "2026-10-08T18:23:08Z"
}
```

#### Good to know about the fields

- **`experience`** is read from the job title and description. "3–6 years of experience" becomes `minYears: 3, maxYears: 6`, and "5+ years" becomes `minYears: 5, maxYears: null`. `text` is the exact line it came from, so you can check it at a glance. Numbers that are not about the candidate, like "a company with 20 years of history", are left out.
- **`experience.level`** is worked out from the minimum years: under 2 years is *Entry level*, 2–4 years is *Associate*, 5 or more is *Mid-Senior level*.
- **`seniorityLevel`** is the level the employer picked on LinkedIn. Employers often leave it at a default, so `experience.level` or `experience.minYears` is usually the better guide when you're looking for fresher or 0–2 year roles.
- **`skills`** lists the technologies and skills named in the posting, such as Python, Django, Spring Boot, Unix shell scripting or OOPS.
- **`salary`** is filled only when the employer publishes a salary on LinkedIn, with the amounts as numbers plus the original text.
- **`applicants.count`** is a lower bound when LinkedIn says "Over 200 applicants". `competition` is *low* under 25 applicants, *medium* for 25–100 and *high* above 100.
- **`workplaceType`** is certain when you filter by exactly one workplace type. Otherwise it is worked out from the title, location and description, and left empty when the posting doesn't say.
- **`sourceSearchUrl`** opens the same search on LinkedIn, so you can see the results the job came from.
- Missing information is always `null` or an empty list, never an error. Your exports keep the same columns from run to run.

### ❓ FAQ

#### Do I need a LinkedIn account?

No.

#### How many jobs can I get?

LinkedIn shows up to 1,000 jobs per search, so each keyword and location pair can return up to 1,000. To collect more, add more keywords or split a large location into smaller ones, such as cities or states. For example:

- `New York`, `San Francisco` and `Austin` instead of `United States`
- `London`, `Manchester` and `Edinburgh` instead of `United Kingdom`
- `Berlin`, `Munich` and `Hamburg` instead of `Germany`
- `Bangalore`, `Pune` and `Hyderabad` instead of `India`
- `Toronto`, `Vancouver` and `Montreal` instead of `Canada`
- `Sydney`, `Melbourne` and `Brisbane` instead of `Australia`

#### How do I get only new jobs every day?

Set **Date posted** to *Past 24 hours* and schedule the Actor to run once a day in Apify Console. Each run gives you the jobs posted since the previous one.

#### Why are some salaries empty?

Many employers, especially outside the US, don't publish a salary on LinkedIn. The Actor fills the salary fields only when LinkedIn shows one.

#### How can I make runs faster and cheaper?

- Use **Date posted** and the LinkedIn filters, so fewer jobs need to be collected in the first place.
- Use the exclusion fields to skip companies, titles and locations you don't want.
- Turn off **Fetch job details** if a list of titles, companies and links is enough.
- Set **Max jobs** to the number you actually need.

#### Can I connect it to other tools?

Yes. You can send results to Google Sheets, Slack, Zapier, Make, n8n, Airtable and many other tools using Apify integrations, or trigger your own workflow with a webhook when a run finishes. You can also start runs and download results from your own code through the Apify API, using the `apify-client` package for Python or JavaScript.

### 💬 Feedback and support

Found a bug, missing a field or need a filter that isn't here? Open an issue in the **Issues** tab and we'll take a look.

# Actor input Schema

## `keyword` (type: `array`):

Job titles or search terms, e.g. 'Python Developer'.

## `location` (type: `array`):

Countries, regions or cities, e.g. 'India', 'Bangalore', 'Worldwide'.

## `date` (type: `string`):

Filter applied by LinkedIn itself, so older jobs are never downloaded.

## `page` (type: `integer`):

First results page to read (10 jobs per page).

## `maxPages` (type: `integer`):

How many pages to read for each keyword/location combination, starting at 'Start page'. LinkedIn serves at most 100 pages (1,000 jobs) per search.

## `maxItems` (type: `integer`):

Stop after this many unique jobs in total. Leave empty for no limit beyond the page limit.

## `jobType` (type: `array`):

Employment types to include (LinkedIn filter).

## `experienceLevel` (type: `array`):

Seniority levels to include (LinkedIn filter).

## `workType` (type: `array`):

On-site / remote / hybrid (LinkedIn filter). With exactly one value, every job's workplaceType is known for certain.

## `sortBy` (type: `string`):

Result order. Empty = LinkedIn default.

## `easyApplyOnly` (type: `boolean`):

Only jobs that can be applied to on LinkedIn.

## `under10Applicants` (type: `boolean`):

Only jobs with fewer than 10 applicants.

## `companyInclude` (type: `array`):

Numeric LinkedIn company IDs are filtered by LinkedIn; company names are matched on search results.

## `companyExclude` (type: `array`):

Company names (whole-word, case-insensitive) or numeric company IDs.

## `jobTitleExclude` (type: `array`):

Skip jobs whose title contains any of these words, e.g. 'senior', 'intern'.

## `subLocationExclude` (type: `array`):

Skip jobs whose location contains any of these words.

## `fetchJobDetails` (type: `boolean`):

Description, criteria, salary, applicants, recruiter. Turn off for a cheap listing-only run (measured: ~1.3 KB per job instead of ~14 KB).

## `includeDescriptionHtml` (type: `boolean`):

Also save the original description HTML (larger dataset items, no extra requests).

## `saveOnlyUniqueItems` (type: `boolean`):

If off, a job found by several searches is saved once per search (no extra requests).

## `requestTimeout` (type: `integer`):

Per-request timeout.

## `maxConcurrency` (type: `integer`):

Parallel requests. Higher is rarely better: LinkedIn rate-limits bursts.

## Actor input object example

```json
{
  "keyword": [
    "Software Engineer"
  ],
  "location": [
    "India"
  ],
  "date": "any",
  "page": 1,
  "maxPages": 1,
  "easyApplyOnly": false,
  "under10Applicants": false,
  "fetchJobDetails": true,
  "includeDescriptionHtml": true,
  "saveOnlyUniqueItems": true,
  "requestTimeout": 30,
  "maxConcurrency": 4
}
```

# Actor output Schema

## `overview` (type: `string`):

Job title, company, location, salary, posting date, applicants and link.

## `details` (type: `string`):

Skills, experience, industry, competition and who posted the job.

## `runStats` (type: `string`):

Pages read, jobs found, duplicates skipped and bandwidth used.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keyword": [
        "Software Engineer"
    ],
    "location": [
        "India"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("prs_scraper/linkedin-job-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "keyword": ["Software Engineer"],
    "location": ["India"],
}

# Run the Actor and wait for it to finish
run = client.actor("prs_scraper/linkedin-job-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keyword": [
    "Software Engineer"
  ],
  "location": [
    "India"
  ]
}' |
apify call prs_scraper/linkedin-job-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,prs_scraper/linkedin-job-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/TKADhm0SQ4QP499Zg/builds/sE0YjTrzoy8bdPZNN/openapi.json
