JustJoin.it Scraper
Pricing
from $3.00 / 1,000 serp results
JustJoin.it Scraper
Scrape IT jobs from JustJoin.it, Poland's tech job board. Returns title, company, city, tech stack with skill levels, B2B/UoP salaries, remote/hybrid mode, languages, office address and expiry date. Sort by newest. Pay per result.
Pricing
from $3.00 / 1,000 serp results
Rating
0.0
(0)
Developer
NanoScrape
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
20 days ago
Last modified
Categories
Share
JustJoin.it Scraper: Polish & EU Tech Jobs with Salary Data
Extract IT/tech job listings from JustJoin.it, Poland's leading IT job board. Filter by keyword, city, seniority, remote status, and contract type (B2B/UoP).
What you get
- Salary data: Salary disclosure is mandatory for native JustJoin.it listings but may be null on partner-imported listings from LinkedIn, Pracuj.pl, etc. Listings with a disclosed range return salary_min, salary_max, currency (PLN/EUR), and period (hourly/daily/monthly/annual). In our test runs roughly a quarter of listings carried a numeric range, so expect nulls.
- Tech stack with levels: the required and nice-to-have skills the offer lists (for example Databricks, .Net, Python), with the skill level shown on the page (Nice To Have, Junior, Regular, Advanced, Master). The job category (python, data, java) is a separate field.
- Salary per contract type: separate B2B and UoP ranges with currency, period and gross/net.
- Contract types: B2B, UoP and mandate contract as listed on the offer.
- Expiry date, languages, office address and every office location when the offer has several.
- Remote type: fully-remote, hybrid, or office (from JustJoin.it's workplace type).
- Company details: company name, website, profile page link, size, and the "About the company" text.
- Description quartet: description_snippet (first 300 chars), description_full (plain text), description_html (raw HTML), description_md (Markdown). Requires includeJobDetails=true for the full variants.
- Real server-side sorting (newest, relevance, highest salary) and a posted-within-days filter.
- Around 10,000 active listings refreshed daily.
Output fields
| Field | Type | Notes |
|---|---|---|
_type | string | Always "job" |
id | string | JustJoin.it job slug |
title | string | Job title |
job_url | string | Canonical listing URL |
source_url | string | Same as job_url (pipeline compat) |
company_name | string/null | Hiring company |
company_website | string/null | Company site from schema.org |
location | string/null | City, CountryCode |
country | string/null | ISO 2-letter code (usually PL) |
city | string/null | Primary city |
posted_at_text | string/null | Human-readable date |
posted_at_datetime | string/null | ISO 8601 timestamp |
employment_type | string/null | Full-time, Part-time, or Contract (freelance and B2B-only offers) |
remote_type | string/null | fully-remote / hybrid / office (kept for compatibility, same information as remote_option) |
remote_option | string/null | Canonical work mode: remote / hybrid / onsite |
salary_min | number/null | Lower salary bound |
salary_max | number/null | Upper salary bound |
salary_currency | string/null | ISO currency (PLN, EUR) |
salary_period | string/null | monthly / hourly / annual |
salary_text | string/null | Human-readable salary range |
seniority | string/null | Junior / Mid / Senior / Lead |
tech_stack | array | Skill names listed on the offer (required first, then nice-to-have), e.g. ["Databricks", ".Net", "Python"] |
tech_stack_levels | array | [{name, level, level_value}], level is Nice To Have / Junior / Regular / Advanced / Master, level_value 1 to 5 |
category | string/null | JustJoin.it job category (python, data, java, devops) |
contract_types | array | B2B / UoP / Mandate contract as listed on the offer |
salaries | array | Salary per contract type: [{contract_type, min, max, currency, period, gross}], original currency only |
salary_gross | boolean/null | Whether the primary salary is gross (true for UoP, usually false for B2B) |
working_pattern | string/null | Full-time / Part-time / Freelance / B2B Contract |
languages | array | [{code, level}] language requirements, e.g. {"code":"en","level":"B2"} |
english_level | string/null | English requirement level (CEFR) when the offer lists one |
expires_at | string/null | ISO 8601 date the offer expires (JSON-LD validThrough) |
description | string/null | Plain-text description |
description_snippet | string/null | First 300 chars of description |
description_full | string/null | Full plain text (requires includeJobDetails) |
description_html | string/null | Raw HTML (requires includeJobDetails) |
description_md | string/null | Markdown (requires includeJobDetails) |
contact_emails | array | Emails from description |
contact_email | string/null | First email found |
contact_phone | string/null | First phone found |
contact_phones | array | Phone numbers from description |
contact_urls | array | External URLs, taken from the real link targets in the description |
company_logo_url | string/null | Company logo thumbnail |
company_about | string/null | "About the company" text from the company profile, when the company has one |
company_profile_url | string/null | JustJoin.it company profile page |
company_size | string/null | Company size range when listed (e.g. 501+) |
company_address | string/null | Office street and city (city only when no street is listed) |
street_address | string/null | Office street when listed |
locations | array | Only when the offer has several locations: [{city, street, latitude, longitude, url}]. location is always the primary one |
latitude, longitude | number/null | Primary office coordinates |
posted_at | string/null | Same value as posted_at_datetime |
apply_method | string/null | external (employer site) or form (apply on JustJoin.it) |
external_apply_url | string/null | Employer apply link when the apply leaves JustJoin.it |
open_to_hire_ukrainians | boolean/null | Offer is flagged open to Ukrainian candidates |
remote_interview | boolean/null | Offer says the interview is remote |
hybrid_office_days, hybrid_remote_days | integer/null | Weekly office and remote days for hybrid offers |
experience_level | string/null | JustJoin.it level: junior, mid, senior, manager, c_level |
apply_url | string/null | External apply link, otherwise the JustJoin.it job page |
search_query | string/null | Keyword that matched this listing |
scraped_at | string | ISO 8601 fetch timestamp |
Input
| Field | Description | Default |
|---|---|---|
searchQueries | Keywords searched on JustJoin.it, one server-side search per keyword (e.g. ["backend developer", "python"]) | developer if empty |
maxResultsPerQuery | Cap per keyword (the actor pages through results, 50 offers per page) | 5 |
maxResults | Total result cap across all queries | 5 |
maxConcurrency | Parallel detail-page workers (safe to increase for large runs) | 5 |
country | Country filter: all, PL, DE, NL, CZ, SK | all |
city | City filter (e.g. Warszawa, Krakow), applied server-side via the city page | empty |
seniority | Junior / Mid / Senior / Lead | any |
remoteOnly | Return only fully-remote positions (server-side) | false |
contractType | Any / B2B / UoP, applied server-side. Offers that do not disclose a contract type are still returned by the site. | Any |
sortBy | newest, relevance, salary (highest first). Legacy aliases: published = newest, salaryDesc = salary. | newest |
postedWithinDays | Only jobs posted within N days (decimals allowed). Rounded up to the site buckets 1, 7, 14 or 30, then cut exactly on posted date. Above 30, 0 or empty = no filter. | empty |
includeJobDetails | Fetch full description + contacts (+$0.005/row) | false |
titleFilter | Comma-separated title terms (OR-match, case-insensitive). Only jobs whose title contains one of the terms are returned. Non-matching rows are dropped before any detail fetch, so you don't pay for them. Leave empty to disable. | empty |
Sorting, freshness and paging
Sorting, the date window, the keyword filter and pagination are all done by JustJoin.it's own search pages, so sortBy has a real effect:
newestreturns the site's "Latest" order (newest first). This is the default and the right choice for scheduled scrapes.relevancesends no sort parameter, so you get the site default, which is relevance-ranked when a keyword is set.salaryreturns the highest salaries first. The site ranks by salary normalized across hourly, daily, monthly and yearly units, so rawsalary_maxvalues with differentsalary_periodcan look out of order.
Notes on ordering:
- Promoted or pinned offers can appear at the top of a page with an older date. That is the site's promotion slot, not a sort failure.
- The site orders and filters by the last (re)publish time.
posted_at_datetimeis the original publish date, so an offer that was republished can look slightly out of order or be older than thepostedWithinDayswindow you asked for. The exact cutoff usesposted_at_datetime, so such reposted offers are dropped. - The actor stops paging for a keyword when the result cap is reached or a page returns no new offers. Results stay separated per keyword (see
search_query). - Start URLs that point to a JustJoin.it search page (
https://justjoin.it/job-offers/...) are paged the same way.
Example input
{"searchQueries": ["python", "java"],"sortBy": "newest","postedWithinDays": 7,"contractType": "B2B","maxResultsPerQuery": 50,"maxResults": 100}
Sample output
{"_type": "job","id": "fabrity-s-a--backend-developer-net-warszawa-net","title": "Backend Developer .NET","job_url": "https://justjoin.it/job-offer/fabrity-s-a--backend-developer-net-warszawa-net","company_name": "Fabrity S.A.","company_website": "https://kariera.fabrity.com/","location": "Warszawa, PL","country": "PL","city": "Warszawa","remote_type": "fully-remote","employment_type": "Full-time","salary_min": 17000,"salary_max": 23000,"salary_currency": "PLN","salary_period": "monthly","salary_text": "17000 - 23000 PLN/month","seniority": "Senior","tech_stack": ["Java", "Spring", "SQL"],"tech_stack_levels": [{"name": "Java", "level": "Advanced", "level_value": 4}],"category": "java","contract_types": ["B2B", "UoP"],"expires_at": "2026-10-31T22:59:59.999Z","company_profile_url": "https://justjoin.it/brands/story/fabrity","company_address": "Prosta 67, Warszawa","posted_at_text": "Aug 25, 2026","posted_at_datetime": "2026-08-25T08:00:39Z","description": "We are looking for a Backend Developer...","description_snippet": "We are looking for a Backend Developer .NET to join our team...","contact_emails": [],"search_query": "backend developer","scraped_at": "2026-08-25T08:54:14Z"}
Pricing
Pay-per-result pricing. $5 free monthly credit on Apify.
| Event | Cost |
|---|---|
| Actor start | $0.001 |
| Job listing (SERP) | $0.003 |
| Job listing with full details | $0.005 |
Typical cost: around $3 per 1,000 jobs (SERP only), or $5 per 1,000 with full details.
Scale and speed
Runs on 128 MB with plain HTTP requests. A 30-job run finishes in about 10 seconds and a 120-job, two-keyword run in about 85 seconds. Each search page holds 50 offers, and you can raise maxConcurrency (up to 20) to speed up larger runs. JustJoin.it lists roughly 10,000 active offers at any time.
How it works
- Requests JustJoin.it's server-rendered search pages (
/job-offers/all-locations?keyword=...&sortBy=...&published-date=...&page=N) for each keyword - Reads the listing data (title, company, city, publish date, salary, work mode) from the page's embedded Next.js payload, 50 offers per page
- Fetches each job page and reads schema.org/JobPosting JSON-LD plus the page's embedded offer data for the full salary, skills with levels, company text, office address, expiry and description
- Optionally extracts full description and contact details
Precision title filter
{"searchQueries": ["developer"],"titleFilter": "developer, python","maxResults": 50}
Only jobs with "developer" or "python" in the title are returned. Non-matching rows are dropped before any detail fetch.
API and integrations
See the auto-generated API tab for ready-to-run cURL, JavaScript and Python examples that stay in sync with the input schema. Found a problem? Open an issue.
Use with AI agents (MCP)
This actor works with Apify's MCP server in Claude, Cursor, LangChain and other agent frameworks.
{"mcpServers": {"apify": {"command": "npx","args": ["mcp-remote","https://mcp.apify.com/?tools=santamaria-automations/justjoinit-scraper","--header","Authorization: Bearer <YOUR_API_TOKEN>"]}}}
For per-tool schemas and copy-paste snippets for MCP clients, see the MCP tab.
Example prompt: "Find the 20 newest Python jobs on JustJoin.it posted in the last 7 days, and return title, company, city and salary range."
Related actors
Working across the Polish job market? These complement JustJoin.it:
- Pracuj.pl Scraper: Poland's largest private-sector generalist board (all industries, 80,000+ listings).
- praca.gov.pl Scraper: Poland's official government portal (Central Job Offers Database / CBOP) for public-sector and PUP office listings.
- NoFluffJobs EU Scraper: direct Polish tech peer with mandatory salary (CZ/SK/DE/AT/CH coverage too).
Broader coverage:
- LinkedIn Jobs Scraper: global professional network jobs.
- Indeed Scraper: broad global coverage including PL market.
- Glassdoor Scraper: company reviews, ratings and salary data alongside listings.
- Website Job Extractor: pulls job postings from any company career page.
Turn company_website into outreach data:
- Website Email Scraper: finds public emails on the company websites returned here.
- Website Contact Extractor: extracts phones, social links and decision-maker contacts from those sites.
Support
- Questions or issues? Email contact@nanoscrape.com, we typically reply within 6 hours. You can also open a ticket in the Issues tab on the actor page.
- Feature request for this actor? Open a ticket in the Issues tab or email contact@nanoscrape.com with the platform field you need and (if possible) a URL that shows the data live.
- Need a scraper for a job board we don't cover yet? Email contact@nanoscrape.com with the target site and your rough usage volume. We ship one-off boards regularly.