# LinkedIn Jobs Scraper (No Login): Search & Job Alerts (`datadesk-io/linkedin-jobs-scraper`) Actor

Scrape public LinkedIn job listings without logging in: title, company, location, posting date, full description, seniority, employment type, industries and applicants. Search by keyword and location, filter by date, title and job type, only-new mode for job alerts. Public job pages only: no profile

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

## Pricing

from $0.96 / 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.
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 (No Login): Search & Job Alerts

Scrape **public LinkedIn job listings without logging in**: search by keyword and location and get clean JSON/CSV/Excel with job title, company, location, posting date, **full description**, seniority level, employment type, industries, applicants and the job URL. **Only-new mode** for daily job alerts. It reads only the public, logged-out job pages that anyone can open in a browser. **No account, no cookies, no API key, no proxy.**

🇪🇸 **Español:** extrae ofertas de empleo **públicas** de LinkedIn sin iniciar sesión: busca por palabra clave y ubicación y obtén título, empresa, ubicación, fecha, descripción completa, nivel de seniority, tipo de contrato, industria y número de postulantes. Modo **solo ofertas nuevas** para alertas diarias. Sin cuenta ni cookies; no extrae perfiles ni datos personales. Ve la sección de responsabilidad más abajo.
🇧🇷 **Português:** extrai vagas **públicas** do LinkedIn sem login: busque por palavra-chave e local e receba título, empresa, local, data, descrição completa, nível de senioridade, tipo de contrato, setor e número de candidatos. Modo **somente vagas novas** para alertas diários. Sem conta nem cookies; não extrai perfis nem dados pessoais. Veja a seção de responsabilidade abaixo.

### What you get

- 🔎 **Search by keyword and location** (one search per keyword × location pair), or paste public LinkedIn job search URLs.
- 📄 **Full job details** (default on): description as text + HTML, seniority level, employment type, industries, applicants and the salary text when the page shows one.
- 🗓️ **Date posted filter** applied by LinkedIn (past 24 hours / week / month).
- 🎯 **Extra filters applied by the Actor:** job type, experience level, remote only, title keywords, excluded titles and companies. Jobs that don't match are skipped and **never charged**.
- 🔔 **Only new jobs** (`onlyNew`, `onlyNewSince`): every row has `isNew` and `firstSeen`. Schedule it daily with "Past 24 hours" and pay only for jobs you haven't seen.
- 💸 **$1.20 per 1,000 jobs**, plus $0.005 per run. Runs with no results cost nothing.

### Built to stay on the public side (and polite)

- **Public job listings only.** The Actor never logs in, never uses cookies or accounts, and never opens profiles. It does **not** collect people, recruiter, employee or other personal data. The only company data is the employer's name and public company page link.
- **Low request rate.** One request at a time with short pauses. When LinkedIn answers with a rate limit (HTTP 429) the Actor cools down for 25-30 seconds and retries; if LinkedIn keeps refusing, the run stops cleanly and keeps (and charges only for) what it already saved.
- **No residential proxies, no tricks to get around blocks.**

### Disclaimer: your responsibility

This Actor is **not affiliated with, endorsed by or sponsored by LinkedIn**. "LinkedIn" is a trademark of its owner and is used here only to describe the source of the public data. **You are responsible for complying with LinkedIn's Terms of Service (which restrict automated access) and with the laws that apply to you** (data protection, copyright, competition, employment). Use the data for lawful purposes, respect the rights of the people and companies in it, and keep volumes reasonable. This text is not legal advice. If LinkedIn changes or restricts public access, the Actor can stop working.

### Pricing

Pay-per-event: **$0.0012 per job** (Store discounts for Silver/Gold/Platinum/Diamond plans) + $0.005 once per run, charged only if at least one job is saved. Duplicates and jobs filtered out are free. A spending limit is respected: the run stops cleanly at it.

### Input (all optional)

```json
{
  "keywords": ["data analyst", "python developer"],
  "locations": ["Spain", "Mexico City"],
  "datePosted": "week",
  "jobType": ["full-time"],
  "experienceLevel": ["entry", "associate"],
  "remoteOnly": false,
  "excludeTitleKeywords": ["intern"],
  "includeDescription": true,
  "maxItems": 50,
  "onlyNew": true
}
```

**Empty input** searches "software engineer" in the United States and returns 25 jobs with full descriptions.

