# Welcome to the Jungle Scraper 💰 $0.8/1K | Tech Jobs Data (`ahmed_jasarevic/welcometothejungle-scraper`) Actor

Scrape Welcome to the Jungle job listings: title, company, salary range, locations, remote policy, contract type, skills and apply URL. Ideal for recruiters, job aggregators and salary benchmarking.

- **URL**: https://apify.com/ahmed_jasarevic/welcometothejungle-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 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.
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

## Welcome to the Jungle (WTTJ) Jobs Scraper

Scrape job listings from [Welcome to the Jungle](https://www.welcometothejungle.com) — one of Europe's largest tech & startup job boards — and get clean, structured JSON: job title, company (name, size, sectors, logo), salary range, locations, contract type, remote policy, full description and apply URL.

Built for **EU tech recruiters, staffing firms, job aggregators and salary-benchmarking SaaS**.

### Use Cases

- **Tech recruiting & talent sourcing** — pull fresh roles by title, city, country and contract type into your ATS or CRM
- **EU tech job data for aggregators & job boards** — keep a job board or feed continuously updated
- **Salary benchmarking** — extract `salaryMin`/`salaryMax` by role, seniority and market to power compensation tools
- **Hiring & market trends** — track which companies, sectors and cities are hiring over time
- **Lead generation for B2B** — identify fast-growing EU startups by their open roles and sectors
- **Remote job monitoring** — filter for fully-remote and hybrid roles across Europe

### How It Works

WTTJ is a Next.js app whose job list is **not** in the served HTML — the frontend fetches results client-side. This actor reuses that same public surface instead of rendering pages in a browser:

1. **Search index (primary source)** — the job list comes from the public search index the site itself queries. It returns clean JSON, needs no cookies and sits behind no anti-bot challenge, so **no browser, no DOM scraping and no Cloudflare bypass** are required.
2. **Public job detail API (optional enrichment)** — enabled with `fetchDetails`. One extra request per job returns the full description, key missions, what the company looks for, the recruitment process, skills, tools, the ATS and the real external apply URL.
3. **Company index (bulk mode)** — used to list companies with open jobs so the actor can page past the search index's 1,000-records-per-page cap.

The actor is a **pure JSON/API scraper — 256 MB memory, no headless browser**.

### Extract Welcome To The Jungle Job Data Without An Official API

Welcome to the Jungle does **not** publish an official developer API for external job or company data (its API is for employers' own postings). Third-party "WTTJ APIs" are wrappers around this same public surface. This actor reads it directly and returns structured items you can schedule, filter and export — with filters for country, city, contract type, remote policy, sector and language.

### What You Get Per Job

- **Identity** — `jobId`, `reference`, `title`, `url`, `applyUrl`, `status`, `publishedAt`, `updatedAt`, `scrapedAt`
- **Company** — `company`, `companySlug`, `companySize`, `companySizeEmployees`, `companyLogo`, `companyDescription`, `sectors`
- **Location** — `locations` (city, district, state, country, country code)
- **Contract & work** — `contractType`, `contractTypeLabel`, `remotePolicy`, `remotePolicyLabel`, `experienceLevelMin`, `educationLevel`
- **Salary** — `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`, `salaryYearlyMin`, `hasSalary`
- **Detail (when `fetchDetails: true`)** — `description`, `profile`, `keyMissions`, `lookingFor`, `recruitmentProcess`, `companySummary`, `skills`, `tools`, `ats`, `startDate`, `summary`, `companyAssets`

### Input

| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
| `searchQuery` | string | No | — | Keyword(s), e.g. `data engineer`. Empty = all jobs |
| `country` | string | No | — | Office country ISO code, e.g. `FR`, `GB`, `ES`, `DE`, `US` |
| `city` | string | No | — | Office city, e.g. `Paris`, `London`, `Berlin` |
| `contractType` | string | No | — | `FULL_TIME`, `PART_TIME`, `TEMPORARY`, `INTERNSHIP`, `FREELANCE`, `APPRENTICESHIP`, `VIE`, `GRADUATE_PROGRAM`, `VOLUNTEER`, `OTHER` |
| `remote` | string | No | — | `no`, `partial`, `fulltime`, `punctual`, `unknown` |
| `sector` | string | No | — | Company sector (English), e.g. `Tech`, `Banking / Insurance / Finance` |
| `language` | string | No | — | Job posting language, e.g. `fr`, `en` |
| `maxResults` | integer | No | `100` | Max jobs to return (max 10000). Above 1000 switches to bulk mode |
| `fetchDetails` | boolean | No | `false` | Fetch full description / apply URL per job (one extra request per job). **Billed separately** |
| `proxy` | object | No | Apify proxy | Standard Apify proxy configuration |

### Example Input

```json
{
    "searchQuery": "data engineer",
    "country": "FR",
    "contractType": "FULL_TIME",
    "maxResults": 200,
    "fetchDetails": true
}
```

### Example Output

```json
{
    "jobId": "4230652",
    "reference": "EKIM_xxxxx",
    "title": "Senior Data Engineer",
    "company": "Ekimetrics",
    "companySlug": "ekimetrics",
    "companySize": "Between 250 and 2,000 employees",
    "companySizeEmployees": 500,
    "companyLogo": "https://cdn-images.welcometothejungle.com/...",
    "sectors": [{ "name": "Big Data", "parent": "Tech" }],
    "locations": [{ "city": "New York", "state": "New York", "country": "United States", "countryCode": "US" }],
    "contractType": "FULL_TIME",
    "contractTypeLabel": "Full-Time",
    "remotePolicy": "partial",
    "remotePolicyLabel": "Partial remote (hybrid)",
    "experienceLevelMin": 2,
    "educationLevel": "BAC_2",
    "salaryMin": 125000,
    "salaryMax": 140000,
    "salaryCurrency": "USD",
    "salaryPeriod": "yearly",
    "salaryYearlyMin": 125000,
    "hasSalary": true,
    "publishedAt": "2026-10-14T02:00:00.000+02:00",
    "language": "en",
    "url": "https://www.welcometothejungle.com/en/companies/ekimetrics/jobs/senior-data-engineer_new-york",
    "applyUrl": "https://jobs.lever.co/ekimetrics/.../apply?lever-source[]=WTTJ",
    "ats": "external",
    "description": "<p>...</p>",
    "skills": [{ "name": { "en": "Data engineering" } }],
    "tools": [{ "name": "Python" }],
    "status": "published",
    "startDate": "2026-11-01T00:00:00.000Z"
}
```

Fields marked *only when `fetchDetails` is enabled* are `null` otherwise. `profile` (candidate requirements) always comes from the search index.

### Pricing

Runs are billed per result. On top of that, the actor uses Apify's **pay-per-event** model so you only pay for the enrichment you switch on:

| Event | When it fires | What you get |
|---|---|---|
| `job-detail` | Once per job, only when `fetchDetails: true` | Full description, key missions, looking-for, recruitment process, skills, tools, ATS, start date, company perks/key numbers and the real external apply URL |

- `fetchDetails: false` (default) → **no `job-detail` charges at all.**
- The event fires once per detail request, whether or not the source returns the job, so you are never billed twice for the same job.
- Charging happens in batches of 20 as the run progresses and once on graceful shutdown, so an aborted run bills only the work already done.
- The run spending limit (`ACTOR_MAX_TOTAL_CHARGE_USD`) is enforced by the platform: when hit, the actor stops cleanly and stops billing.

### Bulk Mode (More Than 1,000 Results)

The search index only returns the first 1,000 records per query. When `maxResults > 1000`, the actor partitions by company (`organization.slug`) — every job carries one — and pages through the companies that have open jobs. This is slower and uses many more requests, so it is opt-in via `maxResults`.

### Cost & Limits

- Pure HTTP/JSON actor — runs comfortably at **256 MB**.
- Default run: a single search request (up to 1,000 jobs) plus optional detail requests.
- Hard caps: `maxResults` ≤ 10000, search requests ≤ 6000, detail requests ≤ 10000, retries ≤ 3, request timeouts set.
- Free Apify users get a 10-job preview; paying users get the full requested volume.

### Integrations And Automation

- **Apify API** — run from your app and read the dataset.
- **Webhooks** — notify your ATS, CRM or Slack when a run completes.
- **Scheduled runs** — set a **daily** schedule to catch new postings fast, or a **weekly** schedule for trend tracking.
- **Zapier / Make / n8n** — push new roles into Google Sheets, Airtable, Notion or your job board.
- **Export** — JSON, CSV, Excel from the dataset tab.

### Related Actors

- [LinkedIn Jobs Scraper](https://apify.com/curious_coder/linkedin-jobs-scraper) — the largest global job source; pair with WTTJ for full EU coverage
- [Indeed Scraper](https://apify.com/misceres/indeed-scraper) — high-volume general job board data
- [Welcome to the Jungle Jobs Scraper](https://apify.com/clearpath/welcome-to-the-jungle-jobs-api) — an alternative WTTJ actor for cross-checking coverage
- [Glassdoor Scraper](https://apify.com/memo23/glassdoor-scraper) — salary and company-review data to enrich WTTJ results
- [Google Jobs Scraper](https://apify.com/johnvc/google-jobs-scraper) — aggregated listings across many boards

### FAQ

#### Does Welcome to the Jungle have an official API?

Welcome to the Jungle does **not** publish an official developer API for external job or company data (its API is for employers managing their own postings). This actor reads the public search/company surface the site's own frontend uses, so you get the same jobs the website shows — no credentials or employer account needed.

#### Why use this actor instead of a generic job scraper?

It is **WTTJ-specific**: it maps WTTJ's contract types, remote policies, sectors and its multi-location and salary objects into clean fields, and it supports filters (country, city, contract type, remote, sector, language) that generic scrapers do not.

#### How do I get salary data?

Set `fetchDetails: true` and read `salaryMin`, `salaryMax`, `salaryCurrency` and `salaryYearlyMin`. Not every posting publishes a salary — check `hasSalary`.

#### How do I scrape more than 1,000 jobs?

Set `maxResults` above 1000 to switch on **bulk mode**, which partitions by company to page past the 1,000-per-query cap.

#### How do I get the real apply URL?

`applyUrl` is the external ATS link when the company uses one (Lever, Greenhouse, …); otherwise it falls back to the canonical WTTJ job page. Enable `fetchDetails` for the most complete value.

#### Can I filter by remote policy or contract type?

Yes — use the `remote` and `contractType` inputs, plus `country`, `city` and `sector`.

#### Can I export WTTJ job data to CSV or Excel?

Yes — JSON, CSV, Excel and more from the dataset tab or via the API.

### Legal & Compliance Disclaimer

This actor is an independent tool and is **not affiliated with, endorsed by, or sponsored by Welcome to the Jungle**. It accesses only **publicly available** job listings and company data through the site's own public surface; it does not bypass login and does not solve CAPTCHAs.

You are responsible for complying with Welcome to the Jungle's Terms of Service and all applicable laws (including GDPR where the data relates to individuals in the EU). Company and role data should be used in line with applicable data-protection rules.

### For AI Agents & LLM Apps

**Purpose:** returns Welcome to the Jungle job listings (title, company, salary, locations, contract type, remote policy, apply URL) as structured JSON for recruiting, aggregation and salary benchmarking.

**Minimal working input:**

```json
{
    "searchQuery": "data engineer",
    "country": "FR",
    "maxResults": 100
}
```

**Variant — full detail with descriptions and apply URLs:**

```json
{
    "searchQuery": "product manager",
    "country": "GB",
    "contractType": "FULL_TIME",
    "fetchDetails": true,
    "maxResults": 200
}
```

**Variant — bulk mode (more than 1,000 jobs):**

```json
{
    "searchQuery": "",
    "country": "FR",
    "maxResults": 5000
}
```

**Output fields:** `jobId`, `reference`, `title`, `company`, `companySlug`, `companySize`, `companySizeEmployees`, `companyLogo`, `companyDescription`, `sectors`, `locations`, `contractType`, `contractTypeLabel`, `remotePolicy`, `remotePolicyLabel`, `experienceLevelMin`, `educationLevel`, `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`, `salaryYearlyMin`, `hasSalary`, `publishedAt`, `language`, `url`, `applyUrl`, `ats`, `description`, `profile`, `keyMissions`, `lookingFor`, `recruitmentProcess`, `companySummary`, `skills`, `tools`, `status`, `startDate`, `summary`, `companyAssets`, `updatedAt`, `scrapedAt`.

**Behaviors an agent should know:**

- `fetchDetails` defaults to `false`; when false, `description`, `applyUrl`, `keyMissions`, `skills`, `tools`, `ats`, `startDate` and `companyAssets` are `null`/absent. The `profile` field always comes from the search index.
- `fetchDetails: true` fires one billable `job-detail` event **per job**, charged once even if the source returns no detail.
- Setting `maxResults` above **1000** switches the run into **bulk mode** (slower, more requests) that pages past the 1,000-record-per-query cap.
- `maxResults` is capped at 10000; free Apify accounts get a 10-job preview.
- Empty `searchQuery` returns all jobs (subject to other filters).
- Billing: standard run usage plus pay-per-event `job-detail` only when `fetchDetails` is enabled.

### SEO Keywords

welcome to the jungle scraper, wttj scraper, welcometothejungle scraper, welcome to the jungle api, wttj jobs api, welcometothejungle api, scrape welcome to the jungle, tech job board data, french tech jobs data, eu startup jobs data, europe tech job data, tech job scraper, salary benchmarking data, salary data api, recruitment data api, job board scraping, tech hiring trends, job postings dataset, remote tech jobs data, ats apply url, startup hiring data, job market data france, welcometothejungle dataset, jobs api alternative, recruiting lead generation

# Actor input Schema

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

Keyword(s) to search for, e.g. "data engineer" or "product manager". Leave empty to get all jobs.

## `country` (type: `string`):

Filter by office country ISO code, e.g. FR, GB, ES, DE, US.

## `city` (type: `string`):

Filter by office city, e.g. Paris, London, Berlin.

## `contractType` (type: `string`):

Filter by contract type.

## `remote` (type: `string`):

Filter by remote policy.

## `sector` (type: `string`):

Filter by company sector (English name), e.g. Tech, Banking / Insurance / Finance, Consulting / Audit.

## `language` (type: `string`):

Filter by the language the job is posted in, e.g. fr, en, es, de.

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

Maximum number of jobs to return. Values above 1000 switch to bulk mode (partitioned by company) which uses many more requests.

## `fetchDetails` (type: `boolean`):

If enabled, fetch each job's full description, key missions, skills, tools and external apply URL (one extra request per job). Billed per job as a separate pay-per-event charge on top of the results.

## `proxy` (type: `object`):

Select proxies to be used by your crawler.

## Actor input object example

```json
{
  "searchQuery": "data engineer",
  "maxResults": 100,
  "fetchDetails": false,
  "proxy": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (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 = {
    "searchQuery": "data engineer",
    "proxy": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/welcometothejungle-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 = {
    "searchQuery": "data engineer",
    "proxy": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/welcometothejungle-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 '{
  "searchQuery": "data engineer",
  "proxy": {
    "useApifyProxy": false
  }
}' |
apify call ahmed_jasarevic/welcometothejungle-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ahmed_jasarevic/welcometothejungle-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/zs8DC5Uef3kUGdTgo/builds/VOq3BrGpfvNceXeZ9/openapi.json
