# Career Site Jobs Scraper: Teamtailor, Greenhouse, Lever (`vindr/eu-career-site-jobs`) Actor

Get open jobs from company career pages in one clean format. Use your own company list or search our directory of over 10,000 companies, 2,100 in the Nordics. Works with Teamtailor, Greenhouse, Lever, Ashby, Recruitee, Personio, Varbi, ReachMee, HR-manager and EasyCruit. $5 per 1,000 jobs.

- **URL**: https://apify.com/vindr/eu-career-site-jobs.md
- **Developed by:** [VindR](https://apify.com/vindr) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 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.

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

### What does Career Site Jobs Scraper do?

Career Site Jobs Scraper collects job postings directly from company career pages and returns every open position in the same clean format, no matter which recruiting system the company uses behind the scenes.

You can use it in two ways:

- **Give it your own list of companies.** Paste career page URLs and get all their open jobs.
- **Search the built-in company directory.** No list needed. The directory covers over 10,000 companies, about 9,300 of them with open jobs right now, including about 2,000 hiring in the Nordics. Pick a country and a few keywords, for example "all developer jobs in the Nordics", and the scraper does the rest.

It supports ten applicant tracking systems (ATS): **Teamtailor, Greenhouse, Lever, Ashby, Recruitee and Personio**, plus **Varbi, ReachMee, HR-manager and EasyCruit**, which are used by universities, municipalities, regions and other public employers in Sweden, Norway and Denmark. Teamtailor is the most common ATS in the Nordics, and Recruitee and Personio are everywhere in the Netherlands and Germany, so this scraper is a good fit if you need European job data that the big US job boards don't cover well.

The data comes from the public job feeds these systems publish for career sites. That means no browser, no login and no guesswork, which keeps runs quick and cheap. A company with a few hundred open positions usually takes a couple of seconds.

### Which career sites are supported?

| ATS | What to paste in the input |
|---|---|
| Teamtailor | `https://careers.voi.com` or `https://voi.teamtailor.com` |
| Greenhouse | `https://boards.greenhouse.io/stripe` |
| Lever | `https://jobs.lever.co/spotify` (EU accounts work too) |
| Ashby | `https://jobs.ashbyhq.com/notion` |
| Recruitee | `https://bunq.recruitee.com` |
| Personio | `https://yourcompany.jobs.personio.de` |
| Varbi | `https://ki.varbi.com` |
| ReachMee | The career page, like `https://www.oru.se/om-universitetet/jobba-hos-oss/lediga-jobb/`, or the RSS feed link from it |
| HR-manager | `hrmanager:kreftforeningen` |
| EasyCruit | `https://molde.easycruit.com` |

You can also use short forms like `greenhouse:stripe` or `lever:spotify`.

Many companies host their career page on their own domain, like `careers.company.com`. Just paste that URL. The scraper looks at the page and works out which system it runs on.

### How does the company directory work?

Turn on **Search the company directory** and the scraper looks at every company in the directory that matches your filters. You don't need to know who is hiring.

- **Countries** picks the region. `NORDICS`, `EU`, or any country code like `NO`, `SE` or `DE`.
- **Only these job board systems** narrows it to, say, Teamtailor or Varbi.
- **Company name contains** finds companies by name, for example "bank" or "kommun".
- **Max companies from the directory** caps how many companies are checked. The busiest employers come first.

Your normal filters (keywords, workplace type, posted within and so on) then decide which jobs you get.

The directory is built from public data: the Common Crawl web archive, the open job ads from the Swedish Public Employment Service (Arbetsförmedlingen), and the official municipality lists of Norway, Denmark and Sweden. Every company is checked against its live job board when the directory is built, and it's refreshed regularly. You can combine the directory with your own list in the same run.

Directory runs check many companies, so they take longer than a run with a short list. A country or a keyword usually takes a few minutes. A large region like the whole EU with no other filters can take 15 to 20 minutes. Use **Max jobs in total** or **Max companies from the directory** to keep runs short. You only pay for the jobs you get.

### What data do you get?

Every job has the same fields, whichever ATS it came from:

| Field | Example |
|---|---|
| Job title | Senior Platform Engineer |
| Company | Voi Technology |
| Department and team | Engineering, Platform |
| Location | Stockholm, Sweden |
| Country codes | `["SE"]` |
| Workplace type | remote, hybrid or onsite |
| Employment type | Full-time, Permanent |
| Salary | min, max, currency and period, when the company publishes it |
| Posted date | 2026-09-18 |
| Application deadline | 2026-10-21, when the posting has one |
| Job page and apply link | https://careers.voi.com/jobs/... |
| Description | full text, as HTML and as plain text |

Locations are free text on most career sites ("Stockholm", "Remote in Germany", "London, UK"). The scraper turns them into ISO country codes, so you can filter by country and trust the result.

### How to scrape jobs from career sites

1. Click **Try for free** at the top of this page.
2. Paste one or more career site URLs into **Company career sites**, or turn on **Search the company directory**.
3. Add filters if you want them, for example keywords, countries or remote only.
4. Click **Start** and wait a few seconds.
5. Download the jobs as Excel, CSV, JSON or HTML, or pull them into your own app through the API.

You can save your settings as a task and schedule it to run every morning. Combined with the "posted within" filter, that gives you a simple job alert.

### Input examples

The simplest input is just a list of companies:

```json
{
    "companies": [
        "https://careers.voi.com",
        "https://jobs.lever.co/spotify",
        "https://boards.greenhouse.io/stripe"
    ]
}
```

Engineering jobs in the Nordics and Germany, remote or hybrid, posted in the last 30 days:

```json
{
    "companies": ["https://careers.voi.com", "https://jobs.lever.co/spotify"],
    "keywords": ["engineer", "developer"],
    "countries": ["NORDICS", "DE"],
    "workplaceTypes": ["remote", "hybrid"],
    "postedWithinDays": 30
}
```

All developer jobs in the Nordics from the company directory, no company list needed:

```json
{
    "useDirectory": true,
    "countries": ["NORDICS"],
    "keywords": ["developer", "utvecklare", "utvikler", "engineer"]
}
```

A daily alert that only returns new jobs:

```json
{
    "companies": ["https://jobs.ashbyhq.com/notion"],
    "postedWithinDays": 1,
    "includeDescription": false
}
```

For countries you can use any ISO code (`NO`, `SE`, `DK`, `DE`, `GB` and so on) or the shortcuts `EU` (EU and EEA) and `NORDICS`.

### Output example

Here is one job as it appears in the dataset:

```json
{
    "id": "lever:spotify:2193db3f-77c5-43b8-b030-8f92c9882bf1",
    "ats": "lever",
    "companySlug": "spotify",
    "companyName": "Spotify",
    "jobId": "2193db3f-77c5-43b8-b030-8f92c9882bf1",
    "title": "Android Engineer - Experience",
    "department": "Engineering",
    "team": "Experience",
    "employmentType": "Permanent",
    "workplaceType": "hybrid",
    "location": "London | Stockholm",
    "locations": [
        { "city": "London", "region": null, "country": null, "countryCode": "GB" }
    ],
    "countryCodes": ["GB", "SE"],
    "salary": null,
    "postedAt": "2026-06-23T11:29:45.805Z",
    "updatedAt": null,
    "applicationDeadline": null,
    "url": "https://jobs.lever.co/spotify/2193db3f-77c5-43b8-b030-8f92c9882bf1",
    "applyUrl": "https://jobs.lever.co/spotify/2193db3f-77c5-43b8-b030-8f92c9882bf1/apply",
    "descriptionHtml": "<div><p>We design Spotify's consumer experience...</p></div>",
    "descriptionText": "We design Spotify's consumer experience...",
    "scrapedAt": "2026-09-23T18:30:00.000Z"
}
```

After each run you'll also find a `RUN_SUMMARY` record in the key-value store. It lists every company you asked for, how many jobs were found and saved, and whether anything went wrong (for example a company that no longer has a job board).

### How much does it cost to scrape career sites?

You pay **$5 per 1,000 jobs** saved. That's it. Server time is included in the price, and jobs removed by your filters are not charged.

A few examples:

- One company with 200 open jobs costs about $1.
- 50 companies with 5,000 jobs in total cost about $25.
- The $5 in free monthly credit on the Apify free plan covers about 1,000 jobs a month.

If you want to be sure a run never goes over budget, set **Max jobs in total**, or set a maximum cost when you start the run.

### What can you use it for?

- **Job boards and newsletters.** Build a niche board, like Nordic tech jobs or remote roles in Europe, using data straight from the source.
- **Recruiting and sales.** See which companies are hiring, for which roles and in which countries. A company that suddenly opens ten sales positions is worth a call.
- **Market research.** Track hiring trends by country, department or workplace type over time.
- **Job alerts.** Run it on a schedule and send new jobs to Slack, email or Google Sheets through Apify integrations.
- **Public sector jobs.** Collect openings from Swedish universities, regions and municipalities on Varbi and ReachMee, Norwegian and Danish municipalities on EasyCruit, or organisations on HR-manager, including the application deadline.

### FAQ

#### Is it legal to scrape job postings?

Job postings are published so people can find them, and the systems supported here offer public feeds meant for showing jobs on career sites and job boards. The scraper only reads those public feeds, never logs in and keeps its request rate low. You are still responsible for how you use the data. If you republish jobs, link back to the original posting. If you are unsure about your use case, talk to a lawyer.

#### Does the output contain personal data?

By default, email addresses and phone numbers are removed from job descriptions, and recruiter inboxes are never copied. Public sector systems often list contact persons and union representatives next to the job. Those are never collected. What's left is information about the job and the employer. You can turn the removal off with **Remove contact details**, but we recommend leaving it on.

#### Why does my company show up as "unrecognized"?

Either the career page runs on a system that isn't supported yet, or it loads jobs in a way the scraper can't detect. Try the direct link to the job board instead (for example `https://jobs.lever.co/company`). If it still doesn't work, open an issue with the URL and we'll take a look.

#### Why are some jobs missing when I filter by country?

When you use the country filter, jobs without a clear location (like "Anywhere") are left out, so you only get jobs you can be sure about. Run without the filter if you want everything.

#### Can I get all jobs from every company that uses Teamtailor?

Yes, as far as the directory reaches. Turn on **Search the company directory** and choose Teamtailor under **Only these job board systems**. The directory doesn't know every company in the world, so if one you care about is missing, add it to **Company career sites** in the same run and tell us on the Issues tab.

#### How fresh is the directory?

Jobs are always fetched live when you run the scraper, so closed postings are gone and new ones show up right away. The directory is only the list of companies to look at, and it's rebuilt regularly. It also includes companies that had no open jobs when we last checked, so their new postings are picked up too. Companies that stop using a supported system simply return no jobs, and you aren't charged for them.

#### Can I use it from my own code?

Yes. Every Apify Actor has an API, and you can call it from Python, JavaScript or plain HTTP. See the **API** tab for ready-made code. It also works with Make, n8n, Zapier and Google Sheets.

#### Can you add another ATS?

Probably. Workday, SmartRecruiters and Webcruiter are next on the list. Open an issue and tell us which one you need. Requests from users decide what gets built first.

### Feedback

Found a bug or missing a field? Open an issue on the **Issues** tab and we'll look into it. Suggestions for new features and ATS platforms are welcome too.

# Actor input Schema

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

Career pages you want jobs from, one per line. Links to the job board itself work (<code>https://jobs.lever.co/spotify</code>, <code>https://ki.varbi.com</code>), and so do career pages on a company's own domain (<code>https://careers.voi.com</code>). You can also write <code>greenhouse:stripe</code>, <code>varbi:su</code>, <code>hrmanager:kreftforeningen</code>, <code>easycruit:molde</code> and so on. Leave empty if you only want to use the company directory below.

## `useDirectory` (type: `boolean`):

Also look for jobs at thousands of companies in our built-in directory, so you don't need your own company list. Use the Countries filter to pick a region, for example <code>NORDICS</code>. The directory is refreshed regularly from public data.

## `directoryPlatforms` (type: `array`):

Limit the directory to some systems. Leave empty to use all of them.

## `companyNameContains` (type: `array`):

Only use directory companies whose name contains one of these, for example "bank" or "health".

## `maxCompanies` (type: `integer`):

Check at most this many directory companies, starting with the ones that have the most open jobs. Use 0 for no limit.

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

Only keep jobs with at least one of these words in the title. Not case sensitive. Leave empty to get all jobs.

## `searchInDescription` (type: `boolean`):

Off by default, so keywords are only matched against the job title.

## `excludeKeywords` (type: `array`):

Skip jobs with any of these words in the title, for example "intern" or "senior".

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

Country codes to keep, like NO, SE, DE or GB. Use <code>EU</code> for all EU and EEA countries, or <code>NORDICS</code> for Norway, Sweden, Denmark, Finland and Iceland. Jobs without a clear country are skipped when you use this filter.

## `locationContains` (type: `array`):

Only keep jobs where the location mentions one of these, for example "Oslo" or "Berlin".

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

Only keep remote, hybrid or on-site jobs. Leave empty to keep all of them.

## `departments` (type: `array`):

Only keep jobs where the department or team contains one of these, for example "engineering" or "sales".

## `postedWithinDays` (type: `integer`):

Only keep jobs posted in the last N days. Use 0 for no limit.

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

Use 0 for no limit.

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

The run stops after saving this many jobs. Use 0 for no limit.

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

Includes the full job description as HTML and plain text. Turn it off if you only need the basics and want smaller files.

## `redactContactDetails` (type: `boolean`):

Removes email addresses and phone numbers from job descriptions, so you don't end up storing personal contact data. We recommend leaving this on.

## `maxConcurrency` (type: `integer`):

How many companies to fetch at the same time. Each site is still rate limited, so raising this mostly helps with long lists.

## Actor input object example

```json
{
  "companies": [
    "https://careers.voi.com",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/notion"
  ],
  "useDirectory": false,
  "maxCompanies": 0,
  "searchInDescription": false,
  "postedWithinDays": 0,
  "maxJobsPerCompany": 0,
  "maxJobs": 0,
  "includeDescription": true,
  "redactContactDetails": true,
  "maxConcurrency": 16
}
```

# Actor output Schema

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

All jobs saved in this run, one item per job.

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

Per-company status: how many jobs were found and saved, and any companies that could not be read.

# 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://careers.voi.com",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/notion"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("vindr/eu-career-site-jobs").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://careers.voi.com",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/notion",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("vindr/eu-career-site-jobs").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 '{
  "companies": [
    "https://careers.voi.com",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/notion"
  ]
}' |
apify call vindr/eu-career-site-jobs --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vindr/eu-career-site-jobs"
        }
    }
}
```

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/zQsPe7fU2YU09bTWI/builds/xxkw8TDuMA5nO1PY7/openapi.json