- `keywords` × `locations`: each pair is one search. `maxItems` is shared evenly between the searches unless you set `maxItemsPerSearch`.
- `searchUrls`: public search URLs (`https://www.linkedin.com/jobs/search/?keywords=...&location=...`). Only keywords, location, geoId, distance, date posted and company filters are read from the URL.
- `jobType`, `experienceLevel`, `remoteOnly`: LinkedIn offers these filters only to logged-in users, so the Actor applies them by reading each job's own page. Skipped jobs cost a few extra requests (time) but nothing in credits. `remoteOnly` is text-based (title, location, description).
- `onlyNew`: return only jobs that earlier runs with the same searches (or the same `stateKey`) didn't return. `onlyNewSince`: a date (`2026-10-01`) or a period (`7 days`).
- Turn `includeDescription` off for a fast list (title, company, location, date, URL): about 10 jobs per request.

### Output example (real run)

```json
{
  "jobId": "4476983365",
  "title": "Software Engineer II (Java/AWS)",
  "companyName": "JPMorganChase",
  "companyUrl": "https://www.linkedin.com/company/jpmorganchase",
  "location": "New York, NY",
  "postedAt": "2026-10-08",
  "postedAgo": "2 weeks ago",
  "salaryText": "$123,500.00/yr - $150,000.00/yr",
  "url": "https://www.linkedin.com/jobs/view/4476983365",
  "seniorityLevel": "Not Applicable",
  "employmentType": "Full-time",
  "industries": "Financial Services",
  "applicants": 200,
  "applicantsText": "Over 200 applicants",
  "remote": false,
  "seniority": null,
  "isNew": true,
  "firstSeen": "2026-10-28T18:46:41+00:00",
  "scrapedAt": "2026-10-28T18:46:41+00:00",
  "searchKeywords": "software engineer",
  "searchLocation": "United States",
  "postingKey": "4476983365",
  "descriptionText": "Responsibilities: ... (full job description) ..."
}
```

### Speed and limits (honest)

