# Welcome to the Jungle Jobs Scraper | WTTJ API & New Job Feed (`data_daemon/welcome-to-the-jungle-jobs-scraper`) Actor

$0.80 per 1,000 jobs, full descriptions included | France-focused public Welcome to the Jungle board, including postings abroad. Filter by country, contract or remote mode. Persistent only-new feed and skip IDs. JSON, CSV, Excel, REST and MCP.

- **URL**: https://apify.com/data_daemon/welcome-to-the-jungle-jobs-scraper.md
- **Developed by:** [Daemon Data](https://apify.com/data_daemon) (community)
- **Categories:** Jobs, Lead generation, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.56 / 1,000 jobs

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

### What does the Welcome to the Jungle Jobs Scraper do?

Export public **Welcome to the Jungle (WTTJ) jobs** as JSON, CSV or Excel, with full descriptions, company profiles, office locations, remote arrangements and salary information when disclosed. Use keywords, countries, contract types or company slugs, or keep a persistent **only-new jobs feed** for a recruiting database, research workflow or job board.

Source: [Welcome to the Jungle](https://www.welcometothejungle.com/en/jobs). Apify provides REST access, exports, optional scheduling, integrations and run monitoring.

**$0.80 per 1,000 delivered jobs, full descriptions included, plus $0.001 per run** on Free/Starter plans. Jobs skipped by only-new memory, explicit IDs, duplicate keywords or filters are not charged. No source account, cookies or proxy configuration needed.

### Coverage

This Actor reads the **France-focused public WTTJ job board**, including its postings in other countries. It does not cover the separate Otta/US/UK personalized matching inventory. A public `python` search returned 1,673 matches on 23 October 2026; inventory changes continuously.

The source exposes at most **1,000 accessible hits per search**. A broad query cannot be exported beyond that window by increasing limits. Split searches using country, company, contract, language or remote filters. City and posting-date filters are checked locally within that window. Results follow source relevance order, not a guaranteed newest-first order.

### Quick start

Click **Try for free**, then **Start**. Empty input `{}` searches `python` and saves up to 20 jobs with descriptions. At the base rate, 20 jobs cost **$0.017** including the run start.

```json
{
  "queries": ["python", "data engineer"],
  "countryCodes": ["FR"],
  "contractTypes": ["FULL_TIME"],
  "maxJobsPerQuery": 50,
  "maxJobs": 100
}
```

Use the **Output** tab to export JSON, CSV or Excel. The run's key-value store contains `RUN-SUMMARY` with match counts, pages read, delivered and skipped counts, and any stopping limit.

### Useful searches

Ready-to-run examples: [full-time Python jobs in France](https://apify.com/data_daemon/welcome-to-the-jungle-jobs-scraper/examples/wttj-python-full-time-france-json), [fully remote Python jobs](https://apify.com/data_daemon/welcome-to-the-jungle-jobs-scraper/examples/wttj-fully-remote-python-jobs-json), and [Webnet company vacancies](https://apify.com/data_daemon/welcome-to-the-jungle-jobs-scraper/examples/wttj-webnet-python-company-jobs-api).

Fully remote Python jobs on the public board:

```json
{ "queries": ["python"], "remoteModes": ["fulltime"], "maxJobs": 20 }
```

Python vacancies from a particular employer:

```json
{ "queries": ["python"], "companySlugs": ["webnet"], "maxJobs": 20 }
```

An internship search in Paris:

```json
{
  "queries": ["data"],
  "countryCodes": ["FR"],
  "locations": ["Paris"],
  "contractTypes": ["INTERNSHIP"],
  "maxJobs": 20
}
```

### Only-new job feeds

```json
{
  "queries": ["python"],
  "countryCodes": ["FR"],
  "onlyNewSinceLastRun": true,
  "stateName": "fr-python-feed",
  "maxJobsPerQuery": 100,
  "maxJobs": 100
}
```

Run this input again to receive jobs not previously delivered to that feed. Apify schedules and webhooks can connect it to your own database or workflow. Scheduling is optional and must be configured by you.

The first run delivers a capped baseline. Subsequent runs can deliver older unseen jobs left behind by that cap; “new” means **not delivered to this feed**, not necessarily newly published. Add `postedWithinDays` if you need a recent posting window. Republishing an existing job ID does not make it new. Updated descriptions are not re-emitted.

Memory is kept in your account's named `wttj-jobs-state` key-value store, separated by a hash of `stateName`. Without a name, the search filters determine the memory key. Changing delivery limits does not reset memory. Only delivered IDs are remembered, for 120 days and up to 50,000 IDs per feed. Names are shared across your tasks; use separate names for independent feeds and avoid overlapping runs using the same name.

To exclude records already in an external database, send `skipJobIds` with output `id`, `sourceId` or `dedupKey` values. These exclusions happen before detail requests and charging.

### Input

| Field                              | Meaning                                                                                             |
| ---------------------------------- | --------------------------------------------------------------------------------------------------- |
| `queries`                          | Keyword/title searches; default `["python"]`, maximum 50. `[]` runs no searches.                    |
| `countryCodes`                     | Office country codes such as `FR`, `ES`, `DE`.                                                      |
| `locations`                        | Local substring matches on office city, region or country; accents ignored.                         |
| `contractTypes`                    | `FULL_TIME`, `TEMPORARY`, `INTERNSHIP`, `APPRENTICESHIP`, `FREELANCE`, `VIE`, `PART_TIME`, `OTHER`. |
| `remoteModes`                      | `fulltime`, `partial`, `punctual`, `no`, `unknown`. These are source labels.                        |
| `languages`                        | Posting languages, for example `fr` or `en`.                                                        |
| `companySlugs`                     | Company URL slugs, for example `webnet`.                                                            |
| `salaryCurrency`                   | Optional disclosed currency such as `EUR`; no currency conversion.                                  |
| `postedWithinDays`                 | Last 1–365 days; 0/unset means all dates. Unknown dates are excluded when enabled.                  |
| `includeDescription`               | Default `true`; `false` skips detail requests and returns listing metadata. Same price.             |
| `maxJobsPerQuery`                  | Delivered jobs per keyword, default 20; 0 means up to the 1,000-hit source window.                  |
| `maxJobs`                          | Global cap, default 20; 0 removes this cap. Per-query/source limits remain.                         |
| `skipJobIds`                       | IDs to exclude without charge.                                                                      |
| `onlyNewSinceLastRun`, `stateName` | Enable persistent delivered-ID memory and optionally name the feed.                                 |

Values within one filter group are combined with OR; groups are combined with AND. For example, France or Germany **and** full-time **and** fully remote. A remote designation does not guarantee permission to work from every country.

The API also accepts aliases: `query`/`searchQuery`/`keywords`/`searchTerms`, `countries`/`countryCode`, `location`/`city`, `includeDetails`, `maxItems`/`maxResults`, `onlyNewJobs`/`onlyNew`, `stateKey`/`monitorKey`, and `excludeJobIds`. Canonical fields take precedence. Unknown fields fail early so misspelled filters do not silently produce a broad export.

### Output

One dataset row per delivered job. Missing source information is `null` or an empty list; no salary or company details are inferred.

Simplified example from a public posting checked on 23 October 2026:

```json
{
  "id": "WEBNE_2q66Zp5",
  "dedupKey": "wttj:WEBNE_2q66Zp5",
  "title": "Développeur Python - LLM/RAG H/F - Paris",
  "company": {"name": "Webnet", "slug": "webnet", "employeeCount": 200},
  "url": "https://www.welcometothejungle.com/en/companies/webnet/jobs/developpeur-python-llm-rag-h-f-paris_paris",
  "salary": {"minimum": 45, "maximum": 45, "currency": "EUR", "period": "yearly", "units": "as-provided-by-source"},
  "query": "python"
}
```

The real row includes the full job text and the fields below. Export JSON, CSV or Excel from the dataset.

| Field                                    | Meaning                                                                                                                |
| ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `id`                                     | Public job reference, or source search ID if a reference is absent.                                                    |
| `sourceId`                               | Search index object ID, as a string.                                                                                   |
| `dedupKey`                               | Stable `wttj:` prefix plus job ID, useful in multi-source databases.                                                   |
| `title`, `slug`                          | Job title and public URL slug.                                                                                         |
| `url`, `applyUrl`                        | Canonical public page and external application link when provided.                                                     |
| `company`                                | Public name, slug, reference, website, headcount, size, founding year, logo, industry and headquarters when available. |
| `locations`, `offices`, `countryCodes`   | Office labels, structured city/region/country/coordinates, and country codes.                                          |
| `remoteMode`, `contractType`, `language` | Source remote, contract and posting-language labels.                                                                   |
| `salary`                                 | Minimum, maximum, currency, period and source yearly minimum; all amounts are preserved as provided.                   |
| `experienceLevel`, `educationLevel`      | Source experience and education labels when stated.                                                                    |
| `profession`, `sectors`                  | Public profession label and company sector labels when supplied.                                                       |
| `skills`, `tools`                        | Job skill labels (English when available) and named tools such as Python, when the employer lists them.                |
| `postedAt`, `updatedAt`, `startDate`     | Source dates in ISO format when available.                                                                             |
| `descriptionHtml`, `description`         | Full description as HTML and plain text; null in listing-only mode.                                                    |
| `candidateProfile`, `recruitmentProcess` | Plain-text candidate requirements and interview process when published.                                                |
| `query`                                  | First search keyword that delivered this job.                                                                          |
| `source`, `scrapedAt`                    | Source label and collection timestamp.                                                                                 |

**Salary units need checking.** Some employers enter `45`–`55` where others enter `45000`–`55000`. The Actor preserves those numbers and sets `salary.units` to `as-provided-by-source`. It does not guess a multiplier or produce a normalized salary benchmark. Check the posting before comparing amounts. `yearlyMinimumAsProvided` is also a source value, not a normalization by this Actor.

### Pricing

| Event                               | Free / Starter |    Scale | Business and higher |
| ----------------------------------- | -------------: | -------: | ------------------: |
| Delivered job, description included |        $0.0008 | $0.00068 |            $0.00056 |
| Actor start, once per run           |         $0.001 | $0.00085 |             $0.0007 |

At the base rate, 100 jobs cost $0.081 and 1,000 jobs cost $0.801 in one run. A feed delivering 10 unseen jobs per day for 30 runs costs $0.27. This is a volume illustration, not a forecast of new vacancies. Set Apify's maximum charge per run to control spending; the Actor accounts for the start fee before fetching chargeable details. Platform compute is included in these pay-per-event prices.

Default memory is 512 MB, which incurs one start event. Choosing more than 1 GB of memory multiplies the platform's start-event count.

### API and MCP

Call the Actor from Python, JavaScript, n8n or any HTTP client. Put your Apify token in the Authorization header:

```bash
curl -X POST 'https://api.apify.com/v2/acts/data_daemon~welcome-to-the-jungle-jobs-scraper/run-sync-get-dataset-items' \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"queries":["python"],"countryCodes":["FR"],"maxJobs":20}'
```

Use the Actor from an MCP client through [Apify's MCP server](https://mcp.apify.com/?tools=data_daemon/welcome-to-the-jungle-jobs-scraper). Keep your token in your client's secret settings.

### FAQ

**Does it return full descriptions?** Yes, by default. HTML, plain text, candidate profile and recruitment process come from the public job detail endpoint. Optional fields depend on the employer.

**Does it scrape all WTTJ countries?** It covers jobs on the France-focused public board, including postings abroad. It does not promise the separate US/UK matching product's inventory.

**Why did a broad search stop before every match?** The source limits accessible results to 1,000 per search. Narrow your search filters. A delivery cap, charge cap or run time limit can stop it sooner; inspect `RUN-SUMMARY`.

**Can an empty result mean an outage?** A valid search with no matches succeeds with zero rows. Source HTTP errors and invalid responses fail the run, so an outage is not reported as a valid empty feed. Previously saved rows remain available after a partial failure.

**Are recruiter emails included?** No. The Actor returns public job and company information and does not collect applicant data or private recruiter contact details.

### Related Actors by Daemon Data

- [Instahyre Jobs Scraper](https://apify.com/data_daemon/instahyre-jobs-scraper) — Indian tech jobs with descriptions and only-new feeds.
- [Foundit Jobs Scraper](https://apify.com/data_daemon/foundit-jobs-scraper) — foundit.in / Monster India jobs.
- [IIMJobs Jobs Scraper](https://apify.com/data_daemon/iimjobs-jobs-scraper) — MBA, finance and management jobs.
- [Hirist Jobs Scraper](https://apify.com/data_daemon/hirist-jobs-scraper) — Indian IT vacancies.
- [Oracle HCM Jobs Scraper](https://apify.com/data_daemon/oracle-hcm-jobs-scraper) — employer career sites using Oracle Recruiting Cloud.
- [Luma Events Scraper](https://apify.com/data_daemon/luma-events-scraper) — public events by city or organizer.
- [UK Gazette Insolvency Notices](https://apify.com/data_daemon/uk-gazette-insolvency-notices) — corporate insolvency filings.
- [Dubai Property Transactions](https://apify.com/data_daemon/dubai-property-transactions) — official DLD transaction records.
- [India IPO Tracker](https://apify.com/data_daemon/india-ipo-tracker) — Indian IPO information.
- [Tickertape Stocks Scraper](https://apify.com/data_daemon/tickertape-stocks-scraper) — NSE/BSE stock profiles.

### Support

Open an issue with the input and a public job URL if a field or filter behaves unexpectedly. This Actor is independently maintained by Daemon Data and is not affiliated with Welcome to the Jungle.

# Actor input Schema

## `queries` (type: `array`):

One public WTTJ search per keyword; jobs shared by several searches are delivered once. Default: python. An empty array runs no searches. Maximum 50 searches.

## `countryCodes` (type: `array`):

Optional two-letter office country codes, for example FR, ES or DE. Several values match any of them. Covers the France-focused public WTTJ board, including its jobs abroad; not the separate Otta/US/UK matching inventory.

## `locations` (type: `array`):

Optional case-insensitive substring match on public office city, region or country. Accents are ignored. Several values match any of them. Applied locally within the source search window; use countryCodes to narrow the source search first.

## `contractTypes` (type: `array`):

Optional: FULL_TIME, TEMPORARY, INTERNSHIP, APPRENTICESHIP, FREELANCE, VIE, PART_TIME or OTHER. Several values match any of them; other filter groups are combined with AND.

## `remoteModes` (type: `array`):

Optional: fulltime (fully remote), partial (hybrid), punctual (occasional), no or unknown. Several values match any of them. This is the source designation, not a promise that applicants can work from any country.

## `languages` (type: `array`):

Optional two-letter posting language codes such as fr or en. Several values match any of them.

## `companySlugs` (type: `array`):

Optional company URL slugs, for example webnet or elis-france. Several values match any of them. These must be slugs, not display names.

## `salaryCurrency` (type: `string`):

Optional three-letter currency such as EUR. Filters on disclosed currency, not salary size. Salary numbers are preserved as provided; employers use inconsistent units.

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

Optional 1-365 day posting window; 0 means no date filter. Jobs with unknown dates are excluded when enabled. Applied locally before fetching descriptions.

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

Read each public job detail endpoint for description HTML, plain text, candidate profile, recruitment process and public company metadata. Off returns search listing data only. Same price per delivered job.

## `maxJobsPerQuery` (type: `integer`):

Maximum delivered jobs per keyword, after filters and exclusions. Default 20. 0 means up to the source maximum of 1,000 accessible hits per search. Narrow broad searches with country/company/contract filters.

## `maxJobs` (type: `integer`):

Global delivery cap across keywords. Default 20; 0 removes this cap but the per-keyword and 1,000-hit source windows still apply. Set a maximum charge in Apify for a spending cap.

## `skipJobIds` (type: `array`):

Optional output id, sourceId or dedupKey values. Excluded jobs are skipped before detail requests and are not charged. Suitable for a database or spreadsheet containing jobs you already have.

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

Remember delivered job IDs in a persistent named key-value store. Later runs with the same state name return unseen jobs. Skipped jobs are not charged. First run is a baseline capped by maxJobs; later runs may fill older unseen backlog. Memory expires after 120 days and retains at most 50,000 IDs per feed.

## `stateName` (type: `string`):

Optional stable name for an only-new feed (maximum 120 characters). Same name shares memory across tasks in your account; avoid overlapping runs. Leave empty to derive a name from the search filters. Change the name for a fresh baseline.

## Actor input object example

```json
{
  "queries": [
    "python"
  ],
  "countryCodes": [],
  "locations": [],
  "contractTypes": [],
  "remoteModes": [],
  "languages": [],
  "companySlugs": [],
  "includeDescription": true,
  "maxJobsPerQuery": 20,
  "maxJobs": 20,
  "skipJobIds": [],
  "onlyNewSinceLastRun": false
}
```

# Actor output Schema

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

Jobs as JSON items in the default dataset (also downloadable as CSV, Excel, XML).

## `runSummary` (type: `string`):

RUN-SUMMARY record: keywords, jobs found, new, filtered, skipped (already delivered / skipJobIds) and charged counts.

# 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 = {
    "queries": [
        "python"
    ],
    "countryCodes": [],
    "locations": [],
    "contractTypes": [],
    "remoteModes": [],
    "languages": [],
    "companySlugs": [],
    "skipJobIds": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("data_daemon/welcome-to-the-jungle-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 = {
    "queries": ["python"],
    "countryCodes": [],
    "locations": [],
    "contractTypes": [],
    "remoteModes": [],
    "languages": [],
    "companySlugs": [],
    "skipJobIds": [],
}

# Run the Actor and wait for it to finish
run = client.actor("data_daemon/welcome-to-the-jungle-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 '{
  "queries": [
    "python"
  ],
  "countryCodes": [],
  "locations": [],
  "contractTypes": [],
  "remoteModes": [],
  "languages": [],
  "companySlugs": [],
  "skipJobIds": []
}' |
apify call data_daemon/welcome-to-the-jungle-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,data_daemon/welcome-to-the-jungle-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/rJLnujVhP6ucdnrof/builds/vbht6UZl1aEefhx3l/openapi.json
