# LinkedIn Jobs Scraper - No Login, Strict Match (`datalayer/linkedin-jobs-scraper`) Actor

Search LinkedIn jobs logged out - no account, no cookies, nothing to get banned. Title filters and date ranges are enforced on every row, and the job/spend caps stop the run before the money is spent, not after. Full descriptions on request. Versioned schema that will not break your pipeline.

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

## Pricing

from $1.40 / 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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## LinkedIn Jobs Scraper — no login, strict matching, limits that hold

Search LinkedIn job postings and get clean, stable rows: title, company,
location, posted date, salary when shown, and the full description on request.
No LinkedIn account, no cookies, no session to get banned — this Actor reads
the same public listings LinkedIn serves to any logged-out visitor.

### Why this one

Job scrapers are the most-complained-about category on the store, and the
complaints are always the same three:

1. **"One week it matches strictly, another week 5k+ irrelevant results."**
   Here, `titleMustInclude` / `titleMustExclude` are enforced on every row, in
   one place in the code, every run. A job whose title does not match is never
   delivered and never charged for.
2. **"I set a limit and still paid for thousands."** `maxJobs` and `maxCostUsd`
   are hard ceilings checked **before** each fetch. The run stops collecting at
   the ceiling — it does not keep spending and trim the output afterwards.
3. **"The output format changed and broke my pipeline."** Every row carries
   `schemaVersion`. Fields get added, never renamed or removed, without that
   number changing.

### What you get

One row per job:

| Field | Example |
|---|---|
| `title` | Data Engineer |
| `company` / `companyUrl` | Acme Corp / linkedin.com/company/acme |
| `location` | New York, NY |
| `postedAt` | 2026-08-20 |
| `salary` | $140,000 – $180,000 (when LinkedIn shows it) |
| `jobUrl` | linkedin.com/jobs/view/4012345678 |
| `schemaVersion` | 1 |

With **Fetch full descriptions** on, each row also carries the complete
description (text and HTML), seniority level, employment type, job function,
industries, and the applicant count when shown.

Every run writes a `RUN_SUMMARY` saying exactly what was delivered, what your
filters rejected and why, what failed, and what it cost against your cap.

### Filters that actually filter

- **Posted since** — checked against each posting's own date, per row. Jobs
  outside the range are not delivered and not charged.
- **Job type, experience level, workplace** (on-site / remote / hybrid) —
  LinkedIn's own search filters, passed through.
- **Title must include / exclude** — plain, case-insensitive, predictable
  substring matching applied after the search returns. This is the tool for
  pipelines that need "data engineer" to mean data engineer.

### Honest limits

LinkedIn's public guest search serves at most **1,000 results per query**. That
is LinkedIn's ceiling, not ours, and the Actor says so in the log when you hit
it instead of pretending the search was exhausted. To reach deeper, narrow the
query: split by location, date range, or job type.

### Typical uses

- Feed an ATS or CRM with fresh postings for target roles, on a schedule
- Track which companies are hiring for a role, week over week
- Salary and demand research by title and region
- Lead generation: companies hiring for X are buying tools for X

### Pricing

Pay per result: one price per job row, one small extra price per full
description you ask for. No subscription, no minimum. Set **Max spend (USD)**
and the run cannot cost more than that number.

### FAQ

**Do I need a LinkedIn account? Can my account get banned?** No account is
used at all. The Actor reads the public guest listings LinkedIn serves to
logged-out visitors, so there is nothing to ban.

**How many jobs can one search return?** LinkedIn serves at most 1,000 guest
results per query — that is LinkedIn's ceiling, and the run log says so when
you reach it. To go deeper, split the search by location, date range or job
type and combine the runs.

**Does it return salaries?** When LinkedIn shows one on the listing, yes, in
the `salary` field. Most postings do not carry one; the field is `null` rather
than a guess.

**Do repeated jobs get charged twice?** Not within a run — promoted postings
repeat across pages and are deduplicated by job id before anything is charged.

**Can I export to CSV or feed my ATS?** Yes — every run downloads as CSV,
Excel, JSON or JSONL, or pull the dataset via the API. `schemaVersion` on each
row means the columns will not move under your pipeline.

**Can I run it daily?** Yes. Save your search as a Task, schedule it, and pair
it with `postedSince` so each run returns only what is new since the last one.

# Actor input Schema

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

What to search for, exactly as you would type it into the LinkedIn jobs search box. Example: data engineer.

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

City, region or country, as free text. Examples: United States, Berlin, Sydney NSW. Leave empty to search everywhere.

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

Optional numeric LinkedIn location id for precise targeting (the geoId= value in a LinkedIn jobs search URL). Overrides nothing - it is sent alongside the location text.

## `postedSince` (type: `string`):

Only jobs posted on or after this date, YYYY-MM-DD. This is enforced per row against each posting's own date - a job outside the range is never returned and never charged for.

## `jobType` (type: `string`):

Limit to one employment type, matching LinkedIn's own job-type filter.

## `experienceLevel` (type: `string`):

Limit to one seniority band, matching LinkedIn's experience-level filter.

## `workplace` (type: `string`):

On-site, remote or hybrid, matching LinkedIn's workplace filter.

## `titleMustInclude` (type: `array`):

Keep a job only when its title contains at least one of these terms (case-insensitive). This is the fix for search results drifting off-topic: LinkedIn's keyword match is loose, this filter is not.

## `titleMustExclude` (type: `array`):

Drop a job when its title contains any of these terms (case-insensitive). Example: senior, lead, manager.

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

Fetch each job's full description, seniority, employment type, function and industries. One extra request per job, priced as its own event.

## `maxJobs` (type: `integer`):

Hard ceiling on how many jobs are delivered. Collection STOPS at this number - it does not keep fetching and trim afterwards. LinkedIn's guest search serves at most 1000 results per query; narrow the search to reach deeper.

## `maxCostUsd` (type: `number`):

Hard ceiling on what this run may charge. The run stops before the ceiling is crossed. Set it to what the results are worth to you.

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

Requests go through Apify Proxy (datacenter) by default, which the guest API answers to. Switch to residential only if your runs start seeing 429s.

## Actor input object example

```json
{
  "keywords": "data engineer",
  "location": "United States",
  "geoId": "",
  "postedSince": "",
  "jobType": "any",
  "experienceLevel": "any",
  "workplace": "any",
  "titleMustInclude": [],
  "titleMustExclude": [],
  "includeDescription": false,
  "maxJobs": 25,
  "maxCostUsd": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Every job returned by this run as clean JSON.

## `jobsCsv` (type: `string`):

The same rows as a CSV download, ready for a spreadsheet or ATS import.

## `runSummary` (type: `string`):

What was delivered, what your filters rejected and why, what failed, and what it cost against your cap.

# 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("datalayer/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("datalayer/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 datalayer/linkedin-jobs-scraper --silent --output-dataset

```

## MCP server setup

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