# Europe Jobs Scraper — Greenhouse, Lever & Ashby Careers (`xamto1987/europe-jobs-ats`) Actor

Collect job postings from the public career boards of a curated catalog of European companies on Greenhouse, Lever and Ashby. One normalized schema, filters by country, company and title keyword, and a delta mode that reports added and removed postings between runs.

- **URL**: https://apify.com/xamto1987/europe-jobs-ats.md
- **Developed by:** [Santi Belloso Lopez](https://apify.com/xamto1987) (community)
- **Categories:** Jobs, Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

Scrape **job postings from the public career boards of European companies** hosted on **Greenhouse, Lever and Ashby**. This **Europe jobs scraper** reads a curated catalog of companies, normalizes every posting to one schema, and can run in **delta mode** to return only the postings added or removed since your previous run.

Extrae **ofertas de empleo de los tablones públicos de empresas europeas** alojados en **Greenhouse, Lever y Ashby**. Trabaja sobre un **catálogo curado de empresas**, devuelve todas las ofertas con un único esquema y tiene un **modo delta** que entrega solo las altas y bajas desde la última ejecución.

### Europe company jobs scraper: what it does · Qué hace

Greenhouse, Lever and Ashby are applicant tracking systems (ATS) that many companies use to publish their openings. Each one exposes the board as open JSON, with no login, API key or browser needed. The three formats differ, so this Actor reads each board, maps the fields to one common schema and filters by country, company, ATS and title keyword.

- **Curated catalog**: the Actor ships a list of European companies (headquarters country, ATS and board identifier), each one checked against its board before being added. It does not crawl the web looking for boards: it covers the companies in the catalog, nothing else.
- **One schema**: the same 17 fields whichever ATS the posting comes from.
- **Delta mode**: `mode: "delta"` returns only what was added or removed since the last run with the same filters.
- **No personal data**: recruiter names, emails and phone numbers are dropped by the parser.

Greenhouse, Lever y Ashby son sistemas de seguimiento de candidatos (ATS) que muchas empresas usan para publicar sus vacantes. Cada uno expone el tablón como JSON abierto, sin login, sin clave y sin navegador. Los tres formatos son distintos: este actor lee cada tablón, lleva los campos a un esquema común y filtra por país, empresa, ATS y palabra clave del título.

- **Catálogo curado**: el actor incluye una lista de empresas europeas (país sede, ATS e identificador del tablón), comprobada contra su tablón antes de añadirla. No rastrea la web buscando tablones: cubre las empresas del catálogo, nada más.
- **Un solo esquema**: los mismos 17 campos venga la oferta del ATS que venga.
- **Modo delta**: `mode: "delta"` devuelve solo las altas y bajas desde la última ejecución con los mismos filtros.
- **Sin datos personales**: el parser descarta nombres de reclutador, emails y teléfonos.

### Job posting data extracted · Datos extraídos

One item per posting. / Un ítem por oferta.

| Campo / Field | Tipo / Type | Qué es / What it is |
|---|---|---|
| `ats` | texto | `greenhouse`, `lever` o `ashby` · Source system |
| `company` | texto | Slug de la empresa en el catálogo · Company slug in the catalog |
| `companyName` | texto | Nombre de la empresa · Company name |
| `country` | texto | País sede, ISO-2 (por ejemplo `ES`) · Headquarters country, from the catalog |
| `jobId` | texto | Identificador de la oferta en el ATS · Posting ID in the ATS |
| `jobKey` | texto | `ats:company:jobId`, clave estable para comparar ejecuciones · Stable key to compare runs |
| `title` | texto | Título del puesto · Job title |
| `url` | texto | Enlace público a la oferta · Public link to the posting |
| `location` | texto o `null` | Ubicación tal cual la da el ATS · Location text as given by the ATS |
| `remote` | booleano o `null` | Solo si el ATS lo declara; nunca se infiere · Only when the ATS states it; never inferred |
| `department` | texto o `null` | Departamento o equipo · Department or team |
| `employmentType` | texto o `null` | Tipo de contrato tal cual lo da el ATS · Employment type as given by the ATS |
| `publishedAt` | fecha ISO o `null` | Fecha de publicación, si el ATS la da · Publication date, if provided |
| `updatedAt` | fecha ISO o `null` | Última actualización, si el ATS la da · Last update, if provided |
| `descriptionText` | texto o `null` | Descripción en texto plano (máx. 20.000 caracteres), solo con `includeDescription` · Plain-text description, only with `includeDescription` |
| `change` | `added`, `removed` o `null` | Solo en modo `delta` · Only in `delta` mode |
| `scrapedAt` | fecha ISO | Momento de la extracción · Extraction time |

Los campos que un ATS no publica salen como `null`: no todos los tablones dan fecha, tipo de contrato o departamento. / Fields a board does not publish come out as `null`.

### Jobs scraper input: filters, delta and limits · Parámetros de entrada

| Parámetro / Field | Tipo / Type | Por defecto / Default | Descripción / Notes |
|---|---|---|---|
| `countries` | lista de textos | `[]` | Códigos ISO-2 del país sede. Vacío = todo el catálogo · Headquarters country codes. Empty = whole catalog |
| `companies` | lista de textos | `[]` | Slugs del catálogo (por ejemplo `typeform`, `cabify`, `wallapop`, `jetbrains`). Vacío = todas. Si se indica, `countries` se ignora · Catalog slugs. When set, `countries` is ignored |
| `ats` | lista de textos | `greenhouse`, `lever`, `ashby` | Qué sistemas leer · Which systems to read |
| `keywords` | lista de textos | `[]` | Coincidencia sin mayúsculas **solo en el título**. Vacío = todo · Case-insensitive match on the title only |
| `mode` | `all` | `delta` | `all` | `delta` = solo altas y bajas desde la última ejecución · Only additions and removals since the last run |
| `includeDescription` | booleano | `false` | Añade `descriptionText`. Apagado por defecto: ver más abajo · Off by default: see below |
| `maxItems` | entero | `500` | Tope de ítems; `0` = sin límite · Item cap; `0` = no limit |

```json
{
  "countries": ["ES", "DE"],
  "ats": ["greenhouse", "lever", "ashby"],
  "keywords": ["engineer", "data"],
  "mode": "all",
  "includeDescription": false,
  "maxItems": 500
}
```

#### Modo delta · Delta mode

Con `mode: "delta"` el actor guarda, tras cada ejecución, qué ofertas ha visto. En la siguiente ejecución con **los mismos filtros** devuelve solo:

- `change: "added"`: ofertas que no estaban la última vez.
- `change: "removed"`: ofertas que estaban y ya no aparecen en el tablón. Llevan los 17 campos, con `null` donde no hay dato (`companyName` y `country` salen del catálogo).

Reglas del estado:

- Se guarda por combinación de `countries`, `companies`, `ats` y `keywords`. `mode`, `maxItems` e `includeDescription` no cuentan: una ejecución `all` con los mismos filtros deja la foto de partida para el siguiente `delta`.
- La **primera** ejecución en `delta`, sin foto previa, devuelve **todas** las ofertas como `added`.
- Las altas y bajas que no caben en `maxItems` no se dan por vistas: salen en la siguiente ejecución.
- Si el tablón de una empresa falla ese día, sus ofertas no se dan de baja.

Programa el actor (diario o semanal) para alimentar un aviso de nuevas vacantes o un registro de contrataciones abiertas y cerradas.

With `mode: "delta"` the Actor stores which postings it saw. The next run **with the same filters** returns only postings marked `added` (new) or `removed` (no longer on the board; all 17 fields, `null` where there is no data). State is kept per combination of `countries`, `companies`, `ats` and `keywords`; `mode`, `maxItems` and `includeDescription` are not part of it, so an `all` run with the same filters sets the baseline for the next `delta`. The first `delta` run with no baseline returns every posting as `added`. Changes that do not fit in `maxItems` are not marked as seen and come out on the next run. If a company's board fails on a given day, its postings are not reported as removed. Schedule it daily or weekly.

#### Por qué `includeDescription` está apagado · Why descriptions are off by default

Algunos tablones, sobre todo en Ashby, devuelven la descripción de todas las ofertas en una sola respuesta que puede pesar **varios MB por empresa**. Con la opción activa, las ejecuciones tardan más y el dataset crece mucho. Por eso viene en `false`: actívala solo si necesitas el texto, y acótala con `companies`, `countries` o `keywords`. La descripción se entrega en texto plano y se recorta a 20.000 caracteres.

Some boards, especially Ashby, return every description in one response that can weigh **several MB per company**. Turning `includeDescription` on makes runs slower and datasets much larger, so it is off by default. Use it with `companies`, `countries` or `keywords` to keep runs small.

### Job data output example · Ejemplo de output

Ítem sintético, solo ilustrativo (**example**, no es una oferta real). / Synthetic item for illustration only (**example**, not a real posting).

```json
{
  "ats": "greenhouse",
  "company": "example-company",
  "companyName": "Example Company",
  "country": "ES",
  "jobId": "1234567",
  "jobKey": "greenhouse:example-company:1234567",
  "title": "Senior Data Engineer",
  "url": "https://apify.com/xamto1987/europe-jobs-ats",
  "location": "Madrid, Spain",
  "remote": null,
  "department": "Data",
  "employmentType": "Full-time",
  "publishedAt": "2026-10-01T09:30:00.000Z",
  "updatedAt": "2026-10-12T14:05:00.000Z",
  "descriptionText": null,
  "change": null,
  "scrapedAt": "2026-10-16T08:00:00.000Z"
}
```

En modo `delta`, `change` vale `added` o `removed`. / In `delta` mode `change` is `added` or `removed`.

### Job market data use cases · Casos de uso

- **Seguimiento de contratación / Hiring tracking**: qué empresas abren posiciones, en qué departamentos y en qué países, ejecución tras ejecución.
- **Alertas de nuevas vacantes / New-job alerts**: programa el modo `delta` y envía solo las altas a tu correo, Slack o base de datos.
- **Prospección B2B / B2B prospecting**: una empresa que contrata ciertos perfiles suele estar invirtiendo en esa área; úsalo como señal para tu equipo comercial, sin tratar personas.
- **Investigación de mercado laboral / Labor market research**: volumen y tipo de ofertas por país y sistema, sobre las empresas del catálogo (no es una muestra representativa del mercado).
- **Agregadores y agentes / Aggregators and agents**: alimenta un tablón propio o un agente con ofertas ya normalizadas.

### Sources, coverage and limits · Fuente y límites

- **Fuente**: los tablones públicos que cada empresa publica en Greenhouse, Lever y Ashby, en su formato JSON abierto. Sin login, sin cookies, sin proxies ni navegador. Source: the public job-board feeds of each company.
- **Cobertura = el catálogo**: solo se leen las empresas del catálogo incluido, y solo las que usan uno de esos tres sistemas. Una empresa que no está en el catálogo no aparece; las ofertas publicadas fuera de esos tres ATS tampoco. Coverage is the catalog, not "all of Europe".
- **Una empresa puede salir sin ofertas** si en ese momento no tiene vacantes abiertas o su tablón ya no responde.
- **Datos tal cual los publica el ATS**: ubicación, tipo de contrato y departamento son texto libre de la empresa y no están normalizados entre empresas. `remote` solo se rellena si el ATS lo declara.
- **Fechas**: `publishedAt` y `updatedAt` dependen de lo que cada sistema entrega; pueden ser `null`.
- **Ritmo**: el actor lee un tablón cada vez y se identifica con un User-Agent propio. No modifiques ese comportamiento.
- **Filtros**: `keywords` busca solo en el título, no en la descripción ni en la ubicación. No hay filtro por sueldo, seniority ni ciudad.

### Related Actors · Actores relacionados

Más actores de datos públicos del mismo autor. / More public-data Actors by the same author.

| Actor | Qué extrae / What it scrapes |
|---|---|
| [spain-grants-bdns](https://apify.com/xamto1987/spain-grants-bdns) | BDNS: convocatorias y concesiones de subvenciones públicas |
| [spain-de-minimis-aid](https://apify.com/xamto1987/spain-de-minimis-aid) | BDNS: ayudas de minimis y ayudas de Estado por NIF |
| [spain-grants-registries](https://apify.com/xamto1987/spain-grants-registries) | BDNS: grandes beneficiarios, sanciones por fraude y ayudas a partidos |
| [spain-boe-monitor](https://apify.com/xamto1987/spain-boe-monitor) | BOE: monitor incremental por palabra clave, sección y NIF |
| [spain-borme-companies](https://apify.com/xamto1987/spain-borme-companies) | BORME: constituciones, nombramientos, ceses y concursos |
| [spain-cadastre-bulk](https://apify.com/xamto1987/spain-cadastre-bulk) | Catastro: enriquecimiento masivo por referencia catastral o dirección |
| [spain-bocm-gazette](https://apify.com/xamto1987/spain-bocm-gazette) | BOCM: boletín oficial de la Comunidad de Madrid, en modo delta |
| [spain-boja-gazette](https://apify.com/xamto1987/spain-boja-gazette) | BOJA: boletín oficial de la Junta de Andalucía, en modo delta |
| [catalonia-tenders](https://apify.com/xamto1987/catalonia-tenders) | Licitaciones y adjudicaciones públicas de Cataluña (PSCP) |
| [euskadi-tenders](https://apify.com/xamto1987/euskadi-tenders) | Anuncios de contratación pública del País Vasco |
| [aragon-tenders](https://apify.com/xamto1987/aragon-tenders) | Registro de contratos públicos de Aragón (CKAN) |

### Is it legal? Public job boards and GDPR · Aviso legal y RGPD

- **Solo datos públicos**: el actor lee ofertas que las propias empresas publican para ser vistas, sin login ni saltarse ninguna medida técnica. It reads only publicly posted job offers.
- **Sin datos de personas**: el esquema no contiene campos de personas. Los nombres de reclutador o de la persona de contacto, y cualquier email o teléfono, **se eliminan en el parser** y no hay opción para incluirlos. No obstante, el texto libre de una descripción (`descriptionText`) lo redacta la empresa: si lo activas y encuentras en él datos de contacto, tú decides cómo tratarlos conforme al **RGPD**.
- **No es un producto oficial** ni está afiliado, respaldado o verificado por Greenhouse, Lever, Ashby ni por ninguna de las empresas del catálogo. Not affiliated with, endorsed by or verified by any ATS vendor or listed company.
- **Los datos cambian**: una oferta puede cerrarse o editarse justo después de la extracción. Comprueba siempre la oferta en su `url` antes de actuar.
- Comprueba que tu caso de uso cumple la normativa aplicable (protección de datos, condiciones de los tablones, competencia) antes de redistribuir los datos.

### Europe jobs scraper FAQ · Preguntas frecuentes

#### ¿Qué empresas cubre? · Which companies are covered?

Las del catálogo incluido en el actor: hoy 244 empresas de 21 países europeos, 23 de ellas con sede en España, que publican en Greenhouse, Lever o Ashby. El catálogo se amplía con el tiempo, pero no se garantiza ninguna empresa concreta fuera de la lista. No cubre todas las empresas de un país ni ofertas publicadas en otros sistemas. Con `countries` y `companies` eliges cuáles lees; por ejemplo, `{ "companies": ["typeform", "cabify"] }` lee solo esas dos.

#### ¿Cómo recibo solo las ofertas nuevas? · How do I get only new postings?

`mode: "delta"`: la primera ejecución (sin foto previa) devuelve todo como `added`; desde la segunda recibes solo los `added` y `removed` respecto a la anterior, siempre con los mismos filtros. Si quieres una foto de partida sin ese volcado inicial, lanza antes una ejecución `all` con los mismos filtros.

#### ¿Por qué `descriptionText` sale `null`? · Why is `descriptionText` null?

Porque `includeDescription` está en `false` (valor por defecto). Actívalo si necesitas el texto; ten en cuenta que algunas respuestas pesan varios MB. It is off by default because some responses weigh several MB.

#### ¿Puedo buscar por ciudad o por tipo de contrato?

No hay filtro específico: `keywords` mira solo el título. Puedes filtrar después sobre `location` o `employmentType` en tu propio flujo, sabiendo que son texto libre del ATS.

#### ¿`remote` indica si el puesto es en remoto?

Solo cuando el ATS lo declara de forma explícita; si no, es `null`. No se deduce del texto de la ubicación.

#### ¿Incluye datos del reclutador? · Does it include recruiter data?

No. Se descartan siempre. Recruiter and contact details are always dropped.

### Support and feedback · Soporte y sugerencias

¿Falta una empresa en el catálogo, un campo o un filtro? Abre un *issue* desde la pestaña **Issues** de esta ficha.

Missing a company, a field or a filter? Open an issue from the **Issues** tab.

**Palabras clave / Keywords**: Europe jobs scraper, Greenhouse scraper, Lever scraper, Ashby scraper, job postings dataset, ofertas de empleo Europa, company career pages, ATS job boards, new job alerts, hiring signals, empleo España.

# Actor input Schema

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

Keep only companies of the built-in catalog whose headquarters are in these countries, as ISO 3166-1 alpha-2 codes (for example ES, DE, FR). Empty = all countries in the catalog. Ignored when 'Companies' is set. / ES: códigos ISO de dos letras del país sede; vacío = todo el catálogo; se ignora si indicas empresas.

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

Company slugs from the built-in catalog (for example typeform, cabify, wallapop, jetbrains). Empty = every company that matches the other filters. When set, 'Countries' is ignored; slugs not in the catalog are skipped. / ES: slugs del catálogo (por ejemplo typeform, cabify); vacío = todas; si se indican, se ignoran los países.

## `ats` (type: `array`):

Which applicant tracking systems to read: greenhouse, lever, ashby. Default: all three. / ES: sistemas de selección a leer; por defecto los tres.

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

Keep only postings whose job title contains at least one of these terms (case-insensitive substring match on the title only, not on the description). Empty = no text filter. / ES: coincidencia sin mayúsculas solo en el título; vacío = sin filtro.

## `mode` (type: `string`):

'all' returns every posting that matches the filters. 'delta' returns only the postings added or removed since the previous run with the same filters (marked in the 'change' field). / ES: 'all' = todas las ofertas; 'delta' = solo altas y bajas desde la última ejecución con los mismos filtros.

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

OFF BY DEFAULT. Adds the job description as plain text (up to 20,000 characters) in 'descriptionText'. Some boards return several MB per company when descriptions are included, so runs get slower and datasets much larger. / ES: desactivado por defecto; algunas respuestas pesan varios MB por empresa.

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

Hard cap on the number of items saved to the dataset. The Actor stops cleanly when it is reached. 0 = no limit. / ES: tope de items del dataset; 0 = sin límite.

## Actor input object example

```json
{
  "countries": [
    "ES"
  ],
  "companies": [
    "typeform",
    "cabify"
  ],
  "ats": [
    "greenhouse",
    "lever",
    "ashby"
  ],
  "keywords": [
    "engineer",
    "data"
  ],
  "mode": "all",
  "includeDescription": false,
  "maxItems": 100
}
```

# Actor output Schema

## `results` (type: `string`):

Normalized job postings in the default dataset (JSON, CSV, Excel). / Ofertas normalizadas en el dataset por defecto.

# 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 = {
    "countries": [
        "ES"
    ],
    "companies": [
        "typeform",
        "cabify"
    ],
    "ats": [
        "greenhouse",
        "lever",
        "ashby"
    ],
    "keywords": [
        "engineer",
        "data"
    ],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("xamto1987/europe-jobs-ats").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 = {
    "countries": ["ES"],
    "companies": [
        "typeform",
        "cabify",
    ],
    "ats": [
        "greenhouse",
        "lever",
        "ashby",
    ],
    "keywords": [
        "engineer",
        "data",
    ],
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("xamto1987/europe-jobs-ats").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 '{
  "countries": [
    "ES"
  ],
  "companies": [
    "typeform",
    "cabify"
  ],
  "ats": [
    "greenhouse",
    "lever",
    "ashby"
  ],
  "keywords": [
    "engineer",
    "data"
  ],
  "maxItems": 100
}' |
apify call xamto1987/europe-jobs-ats --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,xamto1987/europe-jobs-ats"
        }
    }
}
```

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/I9J2nfrius6H1E26c/builds/ODN3rudhLbeBybv2P/openapi.json
