# LinkedIn Company Jobs Scraper - Every Opening, No Login (`thodor/linkedin-company-jobs-scraper`) Actor

LinkedIn jobs scraper tool that takes a company and returns every job it has open, with full descriptions, seniority, and applicant counts. No login or cookies.

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

## Pricing

from $1.00 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

### What does LinkedIn Company Jobs Scraper do?

LinkedIn jobs scraper tool that takes a company and returns every job that company has open. Give it `vercel`, get back all of Vercel's live postings with the full description, seniority, applicant count, and location on each one. No login, no cookies, no LinkedIn account.

Real output from a run on `vercel`:

| Job title | Location | Posted | Seniority | Function | Applicants |
| --- | --- | --- | --- | --- | --- |
| Software Engineer, Dashboard | New York, United States | 2026-07-19 | Mid-Senior level | Engineering | 200+ |
| Software Engineer, Next.js | San Francisco, CA | 2026-07-15 | Entry level | Engineering | 200+ |
| Software Engineer, Observability | London, England, United Kingdom | 2026-07-07 | Mid-Senior level | Engineering | 76 |
| Software Engineer, CDN Content | San Francisco, CA | 2026-07-07 | Entry level | Engineering | 200+ |

Every row also carries the full HTML job description, employment type, posting and expiry dates, required skills, the hiring organization block, and the original LinkedIn URL.

### Why use LinkedIn Company Jobs Scraper?

Keyword job scrapers answer "who is hiring a Rust engineer in Berlin". This one answers "what is this specific company doing", which is a different question with different uses:

- **Watch an account list for hiring activity.** A company that opens five sales roles is staffing a push. Run your target accounts on a daily schedule and you see it the day it happens.
- **Get the whole account picture in one row.** Every job arrives with the employer's industry, exact headcount, follower count, HQ, and founded year already attached, so a row reads "Vercel, 1,006 employees, Software Development, San Francisco, is hiring a Software Engineer in London". No second lookup, no join, no add-on.
- **Map a competitor's roadmap from their job specs.** Job descriptions name the stack, the team, and the problem before any announcement does. Vercel's openings above are all Engineering, split across Dashboard, Next.js, Observability, and CDN.
- **Track headcount direction over time.** Same companies, same schedule, and the count per company becomes a growth or contraction signal.
- **Build a candidate feed for companies someone actually wants to work at**, instead of a keyword firehose.

Because the input is a company rather than a search query, you are not subject to the 1,000-result ceiling LinkedIn puts on job searches. Each company is walked to exhaustion on its own.

### How to use LinkedIn Company Jobs Scraper

