# Linkedin Job Scraping

> Scrape LinkedIn job listings by keyword and location: title, company, location, link and full job description. No login or cookies. De-duplicated, export to CSV/JSON or use the API.

Actor id `quaking_pail/linkedin-job-scraping`. Index of all Epsimo actors: https://epsimo.org/llms.txt

## What it does

### Linkedin Job Scraping

Scrapes public LinkedIn Jobs search results by keyword and location to extract structured job listing data: job title, employer, job location text, public job URL, and the full job description text. Operates page-by-page (about 10 listings per page), fetches full description over HTTP with a headless Chrome fallback when needed, de-duplicates postings by LinkedIn job identifier across pages, and includes optional proxy support to mitigate rate-limiting. Outputs complete job descriptions suitable for text analysis, classification, matching, retrieval-augmented generation (RAG), hiring-signal detection, and market-level aggregation; designed to run repeated searches and collect incremental results from LinkedIn public guest job pages without authentication.

### Use cases

- Sales and SDR teams identifying companies that are actively hiring as a buying signal.  
- Recruiters and staffing agencies tracking open roles in a city or niche.  
- Job market analysts measuring demand for skills, titles, and locations.  
- Developers and AI builders obtaining full job description text for classification, matching, or RAG.  
- Find companies hiring specific roles (e.g., SDR, engineer, marketer) in a target city for outreach.  
- Build a recurring feed of new roles for downstream processing or tracking.  
- Analyse job descriptions with language models to extract required skills, seniority, or technology stacks.  
- Track hiring trends for competitors or a market over time.

## Use cases and Limits

From the actor README on the Apify Store.

### Use cases for LinkedIn job data

- Find companies hiring SDRs, engineers or marketers in a target city and reach out while the need is fresh.
- Build a weekly feed of new roles into Google Sheets, Slack or a CRM.
- Analyse job descriptions with an LLM to extract required skills, seniority or tech stack.
- Track hiring trends for competitors or a market over time.

### How much will it cost to scrape LinkedIn jobs?

You **pay only per result, no subscription** and no rental. One result is one job saved to the dataset. Run statistics are stored separately and are not charged as results. A small standard Actor start event also applies.

Current prices, including volume discounts on higher Apify plans, are on the **Pricing** tab. Set a **maximum cost per run** and the run stops when that limit is reached.

### Tips for scraping LinkedIn jobs

- Start with `max_pages: 1` to check the results, then scale up.
- LinkedIn's guest search usually shows at most about 1,000 jobs per query. Split large searches by location or keyword.
- If you see empty results or many `429` responses, enable the proxy option.

### FAQ, disclaimers and support

#### Is it legal to scrape LinkedIn job listings?

You should be aware that your results could contain personal data. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

Job descriptions can contain personal data, such as a recruiter's name or contact details. **You are responsible for making sure that your scraping and your use of the results are legal**, including LinkedIn's terms and data protection rules where you operate.

#### Do I need a LinkedIn account or cookies?

No. The Actor only uses LinkedIn's public guest job pages.

#### Why did I get fewer jobs than expected?

LinkedIn may return fewer results for narrow searches, or rate-limit requests. Check the run log and `RUN_METADATA`, and try enabling the proxy.

#### How do I report a problem or request a field?

Open an issue in the **Issues** tab with the run ID. If the Actor saved you time, a rating on the **Reviews** tab helps other users find it.

## Input

| Name | Type | Required | Default | Allowed values / range | Description |
|---|---|---|---|---|---|
| `keywords` | string | yes | `"SDR"` | - | Specific job titles or roles to search for |
| `location` | string | yes | `"Paris"` | - | Geographical location for the job search |
| `max_pages` | integer | yes | `1` | min 1 | Number of search result pages to scrape. Each page returns about 10 jobs; the run stops early when LinkedIn has no more results. |
| `proxyConfiguration` | object | no | - | - | Optional proxy for requests to LinkedIn. Off by default. Use it if you see many 429 or 999 responses in the log; Apify Proxy usage is billed to your account. |

## Example input

Built from the input schema prefill/default values (the actor publishes no example input).

