# Welcome to the Jungle Scraper — Jobs & Company Profiles (`tortuga/welcome-to-the-jungle-scraper`) Actor

Returns Welcome to the Jungle jobs by keyword, location, filter or URL: title, company, offices, remote, contract, salary, date; optional full description; company profiles (headcount, age, gender).

- **URL**: https://apify.com/tortuga/welcome-to-the-jungle-scraper.md
- **Developed by:** [Trevor Ortega](https://apify.com/tortuga) (community)
- **Categories:** Jobs
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.80 / 1,000 job scrapeds

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

## Welcome to the Jungle Scraper — Jobs & Company Profiles

Scrape job ads and company profiles from **Welcome to the Jungle** (welcometothejungle.com, "WTTJ"), the job and
employer-branding site used across France, Europe, the UK and the US (Otta now redirects to Welcome to the Jungle).
Search by keyword and location with the site's filters (country, contract type, remote policy, experience, minimum
salary, company sector and size, ad language, publish date), or paste any WTTJ search, company or job URL.

For every job you get the title, company (name, logo, headcount, founded year, sectors, labels), every office with
city, region and country, remote policy, contract type and duration, minimum experience, education level, **salary
range with currency and period**, publish date, ad language, summary, key missions, candidate profile, benefits and
job function. Optionally the actor opens each job page for the **full description**, recruitment process, tools
(tech stack), skills, office addresses, apply link and company stats (average age, gender split, revenue).
Company URLs return **company profiles**: description, headcount, founded year, average age, gender split, revenue,
tech stack, offices and headquarters.

No account, no cookies, no browser. Fast: up to 500 jobs per request. Export to JSON, CSV, Excel or use the API.

### What data does the Welcome to the Jungle Scraper return?