1. Open the Actor and put your companies in the **Companies** field. A slug (`vercel`), a full URL (`https://www.linkedin.com/company/vercel`), or a country subdomain (`https://be.linkedin.com/company/vercel`) all work.
2. Click **Start**. Jobs stream into the dataset as they are found, so the **Output** tab fills up before the run finishes.
3. Export as JSON, CSV, or Excel, or pull the dataset over the [Apify API](https://docs.apify.com/api/v2#/reference/datasets).

#### Use it as a LinkedIn jobs API

Every run is an HTTP endpoint. Call the Actor synchronously and get the jobs back in the response body:

```bash
curl -X POST "https://api.apify.com/v2/acts/thodor~linkedin-company-jobs-scraper/run-sync-get-dataset-items?token=<APIFY_TOKEN>" \
  -H 'Content-Type: application/json' \
  -d '{"companies": ["vercel"]}'
```

The same call from Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("thodor/linkedin-company-jobs-scraper").call(
    run_input={"companies": ["vercel"], "maxJobsPerCompany": 0}
)
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], job["location"], job["posted"])
```

#### Run it on a schedule

Set **Posted within** to `Past 24 hours` and put the Actor on a daily [Apify Schedule](https://docs.apify.com/platform/schedules). Each run then returns only what appeared since the last one, so the dataset becomes a feed of new openings rather than a full re-scrape. Add a webhook and new postings land in Slack, Airtable, or your CRM the morning they go live. The n8n and Make integrations take the same trigger, so the feed can drive an existing workflow instead.

### Input

```json
{
  "companies": ["https://www.linkedin.com/company/vercel", "microsoft"],
  "postedWithin": "any",
  "maxJobsPerCompany": 0
}
```

| Field | Type | Default | What it does |
| --- | --- | --- | --- |
| `companies` | array | required | Company slugs or full LinkedIn URLs. Mix both in one run. |
| `postedWithin` | dropdown | Any time | Limits results to jobs posted in the last 24 hours, week, or month. |
| `maxJobsPerCompany` | integer | `10` | Stop after this many jobs per company. **Set it to `0` to get every opening**, which is what most real runs want. The default of 10 just keeps a first run quick. |

Narrowing `postedWithin` cuts the work sharply, because LinkedIn applies it before we page through anything. Measured on Vercel in one sitting:

| Posted within | Jobs returned | Oldest posting |
| --- | --- | --- |
| Any time | 44 | 2026-07-09 |
| Past month | 37 | 2026-07-10 |
| Past week | 15 | 2026-07-22 |
| Past 24 hours | 9 | 2026-07-29 |

There is no country filter yet. Runs return a company's postings worldwide.

### Output

![LinkedIn Company Jobs Scraper output showing job title, location, posted date, seniority, applicant count and company details for each scraped LinkedIn job](https://api.apify.com/v2/key-value-stores/LHcvkclm26dcJvwP1/records/linkedin_output_example_jobs.png)

One dataset row per job:

```json
{
  "input_target": "vercel",
  "org_id": "16181286",
  "company_slug": "vercel",
  "job_id": "4437886728",
  "title": "Software Engineer, Observability",
  "company": "Vercel",
  "company_url": "https://www.linkedin.com/company/vercel",
  "location": "London, England, United Kingdom",
  "posted": "2026-07-07",
  "employment_type": "FULL_TIME",
  "seniority": "Mid-Senior level",
  "job_function": "Engineering",
  "industries": "Technology, Information and Internet",
  "applicants": 76,
  "easy_apply": false,
  "description_html": "<p>...</p>",
  "description_text": "...",
  "view_url": "https://uk.linkedin.com/jobs/view/software-engineer-observability-at-vercel-4437886728"
}
```

The example above is trimmed to fit. A real run returns every field in the table below on each row, including the full job description.

You can preview the results in the **Output** tab while the run is still going, and download the whole dataset as JSON, CSV, Excel, HTML, XML, or RSS from the **Storage** tab. Everything is also available through the [Apify API](https://docs.apify.com/api/v2#/reference/datasets), and through the Make, Zapier, n8n, Google Sheets, and Slack integrations.

### Data table

| Field | Notes |
| --- | --- |
| `job_id`, `view_url` | Stable LinkedIn identifiers. Use `job_id` to deduplicate across runs and detect new postings. |
| `title`, `location`, `posted` | The basics, on every row. |
| `date_posted`, `valid_through` | Exact timestamps from LinkedIn's structured data, more precise than the listing's date. |
| `applicants` | Capped by LinkedIn at 200. A row showing `200` means "200 or more", and `applicants_raw` keeps the original wording. |
| `seniority`, `job_function`, `industries`, `employment_type` | Always in English, on every company in every country. |
| `months_of_experience` | Required experience as a number, so `24` means two years. Filter on it directly instead of parsing the description. |
| `employer_job_id` | The employer's own requisition ID, separate from LinkedIn's `job_id`. Use it to join against a company's careers page or ATS. |
| `base_salary` | Populated when LinkedIn publishes structured pay, which is uncommon on public postings. Usually `null`. |
| `description_html`, `description_text` | Full posting body, as HTML and as plain text with paragraphs and list items on their own lines. Feed either to an LLM to pull out tech stack, salary, or team structure. |
| `skills`, `education`, `hiring_org`, `job_location` | Present when LinkedIn publishes them, `null` when it does not. |
| `company_details` | The hiring company's industry, exact employee count, follower count, HQ, website, founded year, type, specialties, and address, on every row. |
| `detail_error` | `null` on success. Set when a detail page failed, so you can retry those rows without rerunning the company. |

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

Billing is per job returned, at the per-1,000 rate shown on this page. There is no charge per company or per page fetched, so `maxJobsPerCompany` doubles as a hard cost cap, and a company with no open jobs costs next to nothing to check.

The 44-job Vercel run above bills as 44 jobs, a few cents at any plan tier. A daily watch of 50 accounts that surfaces 100 new postings a day stays in single-digit dollars a month. The monthly usage credit included in Apify's free plan covers a few thousand jobs.

### Tips and advanced options

- **Detect new postings, not all postings.** Set `postedWithin` to `24h` on a daily schedule and every run is already just the new ones. If you need to be certain nothing slipped through a missed run, keep the `job_id` set from last time and diff it as well.
- **Large employers.** Companies with thousands of openings hit a ceiling around 700 to 800 unique jobs per run, which is LinkedIn's limit on what one IP is served rather than a limit of this Actor. For companies under a few hundred openings, which is most of them, a run gets everything. Set `maxJobsPerCompany` to bound the run when a sample is enough.

### Under the hood

**Geo-targeting is not supported yet.** Every run returns a company's postings worldwide.

**No login, no cookies, no account.** Jobs come from LinkedIn's public guest endpoints, the same pages a logged-out visitor sees. Requests use Chrome TLS impersonation so they look like an ordinary browser.

**Requests go out directly first.** Only when LinkedIn refuses does the Actor retry through a US proxy, up to 5 times, and each retry lands on a different IP. A clean run never touches the proxy. Refusal means HTTP 403, 429, or 999, or a 200 served from the login wall, which LinkedIn uses instead of an error code on gated pages.

**Runs stop themselves when LinkedIn shuts the door.** If 15 requests fail back to back, the run ends with an explanation rather than grinding on. Any success resets that counter, so scattered blocks in a long run are harmless. Whatever was scraped before the stop stays in the dataset.

**One IP sees roughly 700 to 800 jobs per employer.** That is LinkedIn's limit on what it serves a single address, not a limit of this Actor. Most companies have far fewer openings than that, so it only affects the giants.

**Jobs arrive 10 at a time**, and a company is done once 5 consecutive requests return nothing new, because LinkedIn loops back to earlier results past the real end of a large listing rather than returning empty.

**Jobs are not returned newest first.** LinkedIn orders them by its own relevance ranking, so a run on Vercel put a posting from the 29th eighth in the list and one from the 11th fifth. Sort on `date_posted` if you need chronology, and be aware that `maxJobsPerCompany` therefore takes an arbitrary slice rather than the most recent postings.

### FAQ

**Do I need a LinkedIn account or cookies?**
No. The Actor reads LinkedIn's public guest endpoints, the same pages a logged-out visitor sees. Your account is never used, so it cannot be restricted or banned for your runs.

**Is this legal?**
It collects only publicly visible job postings, which are published deliberately so people can find and apply to them. It does not touch private data and it does not log into anyone's account. You are responsible for how you use the output, and GDPR applies to you if you store personal data an employer chose to write into a description.

**Does it include the recruiter who posted the job?**
No. LinkedIn shows the job poster only to logged-in members. Fields that require login are left out rather than filled with guesses.

**Why is `base_salary` usually null?**
LinkedIn publishes structured pay only when the employer provides it, which is uncommon. When it exists you get currency, range, and pay period. The rest of the time salary often sits in the description text, and `description_text` is there to mine for it.

**Why did a company return 0 jobs?**
That company has no public postings right now. Runs are not region-limited, so a zero is a real zero rather than a filter hiding results.

**Can I search by keyword or location instead?**
Not here. This Actor is built around a company as the input. For keyword-and-location searches across all of LinkedIn, use a job search scraper instead.

**How current is the data?**
It is fetched live from LinkedIn at the moment of the run. There is no cached database in between, so what you get is what the page shows right then.

### Support

Found a bug or need a field that is not here? Open an issue on the **Issues** tab and it will be looked at.

# Actor input Schema

## `companies` (type: `array`):

LinkedIn companies to scrape jobs from. Use the company slug (e.g. `vercel`) or the full page URL (e.g. `https://www.linkedin.com/company/vercel`). Country subdomains like `be.linkedin.com` work too. Every company returns all of its public postings worldwide.

