# Jobs Scraper - LinkedIn, Workday, Greenhouse & 15+ Job Sources (`admirala/jobs-scraper`) Actor

US + Europe job listings: LinkedIn search (no login), career sites on Workday, Greenhouse, Lever, Ashby, Personio, Recruitee, Teamtailor & more, plus public job APIs (German and Swedish employment agencies, remote boards). $0.0012 per job.

- **URL**: https://apify.com/admirala/jobs-scraper.md
- **Developed by:** [Ja doei](https://apify.com/admirala) (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 $0.84 / 1,000 per job listing delivereds

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

## Jobs Scraper - LinkedIn, Workday, Greenhouse & 15+ Job Sources

> ✅ **Tested daily** with its default input (Apify's automated QA plus our own smoke test before every release).

**One job scraper for the US and Europe.** Search LinkedIn Jobs by keyword and location (no login, no cookies), search the public job databases of the German and Swedish employment agencies and three remote-job boards, and pull every open job straight from a company's career site on **Workday, Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio, Teamtailor, BambooHR and Breezy HR** by just typing the company name or pasting the career-page URL. Every job comes back in the same clean format: title, company, location, country, remote flag, salary, posted date, employment type, seniority, full description and apply link.

**$0.0012 per job**, lower on higher Apify plans. Proxy cost is included.

### Sources and coverage

| Source | How it is read | Coverage |
|---|---|---|
| **LinkedIn Jobs** | public guest job search (no login) | worldwide: every US state and every European country (`location`, `countries` or `geoId`) |
| **Workday** career sites | the public JSON API behind `*.myworkdayjobs.com` career sites | large employers, mostly US and global (paste the career-site URL) |
| **Greenhouse, Lever, Ashby, Workable, SmartRecruiters** | official public job-board APIs | tech companies and scale-ups, US + Europe |
| **Recruitee, Personio, Teamtailor** | official public job feeds (Recruitee offers API, Personio XML feed, Teamtailor RSS) | strong in the Netherlands, Germany/Austria/Switzerland and the Nordics |
| **BambooHR, Breezy HR** | public careers JSON | small and mid-size companies, mostly US |
| **Bundesagentur für Arbeit** (German Federal Employment Agency) | public Jobsuche API | Germany's largest job database (set `countries` to `DE`) |
| **Arbetsförmedlingen / JobTech** (Swedish Public Employment Service) | open JobSearch API (ads licensed CC0) | Sweden (set `countries` to `SE`) |
| **Arbeitnow** | free public job-board API | Germany / Europe, many English-speaking tech jobs |
| **Remote OK**, **We Work Remotely** | public API / RSS feed (source credited, links back) | remote jobs, worldwide, many US companies |
| **Any other career page** | schema.org `JobPosting` data in the page (robots.txt respected) | e.g. join.com and most modern career sites |

Only official or public endpoints that work without a login or API key are used. No bot-check bypassing, no CAPTCHA solving, no browser-fingerprint tricks.

### What you can scrape

- **Keyword search across job boards**: any keywords + location, or a list of `countries` (e.g. `["US", "DE", "NL"]` or `"EUROPE"`) to search country by country. LinkedIn's own filters (date posted, remote / hybrid / on-site, job type, experience level, newest first) are supported, or paste LinkedIn search URLs
- **Company career sites by name**: type `airbnb`, `Hugging Face`, `bunq` or `tado` and the Actor finds the company's job board and returns all open jobs
- **Career-page URLs**: `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`, `https://jobs.lever.co/spotify`, `https://boards.greenhouse.io/airbnb`, `https://tado.jobs.personio.de`, `https://polestar.teamtailor.com`, `https://join.com/companies/join` ...

### Why this scraper

- **US + Europe in one run, one output format**: LinkedIn, national job databases, remote boards and company career sites without stitching ten scrapers together. Every job has `source` and `country`
- **Career sites are read from the platforms' own public job APIs and feeds**, so these jobs are complete and stable: full description, department, workplace type and, where the company publishes it, structured salary
- **Salary where others leave it empty**: if a posting has no salary field, explicit pay ranges in the description (e.g. "$120,000 - $150,000", "€3.600 to €5.000 per month") are parsed into `salaryMin`, `salaryMax`, `salaryCurrency` and `salaryPeriod`
- **Filters that save money**: date posted, workplace type, title keywords and location are applied before delivery, so you only pay for jobs you keep
- **Fair billing**: a job whose details cannot be loaded after a retry is delivered with its search data and `detailsMissing: true`, and is **not charged**. Companies that are not found and failed searches are free
- **No personal data**: no recruiter or poster names, profiles, e-mail addresses or phone numbers. E-mail addresses and phone numbers inside job descriptions are replaced by `[email removed]` / `[phone removed]`

### Input

| Field | Default | Description |
|---|---|---|
| `searchQueries` | – | Keywords, e.g. `data engineer`, searched on every selected source |
| `location` | – | City, region or country, e.g. `Berlin`, `United States`, `Remote` |
| `countries` | – | ISO codes, e.g. `["US", "DE", "NL"]`, or `EU` / `EUROPE`. Without `location`, LinkedIn is searched per country; `DE` / `SE` add the German / Swedish employment agency |
| `sources` | LinkedIn (+ agencies for DE/SE) | `linkedin`, `arbeitsagentur`, `jobtech`, `arbeitnow`, `remoteok`, `weworkremotely` |
| `geoId` | – | Optional LinkedIn location id (from a LinkedIn search URL) |
| `searchUrls` | – | LinkedIn job search URLs (all URL filters are kept) |
| `maxResultsPerQuery` | 50 | Jobs per keyword, per source and per country |
| `datePosted` | `any` | `24h`, `week`, `month` (all sources) |
| `workplaceTypes` | all | `remote`, `hybrid`, `onsite` (all sources) |
| `jobTypes` | all | LinkedIn: `full-time`, `part-time`, `contract`, `temporary`, `internship`, ... |
| `experienceLevels` | all | LinkedIn: `internship`, `entry`, `associate`, `mid-senior`, `director`, `executive` |
| `sortBy` | `relevance` | LinkedIn: `relevance` or `date` |
| `jobDetails` | true | Full description for LinkedIn and Bundesagentur jobs (same price) |
| `companies` | – | Company names, slugs, career-page URLs (incl. Workday) or `platform:slug` |
| `maxResultsPerCompany` | 100 | Jobs per company, newest first |
| `companyJobKeywords` | – | Only company jobs whose title contains one of these words |
| `companyJobLocation` | – | Only company jobs whose location contains this text (`London, Remote`) |
| `atsPlatforms` | all ten | Platforms to search a company name on |
| `extractSalary` | true | Parse pay ranges from the description |
| `includeDescriptionHtml` | false | Also return the original HTML |

Example (US + Europe):

```json
{
  "searchQueries": ["data engineer"],
  "countries": ["US", "DE", "NL", "SE"],
  "sources": ["linkedin", "arbeitsagentur", "jobtech", "remoteok"],
  "datePosted": "week",
  "maxResultsPerQuery": 100,
  "companies": ["airbnb", "bunq", "personio:tado", "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"],
  "companyJobKeywords": ["data"],
  "maxResultsPerCompany": 50
}
```

### Output

LinkedIn job:

```json
{
  "id": "4419969671",
  "source": "linkedin",
  "title": "Senior Software Engineer – Go (Golang)",
  "company": "General Motors",
  "companyUrl": "https://www.linkedin.com/company/general-motors",
  "location": "Warren, MI",
  "country": "US",
  "isRemote": false,
  "employmentType": "Full-time",
  "seniority": "Not Applicable",
  "industries": "Motor Vehicle Manufacturing, Appliances, Electrical, and Electronics Manufacturing, and IT Services and IT Consulting",
  "postedAt": "2026-10-25",
  "postedAgo": "1 day ago",
  "applicantsCount": 200,
  "salaryText": "$160,000 and $200,000",
  "salaryMin": 160000,
  "salaryMax": 200000,
  "salaryCurrency": "USD",
  "salaryPeriod": "year",
  "salarySource": "description",
  "description": "Job Description\n\nAs a Senior Software Engineer – Go (Golang), you will design, develop, and deliver ...",
  "jobUrl": "https://www.linkedin.com/jobs/view/4419969671/",
  "applyUrl": "https://www.linkedin.com/jobs/view/4419969671/",
  "applyType": "external",
  "closed": false,
  "input": "software engineer",
  "scrapedAt": "2026-10-26T15:12:45Z"
}
```

Career-site job (Ashby):

```json
{
  "id": "e0cca3aa-24f7-46ca-9493-9984a7ae2285",
  "source": "ashby",
  "title": "Product Operations | General Builder (All Levels)",
  "company": "Ramp",
  "location": "New York, NY (HQ); San Francisco, CA",
  "country": "US",
  "isRemote": false,
  "workplaceType": "hybrid",
  "employmentType": "Full-time",
  "department": "Product / Product Operations",
  "postedAt": "2026-10-23T19:41:17Z",
  "salaryText": "$130K - $200K",
  "salaryMin": 130000,
  "salaryMax": 200000,
  "salaryCurrency": "USD",
  "salaryPeriod": "year",
  "salarySource": "structured",
  "description": "ABOUT RAMP\n\nRamp is building the smart infrastructure for finance teams ...",
  "jobUrl": "https://jobs.ashbyhq.com/ramp/e0cca3aa-24f7-46ca-9493-9984a7ae2285",
  "applyUrl": "https://jobs.ashbyhq.com/ramp/e0cca3aa-24f7-46ca-9493-9984a7ae2285/application",
  "input": "ashby:ramp",
  "scrapedAt": "2026-10-26T15:18:10Z"
}
```

`source` is `linkedin`, `workday`, `greenhouse`, `lever`, `ashby`, `workable`, `smartrecruiters`, `recruitee`, `personio`, `teamtailor`, `bamboohr`, `breezy`, `arbeitsagentur`, `jobtech`, `arbeitnow`, `remoteok`, `weworkremotely` or `jsonld` (schema.org data from a career page). `country` is the ISO code of the job's country when the source or the location names it. Fields a source does not publish are left out (e.g. `applicantsCount` only exists on LinkedIn, `department` only on career sites). `salarySource` tells you whether the salary came from a structured field or from the description. LinkedIn's `applicantsCount` is a lower bound when LinkedIn shows "Over 200 applicants". On LinkedIn the apply button for external applications needs a login, so `applyUrl` is the LinkedIn job page and `applyType` says whether the application happens on LinkedIn or on the company site.

### Pricing (pay per event)

- **$0.0012 per job delivered**; $0.00102 on Silver, $0.00084 on Gold and above
- Same price for every source
- Not charged: companies that are not found, failed searches, and jobs delivered without details (`detailsMissing: true`)

So 1,000 jobs with full descriptions cost $1.20 on the free plan. Set the max-results fields or a maximum cost per run to cap spending.

### What this Actor does not collect

Only job postings. No recruiter or hiring-manager names, no profiles, no e-mail addresses or phone numbers (also removed from description texts), no login. Remote OK, We Work Remotely and Arbeitnow ask to be credited: every job from them carries `source` and a `jobUrl` that links back to the original listing; keep that link when you republish. Remotive is not included because its terms do not allow passing its jobs on to third-party sites. Indeed and Glassdoor are not included: they block automated requests with a bot check, and we do not bypass bot checks. Make sure your use of the data follows the sites' terms and applicable law.

### Use with AI agents (MCP)

This Actor can be used as a tool by AI agents (Claude, Cursor, VS Code, other MCP clients) through the official [Apify MCP server](https://docs.apify.com/platform/integrations/mcp):

- Add only this Actor as a tool: `https://mcp.apify.com?tools=admirala/jobs-scraper` (sign in with OAuth or an Apify API token).
- Or connect `https://mcp.apify.com` and let the agent find it with `search-actors` (e.g. "linkedin jobs workday greenhouse scraper"), read the input schema with `fetch-actor-details` and run it with `call-actor`.

Example input an agent can pass:

```json
{
  "searchQueries": ["machine learning engineer"],
  "location": "London",
  "datePosted": "week",
  "workplaceTypes": ["remote", "hybrid"],
  "maxResultsPerQuery": 25
}
```

Cost per call: $0.0012 per job returned. Results come back as dataset items (`get-dataset-items`).

### FAQ

**Do I need a LinkedIn account or cookies?**
No. The Actor only uses the public job pages LinkedIn shows to visitors who are not logged in.

**How do I get all jobs of one company?**
Put the company in `companies`, e.g. `airbnb`, and set `maxResultsPerCompany` high enough. If the company has boards on two platforms the one with most jobs is used and the log names the other; force one with `greenhouse:airbnb`, `lever:spotify`, `ashby:ramp`, `workable:huggingface`, `smartrecruiters:BoschGroup`, `recruitee:bunq`, `personio:tado`, `teamtailor:polestar`, `bamboohr:<subdomain>` or `breezy:<subdomain>`, or paste the career-page URL.

**Which companies are supported?**
Every company that publishes its jobs on Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio, Teamtailor, BambooHR or Breezy HR (found by name), every Workday career site (paste the `myworkdayjobs.com` URL; Workday site names cannot be guessed from a company name) and every career page that embeds schema.org `JobPosting` data (paste the URL). Other companies: use the keyword search.

**Which countries are covered?**
LinkedIn covers the US and every European country; set `countries` (e.g. `["US", "FR", "PL"]`, `EU` or `EUROPE`) to search each one. Germany and Sweden additionally get their national employment-agency databases (`DE`, `SE`). Career sites and remote boards are global.

**Why no USAJOBS, Adzuna, Indeed or Glassdoor?**
USAJOBS and Adzuna require a personal API key; they are not included yet. Indeed and Glassdoor put automated visitors behind a bot check, and we do not bypass bot checks.

**How do I get only remote jobs?**
Set `workplaceTypes` to `["remote"]`. For LinkedIn this uses LinkedIn's own remote filter; for the other sources it uses the workplace type the posting sets (or "remote" in the location). Or select the `remoteok` and `weworkremotely` sources.

**How do I get only new jobs every day?**
Set `datePosted` to `24h` and schedule the Actor daily. Each job has a stable `id` per `source` for de-duplication.

**Why is the salary empty for some jobs?**
Many postings do not publish pay. The Actor only fills salary fields from a structured salary field or an explicit range with a currency in the description; it never guesses.

### Related actors

- [Tech Stack Detector - BuiltWith & Wappalyzer Alternative](https://apify.com/admirala/website-tech-stack-detector)
- [Google News Scraper + GDELT - News Search, No Start Fee](https://apify.com/admirala/news-search-google-gdelt)
- [YouTube Scraper - Channels, Videos, Search, Shorts & Transcript](https://apify.com/admirala/youtube-scraper)

### More examples

Ready-to-run Python, curl and MCP examples with real sample output: https://github.com/AdmiraalA/apify-scrapers-examples

# Actor input Schema

## `searchQueries` (type: `array`):

Job titles or keywords, one per line, e.g. \["data engineer", "product manager"]. Each keyword is searched on every selected source (see 'Job sources') and returns up to 'Max jobs per search' listings per source and country.

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

City, region or country, e.g. 'Berlin', 'London, England', 'United States', 'Remote'. Used for LinkedIn and the job boards. Leave empty and use 'Countries' to search country by country, or leave both empty for worldwide.

## `countries` (type: `array`):

Optional ISO country codes, e.g. \["US", "DE", "NL", "GB"], or 'EU' (27 EU countries) / 'EUROPE' (EU + UK, Switzerland, Norway, Iceland, Liechtenstein). If 'Location' is empty, LinkedIn is searched once per country. 'DE' also searches the German Federal Employment Agency (Bundesagentur für Arbeit) and 'SE' the Swedish Public Employment Service (Arbetsförmedlingen), if those sources are selected.

## `sources` (type: `array`):

Where to search the keywords. Empty = LinkedIn, plus Bundesagentur für Arbeit / Arbetsförmedlingen when 'Countries' contains DE / SE. Remote OK, We Work Remotely and Arbeitnow are only searched when selected here (their feeds hold their newest jobs; keywords are matched on title and tags).

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

Optional LinkedIn location id (the 'geoId' value in a LinkedIn job search URL), e.g. 103644278 for the United States. Overrides LinkedIn's interpretation of 'Location'.

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

Optional: paste LinkedIn job search URLs (linkedin.com/jobs/search/?keywords=...\&location=...\&f_TPR=...). All filters in the URL are kept.

## `maxResultsPerQuery` (type: `integer`):

Maximum jobs per keyword, per source and per country (LinkedIn shows at most ~1000 per search). You pay per job, so this caps the cost.

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

Only jobs posted within this period. Applies to all sources.

## `workplaceTypes` (type: `array`):

Only these workplace types (empty = all). Applies to all sources.

## `jobTypes` (type: `array`):

LinkedIn job type filter (empty = all).

## `experienceLevels` (type: `array`):

LinkedIn experience level filter (empty = all).

## `sortBy` (type: `string`):

Order of LinkedIn search results.

## `jobDetails` (type: `boolean`):

true = open every LinkedIn and Bundesagentur für Arbeit job for the full description (LinkedIn also: seniority, employment type, industries, applicant count, salary; same price). false = only the search-result data, faster.

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

Company names, career-board slugs or career-page URLs. A name is looked up on Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio, Teamtailor, BambooHR and Breezy HR and all open jobs are returned. Workday: paste the career-site URL (e.g. 'https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite'). Any other career-page URL is read for schema.org JobPosting data (robots.txt respected). Examples: 'airbnb', 'Hugging Face', 'https://jobs.lever.co/spotify', 'personio:tado', 'recruitee:bunq'. Use 'platform:slug' to force one platform.

## `maxResultsPerCompany` (type: `integer`):

Maximum jobs per company (newest first).

## `companyJobKeywords` (type: `array`):

Only company jobs whose title contains one of these words, e.g. \["engineer", "data"]. Empty = all jobs. On Workday these words are also used as the site search.

## `companyJobLocation` (type: `string`):

Only company jobs whose location contains this text; comma-separated for several, e.g. 'London, Remote'. Empty = all locations.

## `atsPlatforms` (type: `array`):

Platforms to look up a company name on (empty = all ten). Workday and other URLs are always detected from the URL.

## `extractSalary` (type: `boolean`):

If the posting has no structured salary, read an explicit pay range (e.g. '$120,000 - $150,000') from the description into salaryMin / salaryMax / salaryCurrency / salaryPeriod.

## `includeDescriptionHtml` (type: `boolean`):

Also return the original description HTML (descriptionHtml). The plain-text description is always included.

## `allowResidentialProxy` (type: `boolean`):

If LinkedIn blocks the direct and datacenter routes, retry through Apify residential proxy. Included in the price. All other sources are always requested directly.

## Actor input object example

```json
{
  "searchQueries": [
    "python developer"
  ],
  "location": "United States",
  "maxResultsPerQuery": 10,
  "datePosted": "any",
  "sortBy": "relevance",
  "jobDetails": true,
  "companies": [
    "airbnb",
    "spotify",
    "bunq"
  ],
  "maxResultsPerCompany": 10,
  "extractSalary": true,
  "includeDescriptionHtml": false,
  "allowResidentialProxy": true
}
```

# 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 = {
    "searchQueries": [
        "python developer"
    ],
    "location": "United States",
    "maxResultsPerQuery": 10,
    "companies": [
        "airbnb",
        "spotify",
        "bunq"
    ],
    "maxResultsPerCompany": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("admirala/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 = {
    "searchQueries": ["python developer"],
    "location": "United States",
    "maxResultsPerQuery": 10,
    "companies": [
        "airbnb",
        "spotify",
        "bunq",
    ],
    "maxResultsPerCompany": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("admirala/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 '{
  "searchQueries": [
    "python developer"
  ],
  "location": "United States",
  "maxResultsPerQuery": 10,
  "companies": [
    "airbnb",
    "spotify",
    "bunq"
  ],
  "maxResultsPerCompany": 10
}' |
apify call admirala/jobs-scraper --silent --output-dataset

```

## MCP server setup

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