| Field | Example | Notes |
|---|---|---|
| `type` | `job` | `job` or `company` |
| `jobId`, `wkReference`, `slug`, `url` | `acc34595-47a5-...`, `BOOND_jPLORqa`, `https://www.welcometothejungle.com/en/companies/boondmanager/jobs/...` | |
| `title` | `Product Marketing Lead, Manager (PMM) - Full Remote` | as written by the employer |
| `companyName`, `companySlug`, `companyUrl`, `companyLogo`, `companySummary` | `Boond`, `boondmanager` | |
| `companyEmployees`, `companyFoundedYear`, `companyLabels`, `companyEqualityIndex` | `100`, `2009`, `["bcorp"]`, `59` | labels: B Corp, Great Place to Work, Happy Trainees ... |
| `sectors`, `sectorGroups` | `["Software", "SaaS / Cloud Services"]`, `["Tech"]` | the company's sectors |
| `jobFunction`, `jobSubFunction`, `jobRole` | `Project / Product Management`, `Product Management`, `Product Manager` | WTTJ's job classification |
| `city`, `state`, `country`, `countryCode`, `offices` | `Lyon`, `Auvergne-Rhone-Alpes`, `France`, `FR` | `offices` lists every location of the ad |
| `latitude`, `longitude` | `45.75917`, `4.82965` | single-office jobs (details give coordinates per office) |
| `remote`, `remotePolicy` | `partial`, `Hybrid (regular remote days)` | `fulltime`, `partial`, `punctual`, `no`; null when the ad does not say |
| `contractType`, `contractTypeLabel`, `contractDurationMinMonths`, `contractDurationMaxMonths` | `internship`, `Internship`, `6`, `6` | |
| `experienceMinYears`, `educationLevel`, `educationLevelLabel` | `3`, `bac_5`, `Bac +5 (master's degree)` | |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`, `salaryYearlyMin` | `60000`, `75000`, `EUR`, `yearly`, `60000` | when the employer shows a salary (about 40% of ads) |
| `publishedAt`, `language` | `2026-10-02T09:06:32Z`, `fr` | language the ad is written in |
| `summary`, `keyMissions`, `profile`, `benefits` | | short summary, main missions, who they look for, perks |
| `isSponsored` | `false` | boosted (paid) ad |
| `searchKeyword`, `searchLocation`, `searchUrl`, `scrapedAt`, `detailsFetched` | | where and when the job was found |
| `description`, `descriptionHtml`, `profileHtml`, `recruitmentProcess` | | with **Include full job description** |
| `tools`, `skills`, `experienceLevel`, `startDate`, `applyUrl`, `status`, `updatedAt` | `["Python", "AWS"]`, `["Team management"]`, `7_TO_10_YEARS` | with details; `applyUrl` = the employer's own application page when there is one |
| `officeAddresses` | `[{"address": "6 Rue de Porstrein, 29200 Brest, France", "zipCode": "29200", ...}]` | with details |
| `companyDescription`, `companyIndustry`, `companyAverageAge`, `companyWomenPercent`, `companyMenPercent`, `companyRevenue`, `companyWebsite`, `companyHeadquarters`, `companyLinkedin` | `35`, `34`, `66`, `12M€` | with details, when the company publishes them |
| `changeType`, `previousValues` | `new` | only with **Only new or changed items** |

Company profiles (`type: "company"`, from company URLs): `companyName`, `companySlug`, `companyUrl`, `logo`,
`coverImage`, `website`, `description`, `lookingFor`, `goodToKnow`, `quote`, `sectors`, `employees`, `sizeLabel`,
`foundedYear`, `averageAge`, `womenPercent`, `menPercent`, `revenue`, `turnoverPercent`, `equalityIndex`,
`techStack` (`[{"category": "backend", "name": "Python"}, ...]`), `offices` (address, zip code, coordinates,
headquarters flag), `headquarters`, `labels`, `socialNetworks`, `openJobs`.

### How to scrape Welcome to the Jungle jobs

1. Enter one or more **Keywords** (job title, skill or company) and a **Location** such as `Paris`, `Lyon`,
   `London`, `New York`, `Île-de-France` or `Germany`. Cities are searched within 20 km like on the site (change it
   with **Radius**).
2. Optionally set filters: countries, contract type (CDI, internship, apprenticeship, freelance ...), remote policy,
   experience, minimum yearly salary and currency, company sector, company size, ad language, published in the last
   N days, sort by newest.
3. Set **Max results** and run.

```json
{
  "keywords": ["data analyst", "data engineer"],
  "location": "Paris",
  "contractTypes": ["full_time"],
  "remote": ["partial", "fulltime"],
  "minSalary": 45000,
  "postedWithinDays": 30,
  "maxItems": 500
}
```

You can also paste Welcome to the Jungle URLs into **Start URLs**: job searches with filters set on the site (any
language version), a company's job list, single job pages (returned with full details) and company pages (returned
as company profiles):

```json
{
  "startUrls": [
    { "url": "https://www.welcometothejungle.com/fr/jobs?query=marketing&refinementList%5Bcontract_type%5D%5B%5D=internship&refinementList%5Boffices.country_code%5D%5B%5D=FR" },
    { "url": "https://www.welcometothejungle.com/en/companies/doctolib/jobs" },
    { "url": "https://www.welcometothejungle.com/en/companies/zoox/jobs/senior-software-engineer-continuous-integration_foster-city-ca_k24zmkun" }
  ],
  "maxItems": 300
}
```

#### Output example

```json
{
  "type": "job",
  "jobId": "acc34595-47a5-4b30-8520-e3d507c56b77",
  "title": "Product Marketing Lead, Manager (PMM) - Full Remote",
  "url": "https://www.welcometothejungle.com/en/companies/boondmanager/jobs/product-marketing-lead-manager-pmm-full-remote_BOOND_jPLORqa",
  "companyName": "Boond",
  "companyEmployees": 100,
  "companyFoundedYear": 2009,
  "sectors": ["Software", "SaaS / Cloud Services"],
  "jobRole": "Product Manager",
  "city": "Barcelona",
  "countryCode": "ES",
  "remote": "fulltime",
  "remotePolicy": "Full remote",
  "contractType": "full_time",
  "experienceMinYears": 7,
  "salaryMin": 60000,
  "salaryMax": 75000,
  "salaryCurrency": "EUR",
  "salaryPeriod": "yearly",
  "publishedAt": "2026-10-02T09:06:32Z",
  "language": "fr",
  "keyMissions": ["Définir le discours de l'entreprise, analyser le marché ..."],
  "benefits": ["Open to full remote", "Generous PTO", "Remote work allowance"],
  "detailsFetched": true,
  "description": "Pourquoi nous recrutons : On crée notre tout premier poste de Lead PMM ! ...",
  "skills": ["Competitive analysis", "Market analysis", "Team management"],
  "startDate": "2026-10-04T22:00:00Z",
  "companyAverageAge": 35,
  "companyWomenPercent": 34,
  "companyMenPercent": 66,
  "companyRevenue": "12M€",
  "companyWebsite": "https://www.boondmanager.com"
}
```

### How many jobs can I get per search?

Welcome to the Jungle's search shows at most **1,000 results for any one query**. When you ask for more, the actor
reads the search newest first in windows of 1,000 (each window starts where the previous one ended), so it returns
**every matching job** with no gaps and no duplicates. In a test, 5,000 of the 7,127 internships in France were read
in 12 requests and about 100 seconds. The whole site has about 90,000 open jobs.

### How to scrape Welcome to the Jungle company profiles

Put company pages in **Start URLs**, e.g. `https://www.welcometothejungle.com/en/companies/doctolib`. Each company
becomes one item with its presentation texts, headcount, founded year, average age, gender split, revenue and
turnover (when the company publishes them), gender-equality index, tech stack, offices with addresses and
headquarters, sectors, labels, social networks and number of open jobs. Add `/jobs` to a company URL to get all its
open jobs instead.

