# LinkedIn Jobs Scraper: No Login, Full Details, $1.10/1K Jobs (`actorforgehq/linkedin-jobs-scraper`) Actor

Input: job keywords and a location, with filters for date posted, job type, experience level and on-site or remote work. Output: one JSON row per job with title, company, location, posted date, salary when shown, seniority, employment type and full description. No login. $1.10 per 1,000 jobs.

- **URL**: https://apify.com/actorforgehq/linkedin-jobs-scraper.md
- **Developed by:** [Sluicebox](https://apify.com/actorforgehq) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.10 / 1,000 jobs

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: No Login, Full Details, $1.10/1K Jobs

Search **public LinkedIn job listings by keyword and location**, filter by date posted, job type,
experience level and on-site or remote work, and get one clean JSON row per job: title, company,
location, posted date, salary when shown, seniority, employment type, industries, applicant count,
the full description as text and as HTML, and the job poster when LinkedIn shows one. Use only-new
mode on a schedule to get just the listings that appeared since your last run.

It reads the same public job search and job pages LinkedIn serves to a visitor who is not logged in,
over plain HTTP with no page rendering, no LinkedIn account and no cookies, at a fixed pace.

### What you get

One row per job:

```json
{
  "jobId": "4452633172",
  "url": "https://www.linkedin.com/jobs/view/4452633172/",
  "title": "Brand Marketing Manager",
  "companyName": "Clermont Hotel Group",
  "companyUrl": "https://uk.linkedin.com/company/clermont-hotel-group",
  "location": "London, England, United Kingdom",
  "postedAt": "2026-10-08",
  "salary": null,
  "seniorityLevel": "Not Applicable",
  "employmentType": "Full-time",
  "industries": "Hospitality",
  "applicantsText": "Over 200 applicants",
  "descriptionText": "Clermont Hotel Group Central Support Office\n\nContract: Full Time\n\n...",
  "descriptionHtml": "Clermont Hotel Group Central Support Office<br><br>Contract: Full Time<br><br>...",
  "posterName": "Georgina Spacey",
  "posterTitle": "Head of Resourcing at Clermont Hotel Group",
  "posterProfileUrl": "https://uk.linkedin.com/in/georgina-spacey-a6b74824",
  "searchKeyword": "marketing manager",
  "searchLocation": "London",
  "scrapedAt": "2026-10-22T06:48:12.345Z"
}
```

`salary` is present only when LinkedIn shows a pay range on the job page (about one listing in ten
in our test searches). `jobFunction` is present only when the page lists it. `posterName`,
`posterTitle` and `posterProfileUrl` are `null` when the page shows no job poster (most listings:
about one in eight shows one). With **Include full description** off, a row holds only the search
card fields: `jobId`, `url`, `title`, `companyName`, `companyUrl`, `location`, `postedAt`, the
search keyword and location, and `scrapedAt`.

### Input

| Field | Type | Description |
|---|---|---|
| `keywords` | string\[] | Job titles or skills, e.g. `["data engineer", "machine learning engineer"]`. Each line is a separate search. |
| `location` | string | A country, city or region as you would type it on LinkedIn, e.g. `United States`, `London`, `Remote`. Empty searches worldwide. |
| `datePosted` | string | `any` (default), `past24h`, `pastWeek` or `pastMonth`. |
| `jobType` | string\[] | Any of `fullTime`, `partTime`, `contract`, `temporary`, `internship`, `volunteer`, `other`. Empty keeps all. |
| `experienceLevel` | string\[] | Any of `internship`, `entry`, `associate`, `midSenior`, `director`, `executive`. Empty keeps all. |
| `workplaceType` | string\[] | Any of `onSite`, `remote`, `hybrid`. Empty keeps all. |
| `maxItems` | integer | Max jobs per search (default 100, hard cap 1,000). LinkedIn itself shows at most about 1,000 results for one search. |
| `includeDescription` | boolean | Default `true`: read each job's page for the description, criteria, applicant count and job poster. `false` keeps only the search card fields and is about ten times faster. |
| `startUrls` | array | Public LinkedIn job search URLs (`linkedin.com/jobs/search?...`) with the filters set on the site, as `{ "url": "..." }` objects. Each URL is one more search. |
| `onlyNew` | boolean | Default `false`. Skip jobs this Actor already gave you from the same searches in earlier runs. See [Only new since last run](#only-new-since-last-run). |
| `proxyConfiguration` | object | Defaults to Apify **datacenter proxies**, which is the supported configuration. Residential proxies work too. |

Example:

```json
{
  "keywords": ["data engineer"],
  "location": "United States",
  "datePosted": "pastWeek",
  "workplaceType": ["remote"],
  "maxItems": 200,
  "startUrls": [
    { "url": "https://www.linkedin.com/jobs/search?keywords=data%20engineer&location=Canada&f_TPR=r604800" }
  ]
}
```

### How to use it

1. Click **Try for free** or **Start** on this page.
2. Enter one or more job keywords and a location, pick the filters you need and set **Max jobs
   per search**.
3. Run it. Jobs land in the dataset as one row each. Export them as JSON, CSV or Excel, or pull them
   over the API.

To watch a search on a schedule, use Apify **Schedules** with `onlyNew: true`. Pricing has no
per-run start fee, so a scheduled check costs exactly the rows it delivers. To call it from code,
use the [Apify API](https://docs.apify.com/api/v2) or an official client. AI agents can call it
through the **Apify MCP server**: the description and the input fields above are written to be read
by an agent.

### Only new since last run

Turn on **Only new since last run** (`onlyNew: true`) for monitoring. Here "new" means "not delivered
to you before from the same search", not "newer by date".

- Jobs you already got from a search are not written to the dataset and not charged.
- `maxItems` counts new rows only. LinkedIn orders search results by relevance, not by date, so a
  listing that is new to you can sit below listings you already have. The Actor therefore keeps
  paging until it has seen three pages in a row with nothing new, then stops. A quiet search costs
  three requests and no row charges.
- The list of delivered jobs lives in a named key-value store in your own Apify account, called
  `linkedin-jobs-only-new-` plus a code made from your searches (the run log shows the exact name).
  Each set of searches (keywords with their location and filters) gets its own store, so changing a
  keyword or a filter starts a fresh list for the set. `maxItems` and `includeDescription` do not.
  The store does not expire. The latest 2,000 jobs per search are remembered.
- The list is saved once, at the end of the run. If a run is aborted or times out, the list stays as
  it was, so the next run delivers again what that run had delivered. For the same reason, do not
  let two runs with the same input overlap.
- To start over, delete that store in Apify Console under **Storage**, **Key-value stores**.

### Pricing

Pay-per-event, one event, nothing else:

| Event | Rate |
|---|---|
| `job-scraped` | **$1.10 per 1,000** ($0.0011 each), one per job row |
| Run start | **free, there is no start event** |

**What you get for $1:** 909 jobs. Platform usage (compute, proxy) is charged to us, not to you, so
the per-row price is the whole bill. A row costs the same with or without the full description. A
daily check of three searches that finds 40 new jobs costs $0.044, every day, with no per-run
surcharge. Rates are as of the last README update. The Store page stays authoritative.

### Limits (honest)

- **Only what LinkedIn shows a logged-out visitor.** The Actor reads public job search and job pages.
  It does not log in, so it never sees anything that needs an account: no Easy Apply details, no
  recruiter contact details, no profiles.
- **About 1,000 results per search.** LinkedIn stops paging a search near 1,000 results. For more
  jobs, split the input by location, date posted or other filters: each split is its own search with
  its own 1,000.
- **LinkedIn's search decides what matches.** The Actor returns what LinkedIn's own search shows for
  your keywords and location, in LinkedIn's order. It is not an exhaustive scan of every listing.
- **Posted date is a date, not a time.** LinkedIn states the posting date on the result card as a
  day (`2026-10-08`), so `postedAt` is a date.
- **Salary and job poster only when shown.** In our test searches LinkedIn showed a pay range on
  about one listing in ten and a job poster on about one in eight. Where it shows neither, the fields
  are `null`. The description is saved as is: if an employer wrote a salary or a contact into the
  text, it stays in the text.
- **Text comes as plain text plus the original HTML.** `descriptionText` keeps paragraphs and list
  items. `descriptionHtml` keeps the formatting LinkedIn serves (bold, lists, line breaks).
- **A listing that disappears between the search and the job page** (withdrawn or expired) is
  logged and skipped, not invented.
- **No login, no captcha solving.** If LinkedIn refuses a request, the Actor waits, switches to a
  fresh proxy session and retries. It fails honestly rather than fabricate data.
- If more than 5% of requests in a run fail, the run log says so loudly. A run in which every fetch
  failed is marked **failed**, not "succeeded with 0 items". A run whose filters legitimately match
  nothing still succeeds, with an empty dataset and an empty bill.

### Rate-limit etiquette (built in, with numbers)

- **One request every 2 seconds**, about 30 per minute. One search page carries 10 jobs. With the
  full description on, 100 jobs are about 110 requests, under 4 minutes. With it off, 100 jobs are
  10 requests, about 20 seconds.
- On an HTTP `429` or `999` the Actor **waits 15 seconds** (then 30, then 45), switches to a fresh
  proxy session and retries, at most 3 times. On any other transient refusal it backs off (3 s,
  then 6 s, then 9 s) and retries the same way.
- If five requests in a row fail after all retries, the run stops instead of grinding through the
  rest of the plan.
- The default run timeout is one hour, enough for about 1,500 jobs with descriptions in one run.
  For bigger inputs raise the timeout or split the input across runs.

### FAQ

**Do I need a LinkedIn account, cookies or an API key?**
No. The Actor reads only publicly available pages as a logged-out visitor, never logs in, and does
not use anyone's credentials.

**Can I filter by company or use LinkedIn's other filters?**
Set the filters on LinkedIn's own job search page and paste the URL into `startUrls`. The Actor
keeps the filter parameters it recognises (keywords, location, date posted, job type, experience
level, workplace type, company, sort order, distance) and drops the paging and tracking ones.

**Why are `posterName` and `salary` null for most jobs?**
Because LinkedIn shows them on only a part of its listings. The Actor saves them when they are on
the page and `null` when they are not. It never guesses.

**Can I get only new jobs for a saved search?**
Yes. Keep the same `keywords`, `location` and filters, set `onlyNew: true`, and run the Actor on a
schedule. Each run returns only the jobs it has not delivered to you before.

**Does it use a browser?**
No. Pages are fetched over plain HTTP and read straight from the HTML LinkedIn serves, with no
rendering.

**Where is my data stored?**
In your run's dataset on your Apify account, under your control. The Actor keeps no copy of scraped
data outside your run and sends nothing to any third party. With **Only new since last run** on, it
also keeps the ids of jobs it already gave you in a key-value store in your account (see above), so
you can delete them at any time.

### Legal

This is an **unofficial** scraper. It is not affiliated with, endorsed by, or connected to LinkedIn
Corporation or Microsoft in any way. It reads only data that LinkedIn serves publicly to any
logged-out visitor: no login, no credentials, no captcha solving. Website terms of service are a
contractual matter between a website and its visitors, not criminal law. You are responsible for
ensuring that your use of the collected data complies with the laws that apply to you and with
LinkedIn's terms. Job descriptions belong to the employers who published them.

### Personal data

A job listing is an employer's public advertisement. The only fields about a person are
`posterName`, `posterTitle` and `posterProfileUrl`: the name, headline and public profile link of
the person LinkedIn itself shows on the public job page as the job poster, saved only when LinkedIn
shows them. The Actor does not open profiles, does not look up emails or phone numbers, and performs
no enrichment. A description is saved as is: if an employer wrote a contact into it, that text stays
in the description and is not extracted into a field. Scraped data lives only in your own Apify
dataset and is not retained by us outside your run. If the data you collect contains personal data
under the laws of your jurisdiction (for example the GDPR), you act as its controller: it is your
responsibility to have a legal basis for processing and to honor data-subject requests, including
deletion.

### Rate this Actor

If this Actor saved you time, a short rating or review on its Store page helps other people find it.
Missing a field, or did something break? Open the **Issues** tab on this page and tell us.

### Need a custom scraper?

We can build a custom version of this Actor, for example with extra fields, other filters or another output format, or a new Actor for a site we do not cover yet. It runs on Apify like this one. Email actorforge.hq+orders@gmail.com with the site, the data you need and how often you need it.

### Other Actors by ActorForge

- [Reddit Data Scraper](https://apify.com/actorforgehq/reddit-data-scraper): subreddit feeds,
  posts with their first comments, keyword search and user history in one Actor.
- [Reddit Subreddit Scraper](https://apify.com/actorforgehq/reddit-subreddit-scraper): the hot,
  new, top and rising posts of any subreddit, with date bounds and only-new mode.
- [Reddit Comments Scraper](https://apify.com/actorforgehq/reddit-comments-scraper): the whole
  comment thread of a post, with "more replies" branches and deep reply chains.
- [Reddit Search Scraper](https://apify.com/actorforgehq/reddit-search-scraper): posts and
  comments matching keywords, across Reddit or inside one subreddit, with only-new mode.
- [Reddit User Scraper](https://apify.com/actorforgehq/reddit-user-scraper): a user's public
  posts and comments, newest first, with the profile card.
- [Lazada Reviews Scraper](https://apify.com/actorforgehq/lazada-reviews-scraper): product
  reviews, ratings and buyer media from all six Lazada marketplaces.
- [Wildberries Scraper](https://apify.com/actorforgehq/wildberries-scraper): products, prices
  and reviews from Wildberries as clean, schema-validated JSON.
- [Avito Real Estate Scraper](https://apify.com/actorforgehq/avito-real-estate-scraper): full
  property inventory from Avito with freshness stamps.

### Changelog

- **0.1** (October 2026): first release. Keyword and location search with date posted, job type,
  experience level and workplace filters, LinkedIn search URLs as input, full description with
  criteria, applicant count and job poster when shown, only-new mode, $1.10 per 1,000 jobs, no
  start fee.

# Actor input Schema

## `keywords` (type: `array`):

Job titles or skills to search for, one per line, for example data engineer. Each line is a separate search with the location and filters below.

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

Where the jobs are, as you would type it on LinkedIn: a country, a city or a region, for example United States, London or Remote. Leave empty to search worldwide.

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

Keep only jobs posted within this window: any time (default), past 24 hours, past week or past month.

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

Employment types to keep. Pick several to combine them; leave empty for all.

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

Seniority levels to keep. Pick several to combine them; leave empty for all.

## `workplaceType` (type: `array`):

On-site, remote or hybrid. Pick several to combine them; leave empty for all.

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

How many jobs to keep per search (default 100, hard cap 1,000). LinkedIn itself shows at most about 1,000 results for one search, so for more jobs split the input by location or filters.

## `includeDescription` (type: `boolean`):

On by default: each job's page is read for the full description, seniority, employment type, job function, industries, applicant count and the job poster when LinkedIn shows one. Turn it off to get only the search card fields (title, company, location, posted date, salary when shown), which is faster.

## `startUrls` (type: `array`):

Public LinkedIn job search URLs (linkedin.com/jobs/search?...), one per line, with the filters already set on the site. Each URL is one more search, in addition to the keywords above.

## `onlyNew` (type: `boolean`):

Skip jobs this Actor already gave you in earlier runs with the same searches: they are not saved again and not charged. New means not delivered to you before. With this on, Max jobs counts new rows only, and paging stops at the first page where every job was already delivered. The list of delivered jobs is kept in a key-value store in your own Apify account named linkedin-jobs-only-new- plus a code made from your searches (the run log shows the exact name). It does not expire. To start over, delete that store in Storage.

## `proxyConfiguration` (type: `object`):

Apify datacenter proxies are the default and the supported configuration: in our measurements LinkedIn's public job pages answered them as well as residential ones at a fraction of the cost. Residential proxies work too.

## Actor input object example

```json
{
  "keywords": [
    "data engineer",
    "machine learning engineer"
  ],
  "location": "United States",
  "datePosted": "any",
  "jobType": [
    "fullTime",
    "contract"
  ],
  "experienceLevel": [
    "midSenior"
  ],
  "workplaceType": [
    "remote"
  ],
  "maxItems": 100,
  "includeDescription": true,
  "startUrls": [
    {
      "url": "https://www.linkedin.com/jobs/search?keywords=data%20engineer&location=United%20States&f_TPR=r604800&f_WT=2"
    }
  ],
  "onlyNew": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `jobs` (type: `string`):

One row per job: title, company, location, posted date, salary when shown, seniority, employment type, job function, industries, applicant count, full description and the job poster when LinkedIn shows one.

# 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": [
        "data engineer"
    ],
    "location": "United States"
};

// Run the Actor and wait for it to finish
const run = await client.actor("actorforgehq/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": ["data engineer"],
    "location": "United States",
}

# Run the Actor and wait for it to finish
run = client.actor("actorforgehq/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": [
    "data engineer"
  ],
  "location": "United States"
}' |
apify call actorforgehq/linkedin-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,actorforgehq/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/BqdBoJWcqbYoXJQLM/builds/VE8rVqXIeFCzyGAvr/openapi.json