- LinkedIn throttles anonymous traffic, so this Actor is **slow on purpose**: one request at a time with 1-2 s gaps, about **25-30 jobs per minute with full details** (about 60 per minute as a plain list). In our Apify tests: 25 jobs in 55 s, 60 jobs in 2 min, 200 jobs in 7 min. If LinkedIn rate-limits (HTTP 429), the Actor waits 25-30 s and retries; if it keeps refusing it stops and keeps what it saved. We met no 429 in 288+ requests on Apify, but LinkedIn's limits change by network and by hour.
- Filters beyond date posted run inside the Actor: when few jobs match (e.g. remote only), it checks up to about 100 listings per 5 jobs requested, so it may return fewer jobs than `maxItems`. Example: 'customer support' in Mexico, remote only: 3 jobs from 87 requests.
- LinkedIn serves at most about 1,000 jobs per search. Use several keywords/locations and date filters for more.
- `applicants` is a lower bound when LinkedIn says "Over 200 applicants".
- Salary appears only when the listing shows it (many don't).
- Seniority (`seniority`) is a guess from the title; `seniorityLevel` is LinkedIn's own value.
- Job type, experience and remote filters are applied by the Actor, not by LinkedIn.

### Use cases

Job alerts and job boards for a niche · recruiting and sourcing (who is hiring for what, where) · hiring-trend and market intelligence by role, city or industry · sales triggers (companies hiring for a role you sell to) · career research · feeding AI agents and dashboards.

### Scheduling and integrations

Schedule a task daily with `datePosted: "24h"` and `onlyNew: true` and send new jobs to Slack, email, Google Sheets, Make, Zapier or n8n with webhooks/integrations. REST: `POST https://api.apify.com/v2/acts/datadesk-io~linkedin-jobs-scraper/run-sync-get-dataset-items?token=...`.

### Use with AI agents (MCP)

This Actor works as a tool for AI agents through the [Apify MCP server](https://mcp.apify.com). Add it to Claude, ChatGPT, Cursor, VS Code or any MCP client:

`https://mcp.apify.com/?tools=datadesk-io/linkedin-jobs-scraper`

Sign in with OAuth or `Authorization: Bearer <APIFY_TOKEN>`. Local stdio config:

```json
{"mcpServers": {"linkedin-jobs": {"command": "npx", "args": ["-y", "@apify/actors-mcp-server", "--tools", "datadesk-io/linkedin-jobs-scraper"], "env": {"APIFY_TOKEN": "<token>"}}}}
```

**What goes in → what comes out:** Input: keywords and locations (or public search URLs), optional date, job type, experience, remote and title filters, caps. Output: one JSON row per public job with title, company, location, posting date, description, seniority, employment type, industries, applicants and URL. Every input is optional and every output field is documented.

**Example prompt:** "Find 20 remote data engineer jobs posted in the last 24 hours in Germany on LinkedIn, with company and seniority." Use `maxItems` to cap the cost and time of one call.

### FAQ

**Do I need a LinkedIn account or API key?** No. The Actor never logs in.
**Does it scrape profiles, recruiters or employees?** No. Public job postings only.
**Why so slow?** To respect LinkedIn's rate limits; the Actor pauses instead of hammering the site.
**Is this allowed?** See the disclaimer above: you are responsible for complying with LinkedIn's terms and the law.
**Related:** Greenhouse, Lever, Ashby, Workday and 12 more career systems in one run: [ATS Jobs Scraper](https://apify.com/datadesk-io/ats-jobs-scraper). Large employers on Workday: [Workday Jobs Scraper](https://apify.com/datadesk-io/workday-jobs-scraper). LatAm job boards: [Computrabajo & Bumeran Jobs Scraper](https://apify.com/datadesk-io/latam-jobs-scraper).
**Issues?** Report them on the Issues tab. We usually reply within 48 h.

# Actor input Schema

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

Job titles or skills to search, e.g. 'data analyst', 'react developer', 'nurse'. One search per keyword and location. Leave empty to search a location without keywords.

## `locations` (type: `array`):

City, region or country as you would type it on LinkedIn, e.g. 'Austin, Texas', 'Germany', 'Mexico City', 'Remote'. One search per keyword and location pair.

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

Public job search URLs copied from your browser, e.g. https://www.linkedin.com/jobs/search/?keywords=python\&location=Spain\&f_TPR=r86400. Only the keywords, location, geoId, distance, date posted (f_TPR) and company (f_C) parts are used.

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

Applied by LinkedIn itself. Use 'Past 24 hours' with a daily schedule for job alerts.

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

Keep only jobs of these types. LinkedIn does not offer this filter without a login, so the Actor checks each job's own page; jobs that don't match are skipped and not charged (it takes a few more requests).

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

Keep only jobs with these seniority levels as shown on the job page. Applied by the Actor (not by LinkedIn), so skipped jobs cost extra requests but are never charged.

## `remoteOnly` (type: `boolean`):

Keep jobs whose title, location or description says remote / work from home. LinkedIn does not offer this filter without a login, so this is text-based and can miss jobs that don't say it.

## `titleKeywords` (type: `array`):

Keep only jobs whose title contains at least one of these words (case-insensitive), e.g. 'senior', 'python'.

## `excludeTitleKeywords` (type: `array`):

Drop jobs whose title contains any of these words, e.g. 'intern', 'manager'.

## `excludeCompanies` (type: `array`):

Drop jobs from these company names (exact name, case-insensitive), e.g. staffing agencies.

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

Open every job's public page to get the full description (text + HTML), seniority level, employment type, job function, industries and number of applicants. Turn off for a faster list (title, company, location, date, URL).

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

Hard cap on jobs saved (and charged) in the whole run. LinkedIn serves about 1,000 jobs per search. The Actor is deliberately gentle (one request at a time with pauses): about 25-30 jobs per minute with details, so 100 jobs take about 4 minutes and 1,000 jobs about 35-40 minutes. Keep it small for a quick answer.

## `maxItemsPerSearch` (type: `integer`):

Cap per keyword/location pair. Empty = maxItems divided evenly between the searches.

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

Return only jobs that earlier runs with the same searches (or the same 'State key') did not return. The first run returns everything and remembers it. Schedule it daily with 'Past 24 hours': you pay only for new jobs.

## `onlyNewSince` (type: `string`):

Date (2026-10-01) or period (7 days, 24 hours). Keeps jobs first seen by this Actor since then; jobs never seen before are judged by their LinkedIn posting date.

## `stateKey` (type: `string`):

Name of the memory used by the only-new modes (stored in your key-value store 'linkedin-jobs-scraper-state'). Default: derived from the searches. Use the same key in several tasks to share one memory.

## Actor input object example

```json
{
  "keywords": [
    "software engineer"
  ],
  "locations": [
    "United States"
  ],
  "datePosted": "any",
  "remoteOnly": false,
  "includeDescription": true,
  "maxItems": 25,
  "onlyNew": false
}
```

# Actor output Schema

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

One row per public job posting (see dataset schema for field descriptions).

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

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

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

```

## MCP server setup

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