# LinkedIn Jobs Scraper (`barefoot_grade/linkedin-jobs-scraper`) Actor

Search public LinkedIn job postings by keywords and location with date, job-type, remote and experience filters. Each job is one row: title, company, location, posting date, full description, seniority, employment type, job function, industries and applicants. No LinkedIn account needed.

- **URL**: https://apify.com/barefoot_grade/linkedin-jobs-scraper.md
- **Developed by:** [Philip Kirkbride](https://apify.com/barefoot_grade) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.75 / 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.

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

Search public LinkedIn job postings and get every job as one clean row: title, company and company page, location, posting date, the full job description, seniority level, employment type, industries and the applicant count. Search by keywords and location, narrow it with the same filters LinkedIn offers (date posted, job type, on-site/remote/hybrid, experience level), or paste LinkedIn jobs search links you already use. No LinkedIn account, login or cookies are needed.

Use it to track hiring at target companies, build job boards and alerts, research salaries and skills demand, or feed recruiting and sales pipelines with fresh openings.

### Quick Start

```json
{
  "keywords": "python developer",
  "location": "United States",
  "datePosted": "pastWeek",
  "workplaceTypes": ["remote"],
  "maxItems": 100
}
```

This returns up to 100 remote Python developer jobs posted in the past week in the United States, each with its full description and job details.

### Input

| Input | Type | Default | Meaning |
| --- | --- | --- | --- |
| `keywords` | string | — | Job title, skill or company, e.g. `python developer`. |
| `location` | string | — | Country, region or city as you would type it on LinkedIn, e.g. `Germany` or `London, England, United Kingdom`. |
| `geoId` | string | — | Optional LinkedIn numeric location id (the `geoId` in a LinkedIn jobs search link) for a precise search area. |
| `datePosted` | string | `any` | `any`, `past24h`, `pastWeek` or `pastMonth`. |
| `jobTypes` | array | `[]` | Any of `fullTime`, `partTime`, `contract`, `temporary`, `internship`, `volunteer`, `other`. |
| `workplaceTypes` | array | `[]` | Any of `onSite`, `remote`, `hybrid`. |
| `experienceLevels` | array | `[]` | Any of `internship`, `entryLevel`, `associate`, `midSenior`, `director`, `executive`. |
| `sortBy` | string | `relevance` | `relevance` or `recent` (newest first). |
| `searchUrls` | array | `[]` | LinkedIn jobs search links (`https://www.linkedin.com/jobs/search/?keywords=...`). Their keywords, location and filters are used as-is. |
| `maxItems` | integer | `50` | Total cap on job rows across all searches, after removing duplicates (up to 5,000). |
| `includeDetails` | boolean | `true` | Open every job for the full description, seniority, employment type, industries and applicant count. Turn off for faster runs with search-result fields only. |

You need at least keywords, a location or one search link.

### What it returns

One row per job:

| Field | Meaning |
| --- | --- |
| `jobId`, `url` | LinkedIn job id and the job's page link. |
| `title` | Job title. |
| `companyName`, `companyUrl`, `companyLogo` | The hiring company, its LinkedIn page and logo. |
| `location` | Job location as LinkedIn shows it. |
| `postedAt`, `postedAgo` | Posting date (`YYYY-MM-DD`) and the relative time, e.g. `2 weeks ago`. |
| `salary` | Salary range when LinkedIn shows one on the job card; otherwise `null` (many employers put pay only in the description). |
| `benefits` | Card badge such as `Actively Hiring` or `Be an early applicant`. |
| `descriptionText`, `descriptionHtml` | The full job description as readable text and as HTML. |
| `seniorityLevel`, `employmentType`, `industries` | LinkedIn's job criteria, when the employer filled them in. |
| `jobFunction` | Job function, when LinkedIn shows it on the public job page; LinkedIn currently leaves it out, so expect `null`. |
| `applicantsText`, `applicantsCount` | The applicant caption (e.g. `Over 200 applicants`) and its number. |
| `applyType`, `applyUrl` | `offsite` (apply on the company site) or `easyApply` (apply on LinkedIn), and the external apply link when the job page includes it. |
| `isClosed` | `true` when the job no longer accepts applications. |
| `searchKeywords`, `searchLocation`, `searchPosition` | Which search found the job and its rank in the results. |
| `scrapedAt` | Collection time (UTC, ISO 8601). |

With `includeDetails` off, the description, criteria, applicant and apply fields are `null`.

The run summary (`OUTPUT` in the key-value store) reports `jobs` (rows delivered), `errors`, and per-search counts at `searches`.

### Output example

```json
{
  "jobId": "4431992044",
  "url": "https://www.linkedin.com/jobs/view/4431992044",
  "title": "Python Developer",
  "companyName": "CACI International Inc",
  "companyUrl": "https://www.linkedin.com/company/caci-international-inc",
  "companyLogo": "https://media.licdn.com/dms/image/v2/D4E0BAQFob5rET4oo0w/company-logo_100_100/B4EZpUDHB_GYAQ-/0/1762346693140/caci_international_inc_logo",
  "location": "Chantilly, VA",
  "postedAt": "2026-07-08",
  "postedAgo": "3 months ago",
  "salary": null,
  "benefits": "Actively Hiring",
  "descriptionText": "Job Title: Python Developer\n\nJob Category: Information Technology\n\nTime Type: Full time\n\n...",
  "descriptionHtml": "Job Title: Python Developer<br><br>Job Category: Information Technology<br><br>...",
  "seniorityLevel": "Not Applicable",
  "employmentType": "Full-time",
  "jobFunction": null,
  "industries": "Defense and Space Manufacturing",
  "applicantsText": "72 applicants",
  "applicantsCount": 72,
  "applyType": "offsite",
  "applyUrl": null,
  "isClosed": false,
  "searchKeywords": "python developer",
  "searchLocation": "United States",
  "searchPosition": 1,
  "scrapedAt": "2026-10-19T22:00:00+00:00"
}
```

### Failed jobs

If a job's page cannot be read after several retries, that job is listed in the run summary at `OUTPUT.jobErrors` with its `jobId`, `url` and an error `code` and `message`. Failed jobs are never dataset rows and are not charged. A search that stops early is listed at `OUTPUT.searchErrors`; the jobs it already returned are kept. A run that collects no jobs at all ends with an error instead of finishing green with an empty dataset.

### Limits and caveats

- LinkedIn shows at most about 1,000 jobs per search. For more, split the search by location, date posted or job type.
- When few jobs match, LinkedIn widens the search with related postings, as it does on its own website. Check `title` and `location` if you need strict matches.
- Fields such as `salary` or `applyUrl` are `null` when LinkedIn does not show them for that job. Most jobs that use an external application do not show the external link to signed-out visitors, so `applyUrl` is usually `null`; `applyType` still tells you how to apply.
- Only public job postings are collected; no member profiles or personal data.
- Automated access is subject to LinkedIn's terms; use this actor only where you have the necessary permissions and a lawful basis.

### FAQ

**Do I need a LinkedIn account?** No. The actor reads the same public job pages anyone can open without signing in.

**Can I run several searches at once?** Yes. Fill in the search fields and add more LinkedIn jobs search links in `searchUrls`. A job found by more than one search is returned once, and `maxItems` caps the total.

**How do I get only the newest jobs?** Set `datePosted` to `past24h` and `sortBy` to `recent`, and schedule the actor to run daily.

**Why is `salary` empty when the description mentions pay?** `salary` holds the structured range LinkedIn shows on the job card. Pay written inside the description stays in `descriptionText`.

### Price

**$0.00075 per job** delivered, plus **$0.005 per run start**. The run-start event is charged per GB of memory; the default 512 MB run is one start event. The start is charged even if the run saves no results. Failed jobs are not charged. Platform usage is included in these prices.

# Actor input Schema

## `keywords` (type: `string`):

Job title, skill or company to search for, e.g. "python developer" or "registered nurse".

## `location` (type: `string`):

Country, region or city, written as you would type it on LinkedIn, e.g. "United States", "London, England, United Kingdom" or "Germany".

## `geoId` (type: `string`):

LinkedIn's numeric location id (the geoId value in a LinkedIn jobs search link). When set it pins the search area more precisely than the location text.

## `datePosted` (type: `string`):

Only return jobs posted within this window.

## `jobTypes` (type: `array`):

Only return these employment types. Leave empty for all.

## `workplaceTypes` (type: `array`):

Only return these workplace types. Leave empty for all.

## `experienceLevels` (type: `array`):

Only return these experience levels. Leave empty for all.

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

Most relevant first, or most recent first.

## `searchUrls` (type: `array`):

Paste one or more LinkedIn jobs search links (https://www.linkedin.com/jobs/search/?keywords=...). Their keywords, location and filters are used as-is, in addition to the search above.

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

Total cap on job rows across all searches, after removing duplicates. LinkedIn shows at most about 1,000 jobs per search.

## `includeDetails` (type: `boolean`):

Open every job to add the full description, seniority, employment type, industries and applicant count. Turn off for faster runs with search-card fields only.

## Actor input object example

```json
{
  "keywords": "python developer",
  "location": "United States",
  "datePosted": "any",
  "jobTypes": [],
  "workplaceTypes": [],
  "experienceLevels": [],
  "sortBy": "relevance",
  "searchUrls": [],
  "maxItems": 25,
  "includeDetails": true
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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 = {
    "keywords": "python developer",
    "location": "United States",
    "datePosted": "any",
    "maxItems": 25,
    "includeDetails": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("barefoot_grade/linkedin-jobs-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 = {
    "keywords": "python developer",
    "location": "United States",
    "datePosted": "any",
    "maxItems": 25,
    "includeDetails": True,
}

# Run the Actor and wait for it to finish
run = client.actor("barefoot_grade/linkedin-jobs-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 '{
  "keywords": "python developer",
  "location": "United States",
  "datePosted": "any",
  "maxItems": 25,
  "includeDetails": true
}' |
apify call barefoot_grade/linkedin-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,barefoot_grade/linkedin-jobs-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/18WlPmatrI6eR4Pgx/builds/bf7a2HNVE2ciTjdgM/openapi.json