## `postedWithin` (type: `string`):

Only return jobs posted inside this window. Narrowing it makes runs much cheaper: on a company with 57 open roles, the past 24 hours took 2 requests instead of 12. Pair `Past 24 hours` with a daily schedule to pick up new postings only.

## `maxJobsPerCompany` (type: `integer`):

Stop after this many jobs per company. Defaults to 10 so a first run finishes in seconds. **Set it to 0 to get every job a company has**, which LinkedIn serves up to roughly 700-800 per run. Note that LinkedIn returns jobs in its own relevance order rather than by date, so a limit gives you an arbitrary selection and not the most recent ones.

## Actor input object example

```json
{
  "companies": [
    "https://www.linkedin.com/company/vercel"
  ],
  "postedWithin": "any",
  "maxJobsPerCompany": 10
}
```

# Actor output Schema

## `results` (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 = {
    "companies": [
        "https://www.linkedin.com/company/vercel"
    ],
    "maxJobsPerCompany": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("thodor/linkedin-company-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 = {
    "companies": ["https://www.linkedin.com/company/vercel"],
    "maxJobsPerCompany": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("thodor/linkedin-company-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "companies": [
    "https://www.linkedin.com/company/vercel"
  ],
  "maxJobsPerCompany": 10
}' |
apify call thodor/linkedin-company-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=thodor/linkedin-company-jobs-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/CezllAYHCjfYHvD7i/builds/aaDp3gv6EOf7Qpt1G/openapi.json