### Can I get the full job description?

Yes. Turn on **Include full job description**. The search results already contain the summary, key missions,
candidate profile and benefits; the job page adds the full description (text and HTML), the recruitment process,
tools and skills, office addresses with zip codes, the start date, the employer's own apply link (for about half of
the ads) and the company's average age, gender split, revenue and website. It is one extra request per job. Single
job URLs in Start URLs always come with details.

### Does it work without login? Is a proxy needed?

It works without any login or cookies. It reads the same public search index and job pages that the website loads
in your browser, and Apify's datacenter proxy (the default) works; no residential proxy is needed. The logged-in
matching app (formerly Otta) is not used; its public jobs are on welcometothejungle.com and included.

### Monitor changes on a schedule

Turn on **Only new or changed items** to watch a search: each run remembers what earlier runs returned and outputs
only jobs that are new or whose title or salary changed. Unchanged jobs are dropped before any job page is opened,
so they are not charged. **Max results** then sets how many jobs are checked per run; sort by newest so the latest
jobs land in that window. Save the input as a task and add a Schedule in Apify (for example daily); give each watch
its own **Monitoring key** if several schedules use the same search. Every output item has `changeType` (`new` or
`changed`), and changed jobs have `previousValues` with the old values, e.g. `{"salaryMax": 55000}`.

### Pricing

Pay per item: **$0.0018 per job** ($1.80 per 1,000). With **Include full job description** (or for a job URL) each
job adds a **$0.0006 detail** event, so $2.40 per 1,000 jobs with full descriptions. A company profile is
**$0.0025**. No start fee and no subscription.

### Proxy note and cost

The actor runs on Apify's datacenter proxy by default. A search request returns up to 500 jobs (about 4 KB each);
a job page is about 35 KB. Measured platform usage (compute, storage) is about **$0.005 per 1,000 jobs** without
details and about $0.015 per 1,000 with details, on top of the per-item price. Requests that fail or come back
blocked are retried automatically on a new IP.

### Is it legal to scrape Welcome to the Jungle?

The actor reads only public job ads and company pages that anyone can open on Welcome to the Jungle without an
account: what employers publish about their jobs and themselves, including salary ranges and company statistics. It
does not log in and does not collect candidates' data. Some descriptions or company pages name a recruiter or an
employee; that is part of the public page. You are responsible for using the data in line with Welcome to the
Jungle's terms and the privacy laws that apply to you (for example GDPR when you process personal data).

