# Europe Jobs Scraper — EURES, EURAXESS + 12 More Boards (`nomad-agent/europe-jobs-bundle`) Actor

All Europe-focused job sources behind one endpoint: LinkedIn Europe, AI Jobs, EURES, EURAXESS, AcademicPositions, WTTJ, JustJoin.it, NoFluffJobs, InfoJobs, Tecnoempleo, jobs.ac.uk and university boards. One merged, deduped dataset.

- **URL**: https://apify.com/nomad-agent/europe-jobs-bundle.md
- **Developed by:** [Nomad.Dev](https://apify.com/nomad-agent) (community)
- **Categories:** Jobs
- **Stats:** 7 total users, 1 monthly users, 83.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 job 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

## Europe Jobs Scraper - 14 Sources in One

> **Claude / Codex skill to describe and setup this actor: [SKILL.md](https://github.com/Exdenta/OinkAIJobSearch/blob/main/skill/europe-jobs-bundle/SKILL.md)**

One call for Europe-focused job data. This bundle fans out to 14 existing job-source Actors, merges their results, dedupes by URL, and returns one flat dataset of live European job postings.

This is an unofficial scraper bundle. It is not affiliated with LinkedIn, EURES, EURAXESS, AcademicPositions, Welcome to the Jungle, JustJoin.it, NoFluffJobs, InfoJobs, Tecnoempleo, jobs.ac.uk, Ikerbasque, the University of Copenhagen, Universitat de Barcelona, or AI Jobs.

### Sources included

| Source key | Coverage |
|---|---|
| `linkedin` | LinkedIn jobs, default location: European Union |
| `ai_jobs_net` | AI, ML and data jobs with Europe bias enabled |
| `eures` | EU job mobility portal |
| `euraxess` | EU research jobs |
| `academicpositions` | EU, UK and Switzerland academic jobs |
| `wttj` | Welcome to the Jungle jobs across EU countries |
| `justjoinit` | Polish tech and IT jobs |
| `nofluffjobs` | Poland and CEE IT jobs with salary data |
| `infojobs` | Spain job board |
| `tecnoempleo` | Spain IT jobs |
| `jobs_ac_uk` | UK academic, postdoc and research jobs |
| `ikerbasque` | Basque research jobs in Spain |
| `math_ku_phd` | University of Copenhagen PhD and research jobs |
| `ub_doctoral` | Universitat de Barcelona doctoral vacancies, BYOK AI extraction |

Company ATS Actors like Greenhouse, Lever, Ashby and Workable are not included because they require buyer-supplied company lists. Global sources with no reliable Europe filter are also left out so the default run stays aligned with the Europe promise.

### How the bundle works

This is a bundle Actor. For each selected source it calls the matching child Actor, maps every child record onto one shared schema, dedupes by URL, and pushes the merged output. Each source fails open independently: if one board errors or times out, the other sources still return.

Use `sources` to run a cheaper subset, `keyword` to filter sources that support free-text search, and `location` to override the default `European Union` text for LinkedIn and AI Jobs.

### Incremental mode

Turn on `incrementalMode` for scheduled alerts. The bundle remembers listing URLs it has already delivered in a key-value store on your own Apify account. Later runs skip those already-seen postings and do not charge this bundle's per-result event for them.

### Input example

```json
{
  "keyword": "data engineer",
  "location": "European Union",
  "maxItemsPerSource": 10,
  "maxItems": 50
}
```

UB doctoral is the only BYOK source. Without `anthropicApiKey` or `mistralApiKey`, it is skipped and the dataset includes one uncharged warning row explaining why. The other 13 sources run normally.

### Output fields

Each normal row uses the same flat bundle schema:

```json
{
  "source": "eures",
  "id": "123456",
  "title": "Software Engineer",
  "company": "Example GmbH",
  "location": "Berlin, Germany",
  "url": "https://example.com/job/123456",
  "postedAt": "2026-07-07",
  "deadline": "",
  "snippet": "Short posting excerpt...",
  "salary": "",
  "hiringContactName": null,
  "hiringContactTitle": null,
  "hiringContactUrl": null
}
```

On `linkedin` rows the bundle also returns `hiringContactName`, `hiringContactTitle` and `hiringContactUrl` — the person LinkedIn names as the job poster, i.e. who to write to. LinkedIn names someone on roughly a quarter of postings; the fields are `null` on the rest and on every other source. They cost no extra requests and nothing is guessed.

Fields a source does not provide are returned as empty strings rather than guessed.

### Python client

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("nomad-agent/europe-jobs-bundle").call(run_input={
    "keyword": "engineer",
    "maxItems": 50,
})

items = client.dataset(run["defaultDatasetId"]).list_items().items
print(len(items), items[:1])
```

### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/nomad-agent~europe-jobs-bundle/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"keyword":"engineer","maxItems":50}'
```

### Cost note

Children are pay-per-event Actors. A bundle run charges this bundle's start/result events on top of each enabled child Actor's own start/result events. Use `sources`, `maxItemsPerSource` and `maxItems` to control spend.

### Related Actors

Need just one board, with deeper filters and cheaper per-result pricing? Each source is also a standalone Actor:

- [InfoJobs Scraper — Ofertas de Trabajo y Empleo España](https://apify.com/nomad-agent/infojobs-scraper) — AI skill tags, structured salary, delta mode
- [Tecnoempleo Scraper — Spain IT & Tech Jobs](https://apify.com/nomad-agent/tecnoempleo-scraper)
- [EURES Job Scraper — EU Job Mobility Portal](https://apify.com/nomad-agent/eures-scraper)
- [EURAXESS Research Jobs Scraper](https://apify.com/nomad-agent/euraxess-scraper)

***

**From the maker of [Oink](https://github.com/Exdenta/OinkAIJobSearch)** — an open-source, AI-powered job-search bot for Telegram that runs on these Actors. [Try the free bot](https://t.me/job_search_everyday_bot), get a managed instance at [oinkjobsearch.com](https://oinkjobsearch.com), or browse the [full catalog of 50+ Actors](https://apify.com/nomad-agent).

# Actor input Schema

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

Which boards to include. Leave empty to run the default set (all 13 boards that run inside this Actor — one flat bill, no extra fees). 'AcademicPositions' is the one exception: it needs a real browser to clear Cloudflare, so it runs as a separate child Actor and adds that Actor's own start + per-result fees on top of this bundle's. It is off by default; tick it only if you want it. 'UB doctoral' additionally needs the Anthropic, Mistral or OpenAI API key below (any one); without one it is skipped, you are not charged for it, and a warning row explaining why is added to the results.

## `keyword` (type: `string`):

Optional free-text filter forwarded to children that support it (others ignore it).

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

Location text forwarded to children that support location filtering. LinkedIn always receives it; AI Jobs receives it only when you set a real place (its location field is a substring filter, so the default 'European Union' would match nothing there — its EU focus comes from ranking EU listings first instead). Regional sources are already Europe-scoped.

## `incrementalMode` (type: `boolean`):

Return only postings this bundle has NOT already delivered on a previous run. The bundle remembers every listing URL it returned (in a private key-value store on your own Apify account) and, on later runs, skips — and does not re-charge its per-result fee for — anything you already received. The first run always returns everything; leave this off for a full snapshot each run, turn it on for a scheduled (e.g. daily/weekly) job that should surface only fresh postings.

## `anthropicApiKey` (type: `string`):

Required (together with mistralApiKey / openaiApiKey below — any one is enough) only by 'UB doctoral' — it reads listings that sit behind extra rendering and uses an AI provider to extract them. Without any key that source is skipped (you are not charged for it) and a warning row is added to the output explaining why; the other 13 sources run normally either way. Usage is billed separately by Anthropic, not by this Actor.

## `mistralApiKey` (type: `string`):

Alternative to anthropicApiKey/openaiApiKey for 'UB doctoral' — pass this instead if you'd rather bring a Mistral key than an Anthropic or OpenAI one (any one key is enough; Mistral is preferred when more than one is set). Without any key that source is skipped and a warning row is added explaining why. Usage is billed separately by Mistral, not by this Actor.

## `mistralModel` (type: `string`):

Mistral model forwarded to 'UB doctoral' when it runs on mistralApiKey (no anthropicApiKey supplied). Small is the default — matches larger Mistral models on this task at a fraction of the cost.

## `openaiApiKey` (type: `string`):

Alternative to anthropicApiKey/mistralApiKey for 'UB doctoral' — pass this instead if you'd rather bring an OpenAI key than an Anthropic or Mistral one (Mistral, then Anthropic, are preferred when more than one key is set). Without any key that source is skipped and a warning row is added explaining why. Usage is billed separately by OpenAI, not by this Actor.

## `openaiModel` (type: `string`):

OpenAI model forwarded to 'UB doctoral' when it runs on openaiApiKey. Defaults to gpt-4.1-mini — cheap and fast for this task. Any chat-completions model works, including the gpt-5 family.

## `maxItemsPerSource` (type: `integer`):

Cap on items fetched from EACH board before merging. Raise it for a deeper sweep of every board; the merged total is still bounded by 'Max items (total)' below.

## `maxItems` (type: `integer`):

Hard cap on the merged, deduped output — and therefore on what you pay, since this Actor charges per unique job returned. Default (504) is sources × 'Max items per source'. Set 0 to remove the cap; cost then scales with every board's raw output.

## `cacheTtlSeconds` (type: `integer`):

How long to reuse results already fetched from a source instead of fetching again. Set 0 to always fetch fresh data.

## `concurrency` (type: `integer`):

How many boards to fetch at the same time. The default fetches them all at once, so a run takes as long as the slowest board rather than the sum.

## `runTimeoutSecs` (type: `integer`):

How long to wait for each board before giving up on it and merging what the others returned. Boards run in parallel, so this is a per-board ceiling, not a budget shared across them.

## `apifyToken` (type: `string`):

Leave empty — injected automatically when this Actor runs on the Apify platform. Only set this when running the code outside the platform, e.g. on your own machine.

## `actorOwner` (type: `string`):

Only used to address the 'AcademicPositions' child Actor. Leave empty to use the published one — set it only if you run your own fork under a different Apify account.

## Actor input object example

```json
{
  "sources": [
    "linkedin",
    "ai_jobs_net",
    "eures",
    "euraxess",
    "wttj",
    "justjoinit",
    "nofluffjobs",
    "infojobs",
    "tecnoempleo",
    "jobs_ac_uk",
    "ikerbasque",
    "math_ku_phd",
    "ub_doctoral"
  ],
  "location": "European Union",
  "incrementalMode": false,
  "mistralModel": "mistral-small-latest",
  "openaiModel": "gpt-4.1-mini",
  "maxItemsPerSource": 36,
  "maxItems": 504,
  "cacheTtlSeconds": 1800,
  "concurrency": 14,
  "runTimeoutSecs": 300,
  "actorOwner": ""
}
```

# Actor output Schema

## `dataset` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("nomad-agent/europe-jobs-bundle").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("nomad-agent/europe-jobs-bundle").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 '{}' |
apify call nomad-agent/europe-jobs-bundle --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=nomad-agent/europe-jobs-bundle",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

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