# Just Join IT Scraper (`trev0n/justjoinit-scraper`) Actor

Fast IT job scraper for JustJoin.it. Extract salaries, tech stacks, experience levels, remote options. Supports keyword, location, category filters. Up to 100 offers per request.

- **URL**: https://apify.com/trev0n/justjoinit-scraper.md
- **Developed by:** [Paweł](https://apify.com/trev0n) (community)
- **Categories:** Automation, Jobs, Developer tools
- **Stats:** 72 total users, 17 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

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

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

## Just Join IT Scraper

Fast and efficient Apify Actor for scraping IT job listings from [JustJoin.it](https://justjoin.it) -- Poland's and Central Europe's leading IT job board.

### Features

- Scrapes every matching offer -- automatically pages through the full result set (hundreds or thousands of offers, not just the first page)
- Comprehensive job data: title, company, salary (min/max/currency/type), location, experience level, required skills, workplace type, and more
- All salary information broken down into structured fields (min, max, currency, contract type, gross/net)
- Multiple employment type salary variants per offer (B2B, permanent, converted currencies)
- Filter by: keyword, location, technology category, experience level, employment type, workplace type, salary availability
- Optional full detail extraction: visits each job page for description, skill levels, languages, company size
- Built-in deduplication, session rotation, and proxy support
- Three dataset views: Overview, Detailed, and Salaries

### How It Works

1. You set filters (keyword, location, category, experience, salary, etc.) or paste JustJoin.it URLs
2. The scraper pages through every matching offer and returns clean, structured data -- no browser, fast and lightweight
3. Optionally enriches each offer with the full description, skill levels, languages, and company size

### Input Parameters

| Parameter              | Type    | Default         | Description                                            |
| ---------------------- | ------- | --------------- | ------------------------------------------------------ |
| `startUrls`            | Array   | `[]`            | Direct JustJoin.it URLs to scrape (overrides filters)  |
| `keyword`              | String  | -               | Search keyword (e.g., "React", "DevOps")               |
| `location`             | String  | `all-locations` | City name (e.g., "warszawa", "krakow")                 |
| `category`             | String  | -               | Technology category (javascript, python, devops, etc.) |
| `experienceLevel`      | Array   | `[]`            | Filter: junior, mid, senior, lead                      |
| `employmentType`       | Array   | `[]`            | Filter: b2b, permanent, mandate\_contract               |
| `workplaceType`        | Array   | `[]`            | Filter: remote, hybrid, office                         |
| `withSalary`           | Boolean | `false`         | Only return offers with salary disclosed               |
| `sortBy`               | String  | `published`     | Sort by: published, salary                             |
| `maxItems`             | Integer | `100`           | Max offers to scrape (0 = unlimited)                   |
| `extractFullDetails`   | Boolean | `false`         | Visit each job page for full description               |
| `maxConcurrency`       | Integer | `10`            | Max parallel requests                                  |
| `maxRequestsPerMinute` | Integer | `300`           | Rate limiting                                          |
| `proxyConfiguration`   | Object  | -               | Proxy settings (recommended for extractFullDetails)    |

#### Input Example

```json
{
    "keyword": "React",
    "location": "warszawa",
    "category": "javascript",
    "experienceLevel": ["senior", "mid"],
    "employmentType": ["b2b"],
    "workplaceType": ["remote", "hybrid"],
    "withSalary": true,
    "maxItems": 50,
    "extractFullDetails": false
}
```

#### Using Start URLs

You can also provide pre-built URLs directly:

```json
{
    "startUrls": [
        "https://justjoin.it/job-offers/all-locations/python?experience-level=senior&with-salary=yes",
        "https://justjoin.it/job-offers/warszawa/javascript?workplace-type=remote"
    ],
    "maxItems": 200
}
```

### Output

#### Default Mode (`extractFullDetails: false`)

Each record contains:

| Field                | Type    | Description                                                          |
| -------------------- | ------- | -------------------------------------------------------------------- |
| `title`              | String  | Job title                                                            |
| `companyName`        | String  | Company name                                                         |
| `companyLogoUrl`     | String  | Company logo image URL                                               |
| `city`               | String  | Primary city                                                         |
| `street`             | String  | Street address                                                       |
| `locations`          | Array   | All locations `[{city, street}]`                                     |
| `salary`             | String  | Human-readable salary (e.g., "24,000 - 33,000 PLN/month (net, b2b)") |
| `salaryMin`          | Number  | Minimum salary (original currency)                                   |
| `salaryMax`          | Number  | Maximum salary (original currency)                                   |
| `salaryCurrency`     | String  | Salary currency (PLN, USD, EUR, etc.)                                |
| `salaryType`         | String  | Contract type for this salary (b2b, permanent, etc.)                 |
| `salaryUnit`         | String  | Pay unit (month, hour)                                               |
| `salaryGross`        | Boolean | Whether salary is gross (true) or net (false)                        |
| `allEmploymentTypes` | Array   | All salary variants `[{from, to, currency, type, unit, gross}]`      |
| `experienceLevel`    | String  | Experience level (junior, mid, senior, lead)                         |
| `workplaceType`      | String  | Workplace type (remote, hybrid, office)                              |
| `workingTime`        | String  | Working time (full\_time, part\_time)                                  |
| `requiredSkills`     | Array   | Required technology skills                                           |
| `niceToHaveSkills`   | Array   | Nice-to-have skills                                                  |
| `remoteInterview`    | Boolean | Remote interview available                                           |
| `isPromoted`         | Boolean | Promoted/featured listing                                            |
| `isSuperOffer`       | Boolean | Super offer badge                                                    |
| `publishedAt`        | String  | ISO 8601 publish date                                                |
| `lastPublishedAt`    | String  | ISO 8601 last republish date                                         |
| `expiredAt`          | String  | ISO 8601 expiration date                                             |
| `slug`               | String  | URL slug identifier                                                  |
| `jobUrl`             | String  | Direct URL to job offer                                              |
| `guid`               | String  | Unique offer identifier                                              |
| `scrapedAt`          | String  | ISO 8601 scrape timestamp                                            |

#### Full Details Mode (`extractFullDetails: true`)

Additional fields when visiting each job page:

| Field                      | Type   | Description                                      |
| -------------------------- | ------ | ------------------------------------------------ |
| `description`              | String | Full job description text                        |
| `companyWebsite`           | String | Company website URL                              |
| `country`                  | String | Country code (e.g., "PL")                        |
| `region`                   | String | Region/state                                     |
| `validThrough`             | String | Offer validity date                              |
| `requiredSkillsDetailed`   | Array  | Skills with proficiency levels `[{name, level}]` |
| `niceToHaveSkillsDetailed` | Array  | Nice-to-have skills with levels                  |
| `languages`                | Array  | Required languages `[{code, level}]`             |
| `companySize`              | String | Company size category                            |
| `countryCode`              | String | ISO country code                                 |

#### Example Output (Default Mode)

```json
{
    "title": "Fullstack Developer (Angular + Python)",
    "companyName": "Code and Pepper",
    "companyLogoUrl": "https://imgproxy.justjoinit.tech/.../logo.png",
    "city": "Gdansk",
    "street": "Aleja Grunwaldzka",
    "locations": [
        { "city": "Gdansk", "street": "Aleja Grunwaldzka" },
        { "city": "Suwalki", "street": null }
    ],
    "salary": "24,000 - 33,000 PLN/month (net, b2b)",
    "salaryMin": 24000,
    "salaryMax": 33000,
    "salaryCurrency": "PLN",
    "salaryType": "b2b",
    "salaryUnit": "month",
    "salaryGross": false,
    "allEmploymentTypes": [
        {
            "from": 24000,
            "to": 33000,
            "currency": "PLN",
            "type": "b2b",
            "unit": "month",
            "gross": false,
            "currencySource": "original"
        },
        {
            "from": 18000,
            "to": 27000,
            "currency": "PLN",
            "type": "permanent",
            "unit": "month",
            "gross": true,
            "currencySource": "original"
        },
        {
            "from": 6402,
            "to": 8803,
            "currency": "USD",
            "type": "b2b",
            "unit": "month",
            "gross": false,
            "currencySource": "conversion"
        }
    ],
    "experienceLevel": "senior",
    "workplaceType": "hybrid",
    "workingTime": "full_time",
    "requiredSkills": ["Angular", "Python", "TypeScript", "REST API"],
    "niceToHaveSkills": [],
    "remoteInterview": true,
    "isPromoted": false,
    "isSuperOffer": false,
    "publishedAt": "2026-03-15T08:00:00.000Z",
    "lastPublishedAt": "2026-03-15T08:00:00.000Z",
    "expiredAt": "2026-04-15T21:59:59.999Z",
    "slug": "code-and-pepper-fullstack-developer-angular-python--gdansk-javascript",
    "jobUrl": "https://justjoin.it/job-offer/code-and-pepper-fullstack-developer-angular-python--gdansk-javascript",
    "guid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "scrapedAt": "2026-03-16T12:00:00.000Z"
}
```

#### Example Output (Full Details Mode)

Includes all fields above plus:

```json
{
    "description": "We are looking for a Senior Fullstack Developer with strong Angular and Python skills to join our product team...",
    "companyWebsite": "https://codeandpepper.com/",
    "country": "PL",
    "region": "Pomorskie",
    "validThrough": "2026-04-15T21:59:59.999Z",
    "requiredSkillsDetailed": [
        { "name": "Angular", "level": 4 },
        { "name": "Python", "level": 4 },
        { "name": "TypeScript", "level": 3 },
        { "name": "REST API", "level": 3 }
    ],
    "languages": [{ "code": "en", "level": "B2" }],
    "countryCode": "PL"
}
```

### Available Technology Categories

| Slug           | Name               |
| -------------- | ------------------ |
| `javascript`   | JavaScript         |
| `html`         | HTML               |
| `php`          | PHP                |
| `ruby`         | Ruby               |
| `python`       | Python             |
| `java`         | Java               |
| `net`          | .NET               |
| `scala`        | Scala              |
| `c`            | C                  |
| `mobile`       | Mobile             |
| `testing`      | Testing/QA         |
| `devops`       | DevOps             |
| `admin`        | Admin/IT           |
| `ux`           | UX/UI              |
| `pm`           | Project Management |
| `game`         | Game Dev           |
| `analytics`    | Analytics          |
| `security`     | Security           |
| `data`         | Data               |
| `go`           | Go                 |
| `support`      | Support            |
| `erp`          | ERP                |
| `architecture` | Architecture       |
| `ai`           | AI/ML              |

### Performance and Cost

#### Default Mode (`extractFullDetails: false`)

- **Speed**: Very fast -- fetches 100 offers per page and pages through the whole result set
- **Cost**: Minimal -- lightweight structured data, no browser
- **Proxy**: Optional, works without proxies in most cases
- **Recommended for**: Most use cases, salary analysis, market research

#### Full Details Mode (`extractFullDetails: true`)

- **Speed**: Slower -- fetches one extra page per offer for the full description
- **Cost**: Higher -- one extra fetch per offer on top of the listing pages
- **Proxy**: Recommended to avoid rate limiting
- **Recommended for**: When you need full job descriptions, skill proficiency levels, or language requirements

### URL Filter Reference

JustJoin.it URL structure:

```
https://justjoin.it/job-offers/{location}/{category}?{filters}
```

#### Query Parameters

| Parameter          | Values                           | Example                         |
| ------------------ | -------------------------------- | ------------------------------- |
| `experience-level` | junior, mid, senior, lead        | `?experience-level=senior,mid`  |
| `employment-type`  | b2b, permanent, mandate\_contract | `?employment-type=b2b`          |
| `workplace-type`   | remote, hybrid, office           | `?workplace-type=remote,hybrid` |
| `with-salary`      | yes                              | `?with-salary=yes`              |
| `keyword`          | any string                       | `?keyword=React`                |
| `orderBy`          | DESC                             | `?orderBy=DESC`                 |
| `sortBy`           | published, salary                | `?sortBy=published`             |

#### Example URLs

```
## All remote senior Python jobs with salary
https://justjoin.it/job-offers/all-locations/python?experience-level=senior&workplace-type=remote&with-salary=yes

## B2B JavaScript jobs in Warsaw
https://justjoin.it/job-offers/warszawa/javascript?employment-type=b2b

## All DevOps jobs sorted by salary
https://justjoin.it/job-offers/all-locations/devops?with-salary=yes&sortBy=salary&orderBy=DESC
```

# Actor input Schema

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

List of JustJoin.it URLs to scrape. Can be search result URLs with filters or direct job offer URLs. If provided, keyword and filter settings are ignored.

## `keyword` (type: `string`):

Job search keyword (e.g., 'React Developer', 'DevOps', 'Python'). Used only if startUrls is not provided.

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

City name (e.g., 'warszawa', 'krakow', 'wroclaw', 'gdansk'). Use 'all-locations' for all. Used only if startUrls is not provided.

## `category` (type: `string`):

Filter by technology/role category.

## `experienceLevel` (type: `array`):

Filter by experience level. Accepts: 'junior', 'mid', 'senior', 'lead'.

## `employmentType` (type: `array`):

Filter by employment type. Accepts: 'b2b', 'permanent', 'mandate\_contract', 'internship'.

## `workplaceType` (type: `array`):

Filter by workplace type. Accepts: 'remote', 'hybrid', 'office'.

## `withSalary` (type: `boolean`):

If enabled, only returns job offers that have salary information disclosed.

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

How to sort the results.

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

Maximum number of job listings to scrape (0 = unlimited). The scraper pages through all matching offers automatically.

## `extractFullDetails` (type: `boolean`):

When enabled, visits each job detail page to extract full description, skill levels, languages, and company info. Slower but more comprehensive. Recommended to use with proxy when enabled.

## `maxConcurrency` (type: `integer`):

Maximum number of parallel requests (1-100).

## `minConcurrency` (type: `integer`):

Minimum number of parallel requests (1-100).

## `maxRequestRetries` (type: `integer`):

Maximum number of retries for failed requests.

## `maxRequestsPerMinute` (type: `integer`):

Maximum number of requests per minute.

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

Proxy settings for the scraper. Optional for listing pages, recommended when extractFullDetails is enabled.

## Actor input object example

```json
{
  "location": "all-locations",
  "category": "",
  "withSalary": false,
  "sortBy": "published",
  "maxItems": 100,
  "extractFullDetails": false,
  "maxConcurrency": 10,
  "minConcurrency": 1,
  "maxRequestRetries": 3,
  "maxRequestsPerMinute": 300
}
```

# Actor output Schema

## `overview` (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("trev0n/justjoinit-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("trev0n/justjoinit-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 '{}' |
apify call trev0n/justjoinit-scraper --silent --output-dataset

```

## MCP server setup

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