# Pracuj Scraper - Poland Jobs, Salaries, B2B & Companies (`scrapewise/pracuj-scraper`) Actor

Scrape Pracuj.pl jobs in Poland by keyword, city, radius, level, contract, schedule and work mode: title, company, salary per contract, category, requirements, benefits, technologies, office address and apply link. Schedule it with onlyNew for daily alerts. Error rows are free.

- **URL**: https://apify.com/scrapewise/pracuj-scraper.md
- **Developed by:** [Scrapewise Data](https://apify.com/scrapewise) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.44 / 1,000 job delivereds

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

## Pracuj Scraper: Poland jobs from Pracuj.pl with salaries, contracts, companies and full offer details

Pracuj Scraper collects **job offers from Pracuj.pl**, one of the main job boards in Poland, without an account, cookies or
a browser. Search by keyword (English or Polish), city or voivodeship with a radius, position level, contract type,
work schedule and work mode, or paste any search link from pracuj.pl or it.pracuj.pl. Each job comes back as one
clean row: title, company, every location, salary per contract type (min, max, currency, period, gross or net),
category, responsibilities, requirements, nice-to-have skills, benefits, technologies, required languages, office
address with coordinates, publication and expiry dates, and the direct apply link.

It is used for job alerts and job-matching tools, salary benchmarks for the Polish market (B2B versus employment
contract), recruitment market research, lead lists of companies that are hiring, and datasets for AI job agents.

### At a glance

| What | Price |
|---|---|
| Job delivered | **US$ 1.90 per 1,000 jobs** (US$ 0.0019 each) |
| Run start | US$ 0.005 per run |

- 500 jobs with full details = **US$ 0.96**. A daily alert of 30 new jobs costs about US$ 0.06 a day.
- One row per job: a job posted in several cities is one row with all its `locations`, so you never pay twice for the
  same offer.
- Error rows, duplicates and jobs already delivered in earlier runs (`onlyNew`) are never charged. `maxItems` is a
  hard cap, and a spending limit set on the run stops it cleanly with everything delivered so far.
- Fast: 50 jobs with full details in about 6 seconds.

### Quick start

```json
{
  "searchQueries": ["power bi"],
  "city": "Gdańsk",
  "maxItems": 50
}
```

More examples:

```json
{
  "searchQueries": ["magazynier", "operator wózka widłowego"],
  "city": "Poznań",
  "radiusKm": 30,
  "contractTypes": ["employment contract"],
  "maxItems": 200
}
```

```json
{
  "searchQueries": ["devops engineer"],
  "positionLevels": ["senior", "expert"],
  "contractTypes": ["B2B contract"],
  "workModes": ["remote"],
  "itOnly": true,
  "onlyNew": true,
  "maxItems": 100
}
```

```json
{
  "startUrls": [
    "https://www.pracuj.pl/praca/python;kw/krak%C3%B3w;wp?rd=10&et=18&wm=hybrid",
    "https://www.pracuj.pl/praca/data-analyst-operational-controlling-reporting-team-wroclaw-legnicka-16,oferta,1005146712"
  ]
}
```

### Input

| Field | What it does |
|---|---|
| `searchQueries` | Keywords or job titles, one search each. English and Polish both work (`power bi`, `księgowa`, `kierowca`) |
| `city` | Polish city or voivodeship (`Wrocław`, `Gdańsk`, `mazowieckie`). Empty = all of Poland |
| `radiusKm` | Also jobs up to 10, 20, 30, 50 or 100 km from the city |
| `positionLevels` | `internship`, `assistant`, `junior`, `mid`, `senior`, `expert`, `team leader`, `manager`, `director`, `president`, `blue-collar` |
| `contractTypes` | `employment contract` (umowa o pracę), `B2B contract`, `mandate contract` (umowa zlecenie), `contract for specific work` (umowa o dzieło), `temporary employment`, `replacement contract`, `agency contract`, `internship contract` |
| `workSchedules` | `full time`, `part time`, `additional / temporary` |
| `workModes` | `office`, `hybrid`, `remote`, `mobile` (field work) |
| `itOnly` | Search only the IT section of Pracuj.pl |
| `startUrls` | Search links copied from pracuj.pl or it.pracuj.pl (every filter in the link is kept, categories included) or links to single job offers |
| `includeDetails` | On by default: full description, requirements, benefits, technologies, salary per contract, category, office address. Off: faster, search-result fields only |
| `labelsLanguage` | `en` (default) or `pl`: language of the fixed labels such as level, contract, work mode and category |
| `maxItems` | Cap for the whole run (default 50, 0 = no cap) |
| `onlyNew` | Deliver only jobs not delivered in earlier runs of the same search (for schedules) |

Filters of the same kind are combined with OR (`senior` or `expert`); different filters are combined with AND.

### Output

| Field | What it is |
|---|---|
| `jobId`, `offerId` | Pracuj.pl job id (stable across cities) and offer number |
| `title`, `url`, `offerUrls` | Job title, offer link, and one link per city when the job is posted in several |
| `companyName`, `companyId`, `companyProfileUrl`, `companyLogoUrl` | The employer and its Pracuj.pl profile |
| `location`, `locations`, `region`, `country` | City (with district), all cities of the job, voivodeship and country |
| `officeStreet`, `officePostalCode`, `officeDistrict`, `latitude`, `longitude` | The workplace address the employer published |
| `isWholePoland`, `isRemoteAllowed`, `workModes` | Recruiting across Poland, remote work allowed, office / hybrid / remote / mobile |
| `positionLevels`, `contractTypes`, `workSchedules` | Level, contract types and schedule as tagged by the employer |
| `salaryText` | Salary as shown on the site, for example `10 000–15 000 zł gross / mth.` |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`, `salaryType` | First salary range as numbers, period (`hour`, `month`...) and `gross`, `net` or `net + VAT` |
| `salaries` | One range per contract type when the employer gives different pay for B2B and employment contract |
| `category`, `categoryParent`, `categories` | Main category, its parent and every category of the offer |
| `itSpecializations`, `technologiesRequired`, `technologiesNiceToHave`, `operatingSystems`, `developmentPractices` | IT details when the offer has them |
| `responsibilities`, `requirements`, `niceToHave`, `offered`, `benefits`, `recruitmentStages` | The offer sections as lists, one item per bullet |
| `requiredLanguages`, `workingHours`, `workDays`, `salaryComponents`, `paycheckPeriod` | Extra attributes the employer filled in |
| `shiftWork`, `nightWork`, `companyCar`, `noBusinessTrips` | Present (true) when the offer says so |
| `immediateStart`, `noExperienceRequired`, `manyVacancies`, `ukrainianFriendly` | Highlights shown on the offer |
| `isPromoted`, `isOneClickApply`, `isCvOptional`, `isRemoteRecruitment`, `isDirectEmployer` | Offer flags |
| `aboutProject`, `aboutCompany` | Project and company descriptions written by the employer |
| `summary`, `descriptionSnippet`, `description` | Short summary of the offer, the snippet from the results page and the full offer text |
| `applyUrl` | Direct apply link (the employer's own form when it has one) |
| `publishedAt`, `firstPublishedAt`, `expiresAt`, `isActive` | Last refresh, first publication, expiry (UTC) and status |
| `language`, `sourceQuery`, `scrapedAt` | Language of the offer, the keyword or link that found it, and when it was collected |

Fields that come from the full offer (salary numbers, sections, category, address) need `includeDetails` on. Fields
an employer did not fill in are empty.

One real row (lists and long texts shortened):

```json
{
  "type": "job",
  "jobId": "6c290000-56be-0050-f928-08df2544ad48",
  "offerId": 1005147764,
  "title": "Project Manager",
  "companyName": "Aplitt Sp. z o.o.",
  "companyProfileUrl": "https://pracodawcy.pracuj.pl/company/20302439",
  "url": "https://www.pracuj.pl/praca/kierowniczka-kierownik-projektu-gdansk-arkonska-11,oferta,1005147764",
  "location": "Gdańsk",
  "region": "pomorskie",
  "workModes": ["Hybrid work"],
  "positionLevels": ["Manager / Supervisor"],
  "contractTypes": ["Contract of employment"],
  "workSchedules": ["Full-time"],
  "salaryText": "10 000–12 000 zł gross / mth.",
  "salaryMin": 10000.0,
  "salaryMax": 12000.0,
  "salaryCurrency": "PLN",
  "salaryPeriod": "month",
  "salaryType": "gross",
  "category": "Administration of systems",
  "categoryParent": "IT-Administration",
  "itSpecializations": ["Project Management"],
  "technologiesRequired": ["VPN", "Veeam", "VMware", "PostgreSQL", "Microsoft SQL Server"],
  "requirements": ["Masz doświadczenie w samodzielnym prowadzeniu projektów IT po stronie dostawcy usług...", "..."],
  "benefits": ["dofinansowanie zajęć sportowych", "prywatna opieka medyczna", "..."],
  "officeStreet": "Arkońska 11",
  "officePostalCode": "80-387",
  "latitude": 54.405094146728516,
  "longitude": 18.57805061340332,
  "isDirectEmployer": true,
  "applyUrl": "https://aplitt.traffit.com/public/form/a/37?uid=...",
  "publishedAt": "2026-10-20T09:30:13.867Z",
  "expiresAt": "2026-11-08T22:59:59Z",
  "language": "pl",
  "sourceQuery": "power bi"
}
```

### Errors you may see

Every error is a row with `errorCode` and is never charged:

| errorCode | Meaning |
|---|---|
| `INVALID_INPUT` | A filter has a value that is not in the list, or Pracuj.pl did not accept a combination of filters in a link |
| `INVALID_URL` | Not a Pracuj.pl search or offer link |
| `NOT_FOUND` | The offer link points to an offer that was removed |
| `NO_RESULTS` | Pracuj.pl has no job for this search; try fewer filters, another spelling of the city or a broader keyword |
| `BLOCKED` | Pracuj.pl refused every attempt for this search; run it again in a few minutes |
| `UNEXPECTED` | Something unexpected stopped the run; what was delivered before stays in the dataset |

An empty input runs the example search (`power bi`) so you can see the output format right away.

### Integrations, scheduling and AI agents

- **Schedule** the same search every morning in [Apify schedules](https://docs.apify.com/platform/schedules) with
  `onlyNew` on: each run delivers only jobs posted since the last one, and the skipped ones are free.
- **Export** as JSON, CSV, Excel or XML, or read the dataset from the [Apify API](https://docs.apify.com/api/v2).
- **Connect** it to Make, n8n, Zapier, Slack or Google Sheets through
  [Apify integrations](https://docs.apify.com/platform/integrations) to post new jobs to a channel or a sheet.
- **AI agents:** call it as a tool through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp)
  in Claude, ChatGPT, Cursor or any MCP client, for example "find remote senior Python jobs on Pracuj.pl with a B2B
  rate above 150 PLN per hour and rank them against my CV".

### FAQ

**Do I need a Pracuj.pl account?** No. Everything comes from public job offers, without login or cookies.

**Can I search in English?** Yes. Keywords work in English and Polish, and `labelsLanguage: "en"` (the default) gives
the levels, contracts, work modes and categories in English. Text written by the employer stays in the language of
the offer; the `language` field tells you which one it is.

**How do I get the salary in numbers?** Keep `includeDetails` on. `salaryMin`, `salaryMax`, `salaryCurrency`,
`salaryPeriod` and `salaryType` hold the first range, and `salaries` lists one range per contract type. Around a
quarter to a third of offers publish a salary; `salaryText` is empty when the employer did not.

**How many jobs can I get?** All the results of a search: set `maxItems` to 0. A broad search such as all IT jobs
in Warsaw can return thousands of jobs.

**What about jobs posted in many cities?** They are one row with every city in `locations` and every offer link in
`offerUrls`, and you pay for one job.

**Can I use the filters of the site that are not in the input, like categories?** Yes. Set them on pracuj.pl, copy
the link from the address bar and paste it in `startUrls`.

**Is it legal?** The Actor reads public job offers only and returns company and job data, not data about
candidates. Recruiter phone numbers are not collected, and emails or phone numbers inside the offer text are replaced
by `[contact removed]`. You are responsible for how you use the data under the laws that apply to you.

**Something broke or a field is missing?** Open an issue on the Actor page; issues are answered within a day.

### Limitations

- Poland only: Pracuj.pl offers abroad that appear in a search come with the fields the site gives for them.
- Salary numbers come from the full offer; with `includeDetails` off only `salaryText` is filled.
- The order of results is the site's own (most recently refreshed first).
- Data is what Pracuj.pl shows at the moment of the run; offers expire on `expiresAt`.

### Changelog

- **21 Oct 2026:** first version: keyword, city, radius, level, contract, schedule, work mode and IT filters, search
  and offer links, full offer details with salary per contract, English or Polish labels, onlyNew for schedules.

# Actor input Schema

## `searchQueries` (type: `array`):

Job titles, skills or keywords, one per line, in English or Polish, for example power bi, magazynier or księgowa. Each keyword is one search. Leave empty when you paste Pracuj.pl links below.

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

Polish city or voivodeship, for example Gdańsk, Łódź or pomorskie. Empty = all of Poland.

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

Also include jobs up to this distance from the city: 10, 20, 30, 50 or 100 km (other numbers use the closest). Empty or 0 = the city only.

## `positionLevels` (type: `array`):

Keep only these position levels, as employers tag them on Pracuj.pl. Empty = all.

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

Keep only these contract types. Empty = all.

## `workSchedules` (type: `array`):

Keep only these work schedules. Empty = all.

## `workModes` (type: `array`):

Keep only these work modes. Empty = all.

## `itOnly` (type: `boolean`):

On: search only the IT section of Pracuj.pl (software, data, DevOps, support and other tech roles).

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

Optional: search links copied from the address bar of pracuj.pl or it.pracuj.pl after setting filters (every filter in the link is kept, categories included), or links to single job offers.

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

On: each job comes with the full description, responsibilities, requirements, benefits, technologies, category, salary per contract, languages and office address. Off: faster, only the fields shown in the search results.

## `labelsLanguage` (type: `string`):

Language of the fixed labels Pracuj.pl uses (position level, contract, work mode, schedule, category, languages, salary period). The text the employer wrote, including its section titles, stays in the language of the offer.

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

Hard cap for the whole run, across all searches and links. 0 = no cap.

## `onlyNew` (type: `boolean`):

On: remembers the jobs delivered in earlier runs of the same search (in your account) and delivers only jobs not seen before. Skipped jobs are free.

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

Apify datacenter proxy by default. Change it only if you know you need to.

## Actor input object example

```json
{
  "searchQueries": [
    "power bi"
  ],
  "city": "Gdańsk",
  "itOnly": false,
  "includeDetails": true,
  "labelsLanguage": "en",
  "maxItems": 50,
  "onlyNew": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `resultsCsv` (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 = {
    "searchQueries": [
        "power bi"
    ],
    "city": "Gdańsk",
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapewise/pracuj-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 = {
    "searchQueries": ["power bi"],
    "city": "Gdańsk",
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapewise/pracuj-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 '{
  "searchQueries": [
    "power bi"
  ],
  "city": "Gdańsk",
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call scrapewise/pracuj-scraper --silent --output-dataset

```

## MCP server setup

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