```json
{
  "keywords": "SDR",
  "location": "Paris",
  "max_pages": 1
}
```

## Output

| Field | Type | Description |
|---|---|---|
| `Title` | string or null | Job title (falls back to the company name when the card has no title) |
| `Company` | string or null | Company offering the job |
| `Location` | string or null | Job location as shown on LinkedIn |
| `Link` | string or null | Public URL of the job posting |
| `Description` | string or null | Full job description text, or 'No description available' when LinkedIn returned none |

Dataset views: `overview` (Overview).

## Example output item

Built from the `example` values of the dataset schema.

```json
{
  "Title": "Sales Development Representative",
  "Company": "Example Company",
  "Location": "Paris, Île-de-France, France",
  "Link": "https://www.linkedin.com/jobs/view/sales-development-representative-at-example-company-4000000000",
  "Description": "As a Sales Development Representative, you will..."
}
```

## Pricing

Pay per event, in effect since 2026-10-16 (as of 2026-10-18). Each event below is charged.

| Event | Title | Description | Price USD (FREE tier) |
|---|---|---|---|
| `apify-actor-start` | Actor Start (once per run) | Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). | $0.00005 |
| `apify-default-dataset-item` | Job (primary) | One job listing (with description) saved to the default dataset. | $0.00165 |

Plan-tier prices for `apify-default-dataset-item`: FREE $0.00165, BRONZE $0.0015, SILVER $0.00135, GOLD $0.0012, PLATINUM $0.0012, DIAMOND $0.0012.

Prices are in USD at the Apify FREE plan tier; tiered events can cost less on paid Apify plans (plan-tier prices above). The [Apify Store page](https://apify.com/quaking_pail/linkedin-job-scraping) is authoritative: read the current price there instead of hardcoding these values.

## How to run

Run the actor and get its dataset items in one HTTP call (needs an Apify API token in `$APIFY_TOKEN`, sent in the `Authorization` header as Apify recommends ([Apify API authentication](https://docs.apify.com/api/v2))):

```bash
curl -X POST "https://api.apify.com/v2/acts/quaking_pail~linkedin-job-scraping/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
  "keywords": "SDR",
  "location": "Paris",
  "max_pages": 1
}'
```

Apify also accepts `?token=$APIFY_TOKEN` in the URL, but avoid it: URLs end up in logs and shell history.

If the run takes longer than 300 seconds, this endpoint returns HTTP 408 (Request Timeout). For longer runs start the actor with the asynchronous [Run Actor endpoint](https://docs.apify.com/api/v2/act-runs-post) and read the dataset when the run finishes. The `maxTotalChargeUsd` query parameter caps the total cost of a run ([run-sync-get-dataset-items reference](https://docs.apify.com/api/v2/act-run-sync-get-dataset-items-post)).

## Apify MCP

Apify hosts an MCP server at https://mcp.apify.com. The actor id is `quaking_pail/linkedin-job-scraping`; the `tools` query parameter loads only that actor as a tool ([Apify MCP server](https://docs.apify.com/platform/integrations/mcp)).

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=quaking_pail/linkedin-job-scraping",
      "headers": {
        "Authorization": "Bearer $APIFY_TOKEN"
      }
    }
  }
}
```

Replace `$APIFY_TOKEN` with your Apify API token. Without the `headers` entry the client signs in to Apify with OAuth in the browser instead.

## Links

- Apify Store: [quaking_pail/linkedin-job-scraping](https://apify.com/quaking_pail/linkedin-job-scraping)
- Sources: [actor API](https://api.apify.com/v2/acts/quaking_pail~linkedin-job-scraping), [build API](https://api.apify.com/v2/acts/quaking_pail~linkedin-job-scraping/builds/default)
- Data fetched from the Apify API on 2026-10-18
- Build: 0.6.1

## Do not

- Do not hardcode prices: read them on the Apify Store page before a large run.
- Do not put the Apify token in shared URLs, prompts or logs; prefer the `Authorization` header.
- Do not treat the output as verified: it is scraped from public pages and can be incomplete, outdated or wrong.
