# EURAXESS Jobs Scraper (`automation-lab/euraxess-research-jobs-scraper`) Actor

Extract public EURAXESS jobs listing cards with institutions, locations, disciplines, researcher stages, dates, deadlines and stable source links for academic recruitment snapshots. Listing-only; no detail enrichment.

- **URL**: https://apify.com/automation-lab/euraxess-research-jobs-scraper.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.44 / 1,000 item extracteds

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

## EURAXESS Jobs Scraper

Turn public **EURAXESS jobs** search cards into structured recruitment snapshots.
Collect research vacancies with stable job IDs, institutions, countries, work locations,
research fields, researcher stages, posting dates, deadlines and source links.
This is a **listing-only** scraper: it does not visit job detail pages or promise complete descriptions.

### What does it do?

Supply one or more EURAXESS Jobs search URLs, optionally filtered on the source website.
The Actor follows listing pagination and writes one dataset row per unique job ID.
Use the default search for a recent broad snapshot or copy a filtered search for a focused feed.

The listing excerpt is included as `descriptionSnippet`, not as a full job description.
Funding and hosting opportunities are outside this Actor's scope.

### Who is it for?

- Research recruiters building academic vacancy feeds.
- University career services maintaining discipline-specific opportunity sheets.
- PhD and postdoctoral job researchers tracking published recruitment deadlines.
- Analysts taking repeatable snapshots of the public research hiring market.

### Why use this Actor?

A listing-only workflow avoids unnecessary detail requests and produces consistent card-level records.
Stable EURAXESS IDs make joins and downstream comparisons straightforward.
Original deadline text is retained alongside the source datetime so timezone information is not lost.
Filters remain attached during pagination, and duplicate IDs across supplied searches are removed within each run.

It does not store a cross-run history or send change alerts. Schedule separate runs and compare their outputs yourself.
A missing optional field stays null or an empty array; it is not invented from another source.

### Getting started