# Actor input Schema

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

One search per keyword, e.g. "data analyst", "product manager", "python", "stage marketing". Leave empty to list every job matching the location and filters.

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

A city, region or country as you would type it on Welcome to the Jungle: "Paris", "Lyon", "London", "New York", "Île-de-France", "Germany". Cities are searched within the radius below (20 km by default, like the site). Leave empty for everywhere.

## `radiusKm` (type: `integer`):

Search radius around the location when it is a city. The site offers 5, 10, 20, 50 and 100 km; default 20.

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

Only jobs with an office in these countries, as two-letter codes: FR, US, GB, CA, DE, ES, IE, NL, IT, BE, CH, LU, PT ... Several = any of them. Also used to pick the right place when a location name exists in several countries.

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

Only these contract types. Several = any of them. "Full-Time" is WTTJ's permanent contract (CDI in France).

## `remote` (type: `array`):

Only jobs with this remote-work policy. Several = any of them. Many ads do not state one.

## `experienceLevels` (type: `array`):

Minimum years of experience asked in the ad. Several = any of them.

## `minSalary` (type: `integer`):

Only jobs that show a salary whose yearly minimum is at least this much (in the job's currency), e.g. 45000. Jobs without a salary are left out.

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

Only jobs whose salary is shown in this currency.

## `sectors` (type: `array`):

Only jobs at companies in these sectors (WTTJ's sector groups). Several = any of them.

## `companySizes` (type: `array`):

Only jobs at companies of this size. Several = any of them.

## `jobLanguages` (type: `array`):

Only ads written in these languages. Several = any of them.

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

Only jobs published within this many days, e.g. 1, 7 or 30.

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

Relevance (the site's default) or newest first. Searches that need more than 1,000 results are read newest first (the site's search shows at most 1,000 per query).

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

Optional. Job search URLs with filters set on the site (https://www.welcometothejungle.com/fr/jobs?query=data\&refinementList%5Bcontract_type%5D%5B%5D=internship), company pages for a company profile (https://www.welcometothejungle.com/en/companies/doctolib), company job lists (.../companies/doctolib/jobs) or single job pages (.../companies/doctolib/jobs/<job>).

## `includeDetails` (type: `boolean`):

Open each job for the full description (text and HTML), recruitment process, tools / tech stack, skills, office addresses, apply link and company stats (average age, gender split, revenue, website). One extra request and one 'detail' event per job. Job URLs in Start URLs always include it.

## `siteLanguage` (type: `string`):

Language of the site version used for job URLs and for sector, job function and benefit names. Job ads keep the language they were written in.

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

Stop after this many jobs and company profiles in total (you pay per item saved).

## `maxItemsPerSearch` (type: `integer`):

Optional cap for each keyword / start URL, so one search does not use the whole Max results budget.

## `onlyNewOrChanged` (type: `boolean`):

Remember what earlier runs of this search returned and output only new jobs or jobs whose title or salary changed. Use with a Schedule; unchanged jobs are not charged. With this on, Max results is the number of jobs checked per run (the watch window).

## `monitoringKey` (type: `string`):

Name for this watch, so several schedules on the same search stay separate; defaults to a key derived from the search input

## `proxyConfiguration` (type: `object`):

Apify datacenter proxy (the default) works: the search and job APIs do not block it. A search request returns up to 500 jobs (about 4 KB per job); job details are about 35 KB each.

## Actor input object example

```json
{
  "keywords": [
    "data analyst"
  ],
  "location": "Paris",
  "sortBy": "relevance",
  "includeDetails": false,
  "siteLanguage": "en",
  "maxItems": 100,
  "onlyNewOrChanged": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "keywords": [
        "data analyst"
    ],
    "location": "Paris",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tortuga/welcome-to-the-jungle-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 = {
    "keywords": ["data analyst"],
    "location": "Paris",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("tortuga/welcome-to-the-jungle-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 '{
  "keywords": [
    "data analyst"
  ],
  "location": "Paris",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call tortuga/welcome-to-the-jungle-scraper --silent --output-dataset

```

## MCP server setup

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