# Ikerbasque Jobs Scraper — Basque Research, Spain (`nomad-agent/ikerbasque-scraper`) Actor

Scrape open calls from Ikerbasque, the Basque Foundation for Science in Spain: postdoc Research Fellow, Associate & Professor programmes plus permanent science jobs in the Basque Country. Records give title, status, dates, optional AI deadline, snippet and apply URL.

- **URL**: https://apify.com/nomad-agent/ikerbasque-scraper.md
- **Developed by:** [Nomad.Dev](https://apify.com/nomad-agent) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.10 / 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

## Ikerbasque Jobs Scraper — Basque Research, Spain

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

Scrape current research openings and calls from Ikerbasque, the Basque Foundation for Science: postdoc fellowships (Research Fellow), Research Associate and Research Professor programmes, and permanent science jobs in Spain's Basque Country. Ikerbasque researchers are hosted across the region's universities and CIC/BERC research institutes, making this the definitive source for PhD-to-professor research positions in the Basque Country — and a natural companion to EU research portals like EURAXESS or EURES for anyone tracking postdoc and faculty jobs in Spain.

### What Ikerbasque data does this scraper extract?

Each result is one flat JSON record per call:

| Field | Meaning |
|---|---|
| `id` | Stable source-side identifier (the call's URL slug) |
| `title` | Call title as posted |
| `company` | Always `"Ikerbasque"` — the foundation publishing the call |
| `location` | Always `"Bilbao, Spain"` (Ikerbasque's HQ) — the calls page does not list a per-role duty station |
| `status` | `"Open"` or `"Closed"` as shown on the calls page, or `null` if the source page carries no status label |
| `postedAt` | Last-updated date of the call's detail page (`YYYY-MM-DD`), or `null` when it can't be determined — see note below |
| `deadline` | Structured application deadline (`YYYY-MM-DD`), added only when **AI enrichment** is enabled; `null` otherwise — see "AI deadline extraction" below |
| `url` | Direct link to the call |
| `snippet` | Short description excerpt, prefixed with the status label |
| `isNew` | `true` when this call was first seen on a **delta-mode** run (`onlyNewSinceLastRun`); absent otherwise |

**A note on `postedAt`:** Ikerbasque does not publish a distinct "date first posted" for its calls. `postedAt` is read from the call's own detail page (its OpenGraph/article `modified`/`updated` meta tag), which tracks when that page's content was last edited — in practice this lines up closely with the active call cycle. This Actor does **not** invent or guess a date; if the detail page fetch fails or carries no timestamp, `postedAt` is `null`.

**On `deadline`:** Ikerbasque calls mention an application deadline only as free-form prose inside the description (phrasing varies call to call — "Deadline: 10th September 2026.", "Apply before June 30, 2024", etc.), not as a structured field. Rather than guess with brittle date regex, the structured `deadline` field is filled by an **opt-in AI extraction** (see below) that returns `null` whenever the text states no specific calendar date, and never fabricates one. With AI enrichment off, `deadline` stays `null` — read the deadline from `snippet`/the call `url` instead.

### How to scrape Ikerbasque with this Actor

1. Click **Try for free** / **Run** — no login to the target site, no cookies, no proxies to configure.
2. Adjust the input (`includeClosed`, `postedSince`, `maxItems`) or keep the defaults.
3. Run it and export the dataset as JSON, CSV or Excel, or read it over the [API](https://docs.apify.com/api/v2).

Run it from your own code:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("nomad-agent/ikerbasque-scraper").call(run_input={"maxItems": 50})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], "—", item["company"], item["url"])
```

Or a single HTTP call that runs the Actor and returns items in one response:

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

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `includeClosed` | boolean | `false` | When enabled, closed calls (no longer accepting applications) are included alongside open ones. By default only open calls are returned. |
| `postedSince` | integer | `0` | Only return calls last posted/updated within this many days. Applied client-side against the source page's own last-updated date; calls whose date can't be determined are kept rather than dropped. Set 0 to disable and return all calls regardless of age. |
| `maxItems` | integer | `50` | Maximum number of calls to return. Each result returned is a billed event — see Pricing. Applied before AI enrichment, so you never pay to enrich rows you capped out. Set 0 for no limit. |
| `onlyNewSinceLastRun` | boolean | `false` | Delta / alert mode — only return calls not seen on a previous flagged run. See "Delta mode / alerts" below. |
| `aiEnrichment` | boolean | `false` | Add a structured `deadline` field via your own Anthropic/Mistral key. See "AI deadline extraction" below. |
| `aiProvider` | string | `anthropic` | `anthropic` (Claude) or `mistral` — which provider runs deadline extraction when `aiEnrichment` is on. |
| `anthropicApiKey` | string (secret) | — | Your Anthropic API key. Used only when `aiEnrichment` is on and `aiProvider=anthropic`; billed by Anthropic. |
| `aiModel` | string | `claude-haiku-4-5-20251001` | Claude model for extraction (`aiProvider=anthropic`). |
| `mistralApiKey` | string (secret) | — | Your Mistral API key. Used only when `aiEnrichment` is on and `aiProvider=mistral`; billed by Mistral. |
| `mistralModel` | string | `mistral-small-latest` | Mistral model for extraction (`aiProvider=mistral`). |
| `cacheTtlSeconds` | integer | `1800` | *(Advanced)* How long to reuse a previous fetch of the Ikerbasque pages before checking the site again, in seconds. Set 0 to always fetch fresh data. |

### Delta mode / alerts

Set `onlyNewSinceLastRun: true` and this Actor only returns calls it has **not** seen on a previous run that also had the flag on — the mechanical way to "alert researchers to Ikerbasque calls the day they open". Already-seen calls are dropped **before** they are pushed or billed, so a scheduled cron run only costs you the Actor start plus any genuinely new calls. Seen state is tracked per Actor in a dedicated named key-value store, keyed by each call's stable URL slug (`id`); a call is only marked seen after it is successfully pushed, so nothing is lost if a run is interrupted. The cache is best-effort — if it can't be read, the run degrades to "everything is new" rather than failing.

### AI deadline extraction

Ikerbasque states application deadlines only as free-form prose, so the structured `deadline` field is filled by an **optional, bring-your-own-key** LLM pass rather than brittle regex. Set `aiEnrichment: true` and supply a key for your chosen `aiProvider`:

- **Anthropic** (`aiProvider: anthropic`, default) — supply `anthropicApiKey`, pick `aiModel`.
- **Mistral** (`aiProvider: mistral`) — supply `mistralApiKey`, pick `mistralModel`.

The model reads each call's description and returns the deadline as an ISO `YYYY-MM-DD` date, or `null` whenever the text states no specific calendar date — it is instructed never to guess, infer or fabricate a date, and never to invent a day when only a month/year is given. Your API key is billed by that provider, **not** by this Actor. If `aiEnrichment` is on but no matching key is supplied, extraction is skipped (a warning row is emitted) and calls are still returned normally with `deadline` left `null`.

### Output example

```json
{
  "id": "permanent-positions-2026",
  "title": "Permanent Positions 2026",
  "company": "Ikerbasque",
  "location": "Bilbao, Spain",
  "status": "Open",
  "postedAt": "2026-06-10",
  "url": "https://www.ikerbasque.net/en/calls/permanent-positions-2026",
  "snippet": "[Open] Ikerbasque offers 10 permanent positions for researchers willing to develop a long-term scientific career in the Basque Country..."
}
```

### Integrations

Export the dataset as JSON, CSV or Excel from the Console, or pull it programmatically: `apify-client` (Python/JS), a single `run-sync-get-dataset-items` HTTP call (see above), Make/Zapier/n8n via the Apify integration, or directly from AI agents through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp).

### Pricing

Pay per event: a small per-run start fee plus a per-job fee for each result returned — see the **Pricing** tab for current rates (volume discounts apply on higher Apify plans). No subscription, no rental — you pay only for what you fetch.

### Use cases

- Alerting researchers to Ikerbasque calls the day they open
- Academic job boards covering postdoc, research fellow and professor positions in Spain
- Research-mobility consulting for PhD holders and scientists relocating to the Basque Country
- Aggregating EU research portals — pairs naturally with EURAXESS, EURES and other academic sources
- Tracking Basque science hiring over time

### FAQ

**Is it legal to scrape Ikerbasque?**
This Actor reads only publicly available job postings — data any visitor can see without logging in. No personal data behind authentication is touched. Review the target site's terms and your local regulations for your specific use case.

**Do I need an account on the target site?**
No. Postings are fetched from public pages/APIs — no login, cookies or session tokens.

**How fresh is the data?**
Every run fetches live listings. Results are cached for `cacheTtlSeconds` (default 30 min, set 0 to always hit the source live).

**How many jobs can I get?**
`maxItems` caps the run (set 0 for no cap). The Ikerbasque calls page is a small, rolling list of currently open and recently closed calls, not a paginated archive — expect a handful of results per run, not thousands.

**Something broken or missing?**
Open an issue on the Actor's **Issues** tab — it is monitored and reliability fixes ship fast.

### Related Actors

- [Research & Academic Jobs Scraper — 10 Sources](https://apify.com/nomad-agent/researcher-bundle)
- [EURAXESS Jobs Scraper — EU Research Positions](https://apify.com/nomad-agent/euraxess-scraper)
- [Universitat de Barcelona PhD Vacancy Scraper](https://apify.com/nomad-agent/ub-doctoral-scraper)
- [jobs.ac.uk Scraper — UK Academic & Research Jobs](https://apify.com/nomad-agent/jobs-ac-uk-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

## `includeClosed` (type: `boolean`):

When enabled, closed calls (no longer accepting applications) are included alongside open ones. By default only open calls are returned.

## `postedSince` (type: `integer`):

Only return calls last posted/updated within this many days. Ikerbasque doesn't publish a distinct <code>date first posted</code>, so this is applied client-side against the source page's own last-updated date. Calls whose date can't be determined are kept rather than dropped. Set 0 (default) to disable and return all calls regardless of age.

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

Maximum number of calls to return. Each result returned is a billed event — see the Pricing tab. Applied before AI enrichment, so you never pay to enrich rows you capped out. Set 0 for no limit (the calls page currently lists only a handful of open/closed calls, so this is low-risk today, but capping it bounds cost if that changes).

## `onlyNewSinceLastRun` (type: `boolean`):

Delta / alert mode: only output calls not seen on a previous run that also had this flag on — the mechanical way to "alert the day a call opens". Already-seen calls are dropped before push (not billed), so this is the cheapest way to run this Actor on a cron schedule and only pay for genuinely new calls. State is tracked per Actor in a dedicated key-value store, keyed by the call's URL slug. See README "Delta mode / alerts".

## `aiEnrichment` (type: `boolean`):

Adds a structured <code>deadline</code> field (ISO YYYY-MM-DD) to every call by reading its free-form description via the Anthropic, Mistral or OpenAI API (pick which below). Ikerbasque states deadlines only as prose ("Deadline: 10th September 2026"), so this closes that gap without brittle date regex — the model returns null whenever the text states no specific calendar date, and never guesses. Requires your own API key for the provider you pick — billed separately by that provider, not by this Actor (see README "AI deadline extraction"). If turned on without a matching key, enrichment is skipped (with a warning) and calls are still returned normally, with deadline left null.

## `aiProvider` (type: `string`):

Which AI provider runs deadline extraction (only relevant when "AI enrichment" is on). <code>anthropic</code> (default) uses Claude via anthropicApiKey. <code>mistral</code> uses a Mistral model via mistralApiKey instead — pick this if you'd rather bring a Mistral key than an Anthropic one. <code>openai</code> uses a GPT model via openaiApiKey.

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

Your Anthropic API key (sk-ant-…). Only used when "AI enrichment" is on and aiProvider is <code>anthropic</code>; billed separately by Anthropic. Not required unless aiEnrichment is on.

## `aiModel` (type: `string`):

Claude model id used for deadline extraction when aiProvider is <code>anthropic</code> (only relevant when "AI enrichment" is on). Any valid Anthropic model id works, e.g. <code>claude-haiku-4-5-20251001</code> (default — fast, cheap, ample for this single-field extraction) or <code>claude-sonnet-4-5</code> (higher-quality reading on longer descriptions).

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

Your Mistral API key. Only used when "AI enrichment" is on and aiProvider is <code>mistral</code>; billed separately by Mistral. Not required unless aiEnrichment is on with aiProvider=mistral.

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

Mistral model id used for deadline extraction when aiProvider is <code>mistral</code> (only relevant when "AI enrichment" is on). Any valid Mistral model id works, e.g. <code>mistral-small-latest</code> (default — matches larger Mistral models on this well-scoped extraction at a fraction of the cost), <code>mistral-medium-latest</code> or <code>mistral-large-latest</code>.

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

Your OpenAI API key (sk-…). Only used when "AI enrichment" is on and aiProvider is <code>openai</code>; billed separately by OpenAI. Not required unless aiEnrichment is on with aiProvider=openai.

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

OpenAI model id used for deadline extraction when aiProvider is <code>openai</code> (only relevant when "AI enrichment" is on). Defaults to <code>gpt-4.1-mini</code> — cheap, fast and ample for this single-field extraction. Any chat-completions model works, including the gpt-5 family.

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

How long to reuse a previous fetch of the Ikerbasque pages before checking the site again, in seconds. Re-runs within this window are faster and don't hit the site again. Set 0 to always fetch fresh data.

## Actor input object example

```json
{
  "includeClosed": false,
  "postedSince": 0,
  "maxItems": 50,
  "onlyNewSinceLastRun": false,
  "aiEnrichment": false,
  "aiProvider": "anthropic",
  "aiModel": "claude-haiku-4-5-20251001",
  "mistralModel": "mistral-small-latest",
  "openaiModel": "gpt-4.1-mini",
  "cacheTtlSeconds": 1800
}
```

# 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/ikerbasque-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("nomad-agent/ikerbasque-scraper").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/ikerbasque-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/AybSsaxL5kgF8Ekig/builds/8cMJAuVWiq6Ig2TbN/openapi.json