1. Open [EURAXESS Jobs search](https://euraxess.ec.europa.eu/jobs/search).
2. Select Jobs and apply any desired country, research-field or researcher-profile filters.
3. Copy the resulting search URL into `searchUrls`, or leave the default broad Jobs search.
4. Choose a global `maxItems` and `maxPages` cap.
5. Start the Actor and inspect its Research jobs dataset view.
6. Export through Apify as JSON, CSV or Excel, or connect the dataset to your own pipeline.

Programmatic default input (the Console prefill uses conservative 20-job/20-page caps):

```json
{
  "searchUrls": ["https://euraxess.ec.europa.eu/jobs/search"],
  "maxItems": 100,
  "maxPages": 100
}
```

### Filtering EURAXESS jobs

Use source-generated URLs rather than guessing query parameters.
For example, a keyword facet can look like:

```json
{
  "searchUrls": ["https://euraxess.ec.europa.eu/jobs/search?f%5B0%5D=keywords%3Aphysics"],
  "maxItems": 25,
  "maxPages": 10
}
```

The source controls keyword matching, stemming, searchable fields and multiple-filter semantics.
This Actor does not implement a local exact-phrase, whole-word or title-only filter.
A result may be relevant through source-indexed content that is not visible in its listing excerpt.
Plain `?keywords=physics` is rejected because that parameter does not apply the listing keyword filter.

Supported facet families are keywords, offer type, country, research field, researcher profile,
organisation type, positions and EU funding programme. Only the job-offer type is accepted.
Unsupported parameters, off-domain URLs, detail URLs and mixed funding/hosting searches fail validation.
A jobs-only facet is added when absent. No login, cookies or proxy input is required.
Requests use the Actor owner's Apify residential proxy in France; its cost is included in Actor pricing, not a separate key or off-platform charge.

### Input reference

| Field | Default | Meaning |
| --- | --- | --- |
| `searchUrls` | Broad EURAXESS Jobs search | 1–10 URL strings, processed in order; source filters apply during pagination |
| `maxItems` | 100 | 1–1000 unique job rows globally, after excluding non-job cards and duplicate IDs |
| `maxPages` | 100 | 1–100 unique listing pages globally across all searches |

Zero and unlimited limits are unsupported. A source page usually contains about ten cards.
Collection stops at the first applicable limit, source exhaustion or platform runtime/billing limit.
A low page cap can yield fewer than `maxItems`. Later search URLs may not be reached when an earlier search uses the global caps.
The input page parameter, if supplied, is zero-based and defines the starting page for that URL.

### Output fields

| Field | Meaning |
| --- | --- |
| `jobId` | Stable EURAXESS job ID as a string |
| `title` | Listing title |
| `institution` | Organisation named in card metadata, or null |
| `country` | Card country label, or null |
| `workLocations` | Original location block, possibly including offer counts and postal details; not a normalized address |
| `researchFields` | Unique labels from the research-field hierarchy; empty array if absent |
| `researcherProfiles` | Researcher-stage labels such as R1 or R2; empty array if absent |
| `postedDate` | Parsed YYYY-MM-DD date, or null when unparseable |
| `postedDateText` | Original displayed posting date text, or null |
| `applicationDeadline` | Source datetime retaining its UTC offset, or null |
| `applicationDeadlineText` | Original deadline text and timezone when shown, or null |
| `descriptionSnippet` | Listing excerpt; may be truncated by EURAXESS |
| `url` | Public job detail link, not fetched by this Actor |
| `searchUrl` | First listing page where this job was encountered in the run |
| `scrapedAt` | Extraction timestamp in UTC |

A job may describe multiple offers. One row represents one EURAXESS job card, not one individual vacancy slot.
The overview table displays core columns; JSON exports preserve all fields.

### Example output

A representative public listing card has this shape:

```json
{
  "jobId": "475760",
  "title": "Scientific Research Fellowship (BI) 101/2026",
  "institution": "University of Algarve",
  "country": "Portugal",
  "workLocations": "Number of offers: 1, Portugal, University of Algarve, Faro, 8005-139, Campus de Gambelas e Campus da Penha",
  "researchFields": ["Biological sciences"],
  "researcherProfiles": ["First Stage Researcher (R1)"],
  "postedDate": "2026-10-27",
  "postedDateText": "27 October 2026",
  "applicationDeadline": "2026-11-10T23:59:59+00:00",
  "applicationDeadlineText": "10 Nov 2026 - 23:59 (Europe/London)",
  "descriptionSnippet": "NOTICE NO. 101/2026COMPETITION FOR THE AWARD OF A GRANT, IN ACCORDANCE WITH THE PROVISIONS OF THE RESEARCH GRANT REGULATIONS OF UALG Title: 1 Bolsa de Investigação - MestreA competition is open for the award of 1 Bolsa de Investigação - Mestre within the scope of the R&D project Adaptações dos...",
  "url": "https://euraxess.ec.europa.eu/jobs/475760",
  "searchUrl": "https://euraxess.ec.europa.eu/jobs/search?f%5B0%5D=offer_type%3Ajob_offer",
  "scrapedAt": "2026-10-27T21:00:00.000Z"
}
```

The extraction timestamp above illustrates the format. Listings, dates and availability change on the source.

### How much does it cost to extract EURAXESS job listings?

Pricing consists of one `start` event per valid run and one `item` event per unique job row saved.
The start charge is $0.005. BRONZE item pricing is $0.002396 per job.
Spend tiers reflect your qualifying aggregate monthly Apify Store spend, not a private per-Actor volume schedule.

| Plan tier | Per unique job row |
| --- | ---: |
| FREE | $0.0027554 |
| BRONZE | $0.002396 |
| SILVER | $0.0018689 |
| GOLD | $0.0014376 |
| PLATINUM | $0.0014376 |
| DIAMOND | $0.0014376 |

Estimated BRONZE invoice examples, including one start:

| Unique rows saved | Total Actor event charge |
| ---: | ---: |
| 1 | $0.007396 |
| 10 | $0.02896 |
| 100 | $0.2446 |

These totals are Actor event charges, not a promise about your plan's other charges.
There is no separate event charge for dates, snippets or location fields.
Duplicates, excluded non-job cards and failed requests are not item events.
A naturally empty valid search may still incur the start charge.

### Limits and failure behavior

- Listing cards only: no full descriptions, salaries, requirements, application forms or contact enrichment.
- No historical archive, “only new” persistence, scheduling or notifications built into the Actor.
- The current source order is retained; search results may shift while pages are fetched.
- Per-run ID deduplication prevents repeated rows, but changing live pagination cannot guarantee an exhaustive census.
- A verified no-results page succeeds with zero rows; a challenge or unknown page shape fails instead.
- Requests use Apify residential proxy in France. Transient network errors, HTTP 403/429 and server errors receive at most three total attempts per page with bounded backoff and a fresh proxy identity.
- Unexpected redirects and invalid response types fail without blind retries. Exhausted requests fail the run; there is no unbounded retry or browser fallback.
- A page-cap warning indicates potentially partial coverage. Failed or timed-out runs can also leave partial rows: inspect run status before treating an export as complete.

Use modest caps initially and validate search results on EURAXESS before creating a recurring workflow.
A deadline on a listing is source data, not a guarantee that applications are still being accepted.

### Integrations and recurring snapshots

Use Apify schedules to launch daily or weekly snapshots with the same input.
Send exported rows into Google Sheets, a warehouse, Make, Zapier or n8n through their Apify integrations.
Use `jobId` as the upsert key and retain `scrapedAt` for each observation.
Compare successive datasets downstream to identify newly observed IDs or changed deadlines.
Absence from a capped snapshot does not prove a job was removed.

### API usage

Replace the token placeholder with your own Apify credential. Do not share it in public input.

```bash
curl -X POST \
  -H "Authorization: Bearer YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"maxItems":25}' \
  'https://api.apify.com/v2/acts/automation-lab~euraxess-research-jobs-scraper/run-sync-get-dataset-items'
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/euraxess-research-jobs-scraper').call({ maxItems: 25 });
const { items } = await client.dataset(run.defaultDatasetId).listItems({ limit: 25 });
console.log(items);
```

Python:

```python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/euraxess-research-jobs-scraper').call(run_input={'maxItems': 25})
items = client.dataset(run['defaultDatasetId']).list_items(limit=25).items
print(items)
```

For long runs prefer asynchronous run creation and bounded status checks over restarting a timed-out client request.

### MCP usage

Select a stable Actor-specific subset for your client:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/euraxess-research-jobs-scraper"
```

Equivalent Claude Desktop, Cursor and VS Code desktop/editor configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/euraxess-research-jobs-scraper"
    }
  }
}
```

Authenticate through your client's supported Apify flow. Discover actual tools and input schemas with `tools/list`.
Actor selection also exposes run and storage helpers; it does not expose exactly one tool.
Example prompt for an authorized invocation: “Collect at most 25 EURAXESS job cards and show titles, institutions and deadlines.”

Start once and retain the run ID and storage IDs; those IDs are not result rows.
`call-actor` waits at most 45 seconds (`waitSecs`, default 30). If still running,
check the same run with `get-actor-run`, using backoff of 2, 4, 8 then at most 10 seconds,
and stop after a 120-second consumer deadline. Configure the client request timeout above the selected wait plus transport margin.
On timeout recover the known run rather than starting another; if its ID is unknown, report uncertainty.
Report pending at the deadline, or a terminal failure honestly, including that existing rows may be partial.

After success, read `defaultDatasetId` using `get-dataset-items` with explicit fields, limit and offset.
For example, consume untransformed pages of 20 source rows, at most 100 rows and 64 KiB of serialized UTF-8 results,
whichever comes first. Enforce the byte cap host-side before model injection; omit or summarize oversized rows with disclosure.
Track source offsets, return a continuation offset and disclose truncation. If your client cannot intercept oversized responses,
do not claim a hard byte guarantee. Keep full exports outside model context.
These are consumer context limits, not Actor collection limits. Tool caching and progressive loading depend on the client;
no numeric token savings are promised.

### Legality and responsible use

This Actor reads public job-search listings and is not affiliated with the European Commission or EURAXESS.
Respect source terms, applicable law and downstream data-use obligations.
Review the original posting before contacting an institution or making recruitment decisions.
Do not use public snippets as a substitute for the complete official vacancy announcement.

### Diagnostics and privacy

Failed operations send sanitized diagnostic input, exceptions and Actor/build/run IDs to our private GlitchTip service for repair.
Secret fields and URL query strings are removed; diagnostic reports are retained for 30 days.
Do not include confidential search terms or credentials in input. Dataset `searchUrl` preserves the supplied public search filters;
manage access to your run storage appropriately. The runtime uses no AI provider and sends no job data to an AI model.
Apify hosts run input, datasets and logs under your account's retention settings; this Actor creates no independent archive or persistent session cache.
Delete unneeded runs and storage in Apify Console. Request removal of a diagnostic report through the Actor's Apify Store Issues tab;
include only the run ID, not credentials. Public source excerpts may contain personal information supplied by their publishers;
review exports before redistribution. Report reproducible problems through the Store Issues tab with input and run evidence.

### FAQ and troubleshooting

**Does this return full job descriptions?** No. It returns the snippet visible on the search card and a link to the original posting.

**Why did a keyword search fail validation?** Copy the URL after applying the EURAXESS search form. A keyword is a `f[n]=keywords:value` facet, not a plain `keywords` query parameter.

**Why are there fewer rows than requested?** Source exhaustion, overlapping searches, page limits, budgets or runtime limits can all stop collection. `maxItems` is a ceiling, not a guaranteed quantity.

**Can I monitor only new jobs?** Schedule runs and compare job IDs downstream. This Actor has no cross-run deduplication state.

**What if the source blocks access?** The run fails rather than reporting false empty success. Retry later after checking EURAXESS availability; do not assume missing rows mean no jobs exist.

### Related Actors

For a different, general European vacancy corpus, see
[EURES EU Job Listings Scraper](https://apify.com/automation-lab/eures-eu-job-listings-scraper).
EURES and EURAXESS are different sources; using one is not equivalent to covering the other.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/euraxess-research-jobs-scraper/changelog.md

# Actor input Schema

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

One to ten HTTPS euraxess.ec.europa.eu/jobs/search URLs, processed in order. Copy URLs after applying EURAXESS filters (f\[n]=facet:value); keyword search uses f\[n]=keywords:value, not plain keywords=. Source controls matching and multiple-facet semantics; these are not local title filters. Jobs-only scope is enforced; funding, hosting, detail URLs and unsupported parameters are rejected. Defaults to all Jobs. Duplicate job IDs across URLs produce one row per run.

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

Global cap on unique job rows across every search URL, after excluding non-job cards and duplicate IDs. Integer 1–1000, default 100. Zero/unlimited is unsupported. Collection stops at this cap, source exhaustion, maxPages or the platform billing/runtime limit; it does not guarantee full source coverage.

## `maxPages` (type: `integer`):

Global cap on unique listing pages fetched across all search URLs, not per query. Integer 1–100, default 100. A page contains up to about ten cards. Lower caps can return fewer than maxItems; a page-cap warning marks potentially partial coverage. Retries do not consume additional page slots.

## Actor input object example

```json
{
  "searchUrls": [
    "https://euraxess.ec.europa.eu/jobs/search"
  ],
  "maxItems": 20,
  "maxPages": 20
}
```

# Actor output Schema

## `dataset` (type: `string`):

Listing-card records with IDs, institutions, source links and recruitment dates.

# 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 = {
    "searchUrls": [
        "https://euraxess.ec.europa.eu/jobs/search"
    ],
    "maxItems": 20,
    "maxPages": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/euraxess-research-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 = {
    "searchUrls": ["https://euraxess.ec.europa.eu/jobs/search"],
    "maxItems": 20,
    "maxPages": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/euraxess-research-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 '{
  "searchUrls": [
    "https://euraxess.ec.europa.eu/jobs/search"
  ],
  "maxItems": 20,
  "maxPages": 20
}' |
apify call automation-lab/euraxess-research-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/euraxess-research-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/7n0yTMLHrm70uYrsY/builds/KCaA7xU6cPrmYzz7j/openapi.json
