# EURAXESS Scraper (`santamaria-automations/euraxess-scraper`) Actor

Scrape job offers from EURAXESS, the EU researcher job portal. Returns title, employer, location, deadline, research fields, career stage, contract type, start date, contact e-mail, apply URL and full description. Pay per event: $0.001 per run, $0.003 per search result, $0.005 per job with details.

- **URL**: https://apify.com/santamaria-automations/euraxess-scraper.md
- **Developed by:** [NanoScrape](https://apify.com/santamaria-automations) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 80.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 job detail results

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

## EURAXESS Scraper - Research, PhD and Postdoc Jobs Across Europe

Pull job offers from [EURAXESS](https://euraxess.ec.europa.eu), the European Commission's researcher job portal (roughly 6,400 live job offers across 60+ countries, from universities, research institutes, hospitals and companies). Every row returns the employer, location with coordinates, application deadline, research fields, researcher career stage, contract type, hours, start date, reference number, contact e-mail and phone, the apply URL and the full description as text, HTML and Markdown. No login and no API key.

### What you get

| Field | Description |
|---|---|
| `id`, `job_url`, `apply_url` | EURAXESS job number, the EURAXESS page, and where to apply (the employer or job board link when the job page has one) |
| `title`, `company_name` | Offer title and the hiring organisation |
| `publisher_name`, `publisher_profile_url`, `publisher_logo_url` | The EURAXESS organisation profile that posted the offer. This can be a job board such as Academic Positions rather than the employer |
| `location`, `city`, `region`, `country`, `postal_code`, `street_address`, `latitude`, `longitude`, `work_locations` | First work location, plus every work location as a list |
| `posted_at`, `posted_at_datetime`, `posted_at_text` | Posting day as ISO 8601 UTC (the site publishes the day only, so the time is 00:00:00Z) |
| `expires_at`, `application_deadline`, `application_deadline_text` | Application deadline as ISO 8601 UTC, and as printed on the site |
| `employment_type`, `contract_type`, `contract_type_details`, `working_hours`, `hours_per_week`, `start_date` | Full-time or Part-time, contract type, hours per week, offer start date |
| `research_fields`, `category`, `researcher_profiles`, `position_level`, `positions` | Research fields (Parent » Child), career stage R1 to R4, PhD or postdoc position type |
| `education_required`, `experience_required`, `languages`, `requirements`, `benefits_text` | Requirements as published |
| `funding_programme`, `is_research_infrastructure_position`, `reference_number` | EU funding answer, research infrastructure flag, employer reference |
| `contact_email`, `contact_emails`, `contact_phone`, `contact_phones`, `contact_fax`, `contact_website`, `contact_address`, `company_website` | Contact block of the job page |
| `description_full`, `description_snippet`, `description_html`, `description_md` | Offer description in four formats |
| `selection_process`, `eligibility_criteria`, `additional_comments`, `additional_sections`, `attachments`, `additional_info_url` | Extra text blocks and attached files when the employer filled them in |
| `search_query`, `source`, `detail_fetched`, `scraped_at` | Which keyword found the row, source tag, whether the job page was opened, scrape time |

Not available on EURAXESS, so not in the output: salary, a named contact person, and remote/hybrid status. Salary or benefits sometimes appear inside the description text or in `benefits_text`.

### Quick start

`{}` works: with no input the actor returns the 50 newest job offers across all countries.

```json
{
  "countries": ["Switzerland"],
  "searchQueries": ["laboratory technician", "chemistry"],
  "researcherProfiles": ["R1", "R2"],
  "sortBy": "newest",
  "postedWithinDays": 14,
  "includeJobDetails": true,
  "maxResultsPerQuery": 50,
  "maxResults": 100
}
```

Daily "what is new" run for one country: `{"countries": ["Germany"], "sortBy": "newest", "postedWithinDays": 1, "maxResults": 200}`.

### Input

| Input | Server-side or client-side | Notes |
|---|---|---|
| `searchQueries` | Server-side | Keyword search, one search per keyword. Rows are tagged in `search_query` and de-duplicated across keywords. Empty list lists everything that matches the other filters |
| `countries` | Server-side | Several countries are OR-combined. Empty means all countries |
| `location` | Server-side for a country name, otherwise client-side | A country name acts like `countries`. Any other text (a city such as `Zurich`) is matched against the location text of each search result |
| `researcherProfiles` | Server-side | `R1` first stage (PhD level), `R2` recognised (postdoc), `R3` established, `R4` leading, `other` (technicians and administration) |
| `positionTypes` | Server-side | `phd`, `postdoc`, `master`, `bachelor`, `undergraduate`, `research_support`, `other` |
| `organisationTypes` | Server-side | Higher education, public research institution, research laboratory, SME and start-up, large enterprise, and more |
| `euFunding` | Server-side | Horizon Europe (ERC, MSCA, COFUND, EIC), Horizon 2020, Erasmus+, Interreg, LIFE, or `not_eu_funded` |
| `researchFields` | Server-side | Names as on EURAXESS (for example `Chemistry`, `Computer science`) or numeric ids. A top-level field also matches its sub-fields |
| `sortBy` | Server-side | `newest` (posting date, newest first), `relevance` (the site's default order), `deadline` (soonest deadline first) |
| `postedWithinDays`, `maxAgeHours` | Client-side cutoff | EURAXESS has no date filter. With `sortBy: newest` the crawl stops at the first older job, so recent-only runs read only a page or two. With other sorts every page is read and older jobs are dropped |
| `titleFilter` | Client-side | Comma-separated terms, case-insensitive match on the title. Applied before job pages are opened, so jobs dropped by the filter are not charged |
| `maxResults`, `maxResultsPerQuery` | Actor | Total cap (default 50) and per-keyword cap (default: same as `maxResults`) |
| `includeJobDetails` | Actor | On (default): opens each job page. Off: search-result fields only (title, publisher, location text, deadline, research fields, profile, short teaser) |
| `searchUrls`, `directUrls`, `startUrls` | n/a | Paste EURAXESS search URLs (filters and sort in the URL are honoured), job URLs, or a mix |
| `maxConcurrency` | Actor | Parallel job-page fetches, 1 to 4 (default 2) |

Notes on how EURAXESS behaves:

- Only job offers are returned (the site also lists funding and hosting offers, which are excluded).
- The posting date has day precision only. `maxAgeHours` and `postedWithinDays` keep a job when any part of its posting day is inside the window.
- `sortBy: relevance` is the site's own default order, which is close to newest-first but not strictly by date.
- Some job pages carry no description (the employer only linked out). Those rows still have title, employer, deadline and apply URL.
- Speed: about 30 jobs per minute with job pages on (a 200-job run takes roughly 6 minutes, 100 jobs about 2 to 3 minutes). Search-only runs (`includeJobDetails: false`) read 10 jobs per request and are faster. EURAXESS limits how fast one visitor may read it, so very large runs (thousands of jobs) take proportionally longer; the actor handles this on its own and needs no setup.

### Use with AI Agents (MCP)

Connect this actor to any MCP-compatible AI client: Claude Desktop, Claude.ai, Cursor, VS Code, LangChain, LlamaIndex, or custom agents.

Configure the MCP server with EURAXESS Scraper preconfigured at `mcp.apify.com?tools=santamaria-automations/euraxess-scraper`.

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

For per-tool schemas and copy-paste snippets for MCP clients, see the [MCP tab](https://console.apify.com/actors/j31v9WsSBzUWZlmZA/info/api/mcp?build=latest).

See the [auto-generated API tab](https://console.apify.com/actors/j31v9WsSBzUWZlmZA/info/api) for language-specific examples (cURL, JS, Python, .NET, Ruby, PHP).

**Example prompt once connected:**

> "Use `euraxess-scraper` to find PhD and postdoc positions in chemistry in Switzerland posted in the last 14 days. Return employer, deadline, contact e-mail and apply URL as a table."

### Why this actor

- Real server-side filtering for country, keyword, career stage, position type, organisation type, EU funding and research field, so you only pay for rows you asked for.
- Newest-first with stop-early: daily runs with `postedWithinDays` read only the first page or two.
- Employer, contact e-mail, phone, reference number, work-location coordinates, requirements and benefits as separate fields, not buried in a description blob.
- Detail pages that fail to load are billed as search-level rows, not as full detail rows.

### Output example

```json
{
  "id": "471116",
  "title": "Associate professor / Assistant professor pecialised in biochemistry",
  "job_url": "https://euraxess.ec.europa.eu/jobs/471116",
  "company_name": "University of Ostrava",
  "company_website": "http://www.osu.cz",
  "location": "Ostrava, Czech Republic",
  "city": "Ostrava",
  "country": "Czech Republic",
  "posted_at_datetime": "2026-10-07T00:00:00Z",
  "application_deadline": "2026-11-07T22:59:59Z",
  "employment_type": "Part-time",
  "contract_type": "Temporary",
  "hours_per_week": 8,
  "start_date": "2026-11-01",
  "research_fields": ["Medical sciences"],
  "researcher_profiles": ["Recognised Researcher (R2)"],
  "languages": ["Czech (Excellent)", "English (Good)"],
  "education_required": "PhD or equivalent",
  "funding_programme": "Not funded by a EU programme",
  "contact_emails": ["personalnilf@osu.cz"],
  "description_full": "The Dean of the Faculty of Medicine, University of Ostrava, announces a selection procedure for the position of: ..."
}
```

### Pricing

Pay per event, no subscription:

| Event | Price | When |
|---|---|---|
| Run start | $0.001 | Once per run |
| Job Detail Result | $0.005 | Each job row with the full job page (default) |
| Job Search Result | $0.003 | Each job row from search results only (`includeJobDetails: false`) |

A detail page that fails to load is billed as a search result, not as a detail result. Duplicates across keywords are removed before billing. 100 jobs with details cost about $0.50 plus the start fee.

### Common use cases

- Weekly feed of new PhD and postdoc openings for a university research office or recruiter.
- Lab technician and research support job alerts for one country (`researcherProfiles: ["other"]`).
- Funding-aware search: MSCA, ERC and COFUND positions only.
- Feed `company_website` and contact e-mails into an outreach or CRM workflow.

### Related actors

- [Website Job Extractor](https://apify.com/santamaria-automations/website-job-extractor): extract jobs from any company career page.
- [Indeed HTTP Scraper](https://apify.com/santamaria-automations/indeed-http-scraper): general job listings from Indeed.
- [Glassdoor Scraper](https://apify.com/santamaria-automations/glassdoor-scraper): jobs, salaries and company ratings.
- [Career Site Jobs Scraper](https://apify.com/santamaria-automations/career-site-jobs-scraper): extract jobs from company applicant-tracking pages (Lever, Greenhouse, Workable and more).
- [Job Feed](https://apify.com/santamaria-automations/job-feed): aggregate jobs from many platforms into one unified feed.
- [Website Email Scraper](https://apify.com/santamaria-automations/website-email-scraper): feed it `company_website` to collect employer e-mails.
- [Website Contact Extractor](https://apify.com/santamaria-automations/website-contact-extractor): feed it `company_website` to extract contact names, phones and socials.

### Support

- **Questions or issues?** Email contact@nanoscrape.com, we typically reply within 6 hours. You can also open a ticket in the [Issues tab](https://console.apify.com/actors/j31v9WsSBzUWZlmZA/info/issues) on the actor page.
- **Feature request for this actor?** Open a ticket in the [Issues tab](https://console.apify.com/actors/j31v9WsSBzUWZlmZA/info/issues) or email contact@nanoscrape.com with the field you need and, if possible, a URL that shows the data live.
- **Need a scraper for a job board we don't cover yet?** Email contact@nanoscrape.com with the target site and your rough usage volume.

# Actor input Schema

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

Optional keywords, one search per keyword (server-side EURAXESS keyword facet). Leave empty to list all jobs matching the filters below. Rows are tagged with the keyword that found them and de-duplicated across keywords.

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

Only jobs located in these countries (server-side facet, several countries are OR-combined). Leave empty for all countries. Names as on EURAXESS.

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

Optional. A country name is applied server-side like `countries`; any other text (for example a city such as Zurich) is matched client-side against the location shown on each result card.

## `researcherProfiles` (type: `array`):

Career stage (server-side, OR-combined). R1 first stage / PhD, R2 recognised researcher / postdoc, R3 established, R4 leading, Other profession (technicians, administration).

## `positionTypes` (type: `array`):

Type of position offered (server-side, OR-combined).

## `organisationTypes` (type: `array`):

Type of the hiring organisation (server-side, OR-combined).

## `euFunding` (type: `array`):

Only jobs funded through these EU programmes (server-side, OR-combined). Choose `not_eu_funded` for jobs without EU funding.

## `researchFields` (type: `array`):

EURAXESS research field names or numeric ids (server-side, OR-combined). A top-level field such as `Engineering` also matches its sub-fields. Names that exist under several parents (for example `Other`) must be given as numeric id.

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

newest = posting date, newest first (server-side, enables stop-early with postedWithinDays / maxAgeHours). relevance = the site's default order. deadline = application deadline, soonest first.

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

Only jobs posted within the last N days. EURAXESS publishes the posting day only (no time), so the window is day-granular. With sortBy newest the crawl stops at the first older job. 0 = off.

## `maxAgeHours` (type: `integer`):

Alternative to postedWithinDays, in hours. Day-granular on this site: a job is kept when any part of its posting day is inside the window. 0 = off.

## `titleFilter` (type: `string`):

Comma-separated terms, case-insensitive substring OR-match against the job title. Applied before detail pages are fetched, so filtered-out jobs are not charged.

## `maxResults` (type: `integer`):

Total cap across all keywords. Default 50.

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

Cap per keyword / search URL. Empty = same as maxResults. If maxResults is smaller than per-keyword cap x number of keywords, later keywords get fewer or no results.

## `includeJobDetails` (type: `boolean`):

Open every job page for the full description, requirements, contact e-mail/phone, apply URL, employer, locations and start date. Off = search-result data only (billed as a cheaper event).

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

Ready-made EURAXESS search URLs (https://euraxess.ec.europa.eu/jobs/search?...). Filters and sort in the URL are honoured; paging is added by the actor.

## `directUrls` (type: `array`):

EURAXESS job page URLs (https://euraxess.ec.europa.eu/jobs/<id>) to scrape directly, skipping search.

## `startUrls` (type: `array`):

Mixed list: search URLs go to the search crawler, job URLs to the direct scraper.

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

Parallel detail-page fetches (1-4, default 2). All requests share one pacer because EURAXESS rate-limits bursts.

## `searchQuery` (type: `string`):

DEPRECATED alias for searchQueries with one keyword. Kept so saved tasks keep working.

## Actor input object example

```json
{
  "searchQueries": [
    "laboratory technician"
  ],
  "countries": [
    "Switzerland"
  ],
  "researcherProfiles": [],
  "positionTypes": [],
  "organisationTypes": [],
  "euFunding": [],
  "researchFields": [],
  "sortBy": "newest",
  "postedWithinDays": 0,
  "maxAgeHours": 0,
  "titleFilter": "technician, laborant",
  "maxResults": 50,
  "includeJobDetails": true,
  "searchUrls": [],
  "directUrls": [],
  "startUrls": [],
  "maxConcurrency": 2
}
```

# Actor output Schema

## `jobListings` (type: `string`):

Dataset containing scraped EURAXESS job offers

# 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": [
        "laboratory technician"
    ],
    "countries": [
        "Switzerland"
    ],
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("santamaria-automations/euraxess-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": ["laboratory technician"],
    "countries": ["Switzerland"],
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("santamaria-automations/euraxess-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": [
    "laboratory technician"
  ],
  "countries": [
    "Switzerland"
  ],
  "maxResults": 50
}' |
apify call santamaria-automations/euraxess-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,santamaria-automations/euraxess-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/j31v9WsSBzUWZlmZA/builds/TylUrlXHJKJzAZDNz/openapi.json
