# Pracuj.pl Jobs Scraper (`automation-lab/pracuj-pl-jobs-scraper`) Actor

Extract Pracuj.pl vacancies with employer, location, salary, contract, work mode, technologies, dates, descriptions, and application links.

- **URL**: https://apify.com/automation-lab/pracuj-pl-jobs-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#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

## Pracuj.pl Jobs Scraper

Extract **pracuj.pl jobs** into normalized vacancy records for recruiting research, salary analysis, hiring intelligence, and repeatable job feeds.

Search by keyword and location, process an existing Pracuj.pl results URL, or enrich an individual public offer URL. Each record can include the offer ID, employer, workplaces, salary, contracts, work mode, dates, description, technologies, responsibilities, requirements, benefits, application links, and canonical URL.

The Actor uses a resource-blocked browser session and handles Pracuj.pl's public anti-bot page automatically. No Pracuj.pl account is required.

### What can you do with this Pracuj.pl jobs scraper?

- Export Polish vacancies to JSON, CSV, Excel, XML, or RSS.
- Compare salary ranges across roles, cities, employers, and contract types.
- Build a recurring feed keyed by stable Pracuj.pl offer IDs.
- Track active hiring by employer, region, or technology.
- Collect complete vacancy details for recruiting and labor-market analysis.
- Send results to a database, spreadsheet, webhook, Make, Zapier, or an AI workflow.

The Actor extracts current public records. It does not submit applications, upload a CV, log in, or contact employers.

### Who is it for?

**Recruiting teams** can identify active employers, technologies, contract models, and salary signals.

**Labor-market analysts** can collect consistently shaped observations for regional or occupational studies.

**Job-feed and integration developers** can consume stable IDs, canonical URLs, structured dates, and normalized arrays.

**Candidates and career-tool builders** can compare current public openings without manually copying fields from many offer pages.

**Sales and staffing teams** can study employer hiring activity using publicly displayed company and vacancy information.

### What data does it extract?

| Field group | Examples |
| --- | --- |
| Identity | `offerId`, `groupId`, `canonicalUrl` |
| Vacancy | `title`, `description`, `categories` |
| Employer | `employer`, `employerId`, `employerProfileUrl` |
| Place | `locations`, `region`, `country`, coordinates |
| Compensation | `salaryText`, `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod` |
| Work terms | `contractTypes`, `positionLevels`, `workModes`, `workSchedules`, `isRemote` |
| Detail sections | `responsibilities`, `requirements`, `benefits`, `technologies` |
| Dates | `postedAt`, `updatedAt`, `expiresAt`, `scrapedAt` |
| Application | `applyUrl`, `externalApplyUrl`, `isOneClickApply`, `remoteRecruitment` |
| Traceability | `sourceQuery`, `sourceUrl` |

Unavailable source fields are returned as `null` or an empty array instead of being invented.

### How to scrape Pracuj.pl vacancies

1. Open the Actor in Apify Console.
2. Enter one or more job keywords in **Search queries**.
3. Optionally enter a Polish city or region.
4. Keep **Include full job details** enabled for descriptions, technologies, requirements, benefits, structured salary fields, and apply links.
5. Set the maximum number of jobs and pages.
6. Click **Start**.
7. Open the **Jobs** dataset and export it in your preferred format.

A useful first input is:

```json
{
  "queries": ["Java developer"],
  "location": "Kraków",
  "includeDetails": true,
  "maxItems": 10,
  "maxPagesPerSearch": 2
}
```

### Input parameters

| Input | Type | Default | What it does |
| --- | --- | --- | --- |
| `queries` | string array | — | Job keywords to search on Pracuj.pl. |
| `location` | string | empty | City or region applied to every query. |
| `startUrls` | URL array | empty | Public Pracuj.pl search or individual offer URLs. |
| `includeDetails` | boolean | `true` | Opens offer pages for full detail enrichment. |
| `maxItems` | integer | `50` | Stops after 1–1,000 unique jobs. |
| `maxPagesPerSearch` | integer | `10` | Processes at most 1–20 pages per search. |

Provide at least one query or URL. When both are supplied, the Actor processes both and deduplicates results by `offerId`.

The `location` field applies to generated query searches. Existing `startUrls` keep the filters encoded in their URLs.

### Search URLs and individual offer URLs

You can paste a real search URL when you have already configured filters on Pracuj.pl:

```json
{
  "startUrls": [
    { "url": "https://www.pracuj.pl/praca/data%20analyst;kw/warszawa;wp" }
  ],
  "includeDetails": true,
  "maxItems": 25
}
```

You can also enrich one public offer directly:

```json
{
  "startUrls": [
    { "url": "https://www.pracuj.pl/praca/java-developer-krakow,oferta,1005020652" }
  ],
  "includeDetails": true,
  "maxItems": 1
}
```

Only `pracuj.pl` search and offer URLs are accepted. Unsupported domains and malformed limits fail with a clear error.

### Example output

This shortened record reflects the current output shape:

```json
{
  "offerId": 1005002751,
  "title": "Java Script / Mashup Developer",
  "employer": "Mindbox Sp. z o.o.",
  "locations": ["Kraków"],
  "region": "małopolskie",
  "country": "Poland",
  "salaryText": "26 000–29 000 zł netto (+ VAT) / mies.",
  "salaryMin": 26000,
  "salaryMax": 29000,
  "salaryCurrency": "PLN",
  "contractTypes": ["B2B contract"],
  "workModes": ["hybrid work"],
  "technologies": ["React.js", "TypeScript", "QlikSense"],
  "postedAt": "2026-07-31T22:00:00Z",
  "expiresAt": "2026-08-30T21:59:59Z",
  "applyUrl": "https://www.pracuj.pl/aplikuj/java-script-mashup-developer-krakow,oferta,1005002751",
  "canonicalUrl": "https://www.pracuj.pl/praca/java-script-mashup-developer-krakow,oferta,1005002751"
}
```

The complete dataset includes all fields declared in the dataset schema.

### Listing mode versus detail mode

With `includeDetails: false`, the Actor returns useful listing fields such as offer identity, title, employer, locations, salary text, work terms, dates, and URL. This is efficient for broad recurring monitoring.

With `includeDetails: true`, it also opens each offer page and adds structured salary values, full workplace metadata, categories, responsibilities, requirements, benefits, technologies, and apply fields.

If one detail page fails after a valid search result was obtained, the Actor preserves the listing record. A failed or challenged search page fails the run rather than silently returning an empty dataset.

### How much does it cost to extract Pracuj.pl jobs?

The Actor uses pay-per-event pricing:

- **Start:** $0.01 once per run.
- **Job item:** tiered by your Apify plan; the BRONZE price is $0.0016 per saved job.
- Detail enrichment is included in the job item event and has no separate event charge.

At BRONZE rates, approximate Actor charges are:

| Saved jobs | Approximate charge |
| ---: | ---: |
| 1 | $0.0116 |
| 10 | $0.026 |
| 100 | $0.17 |

Apify platform usage and proxy transfer can vary with page size, challenge handling, and run duration. Check Console for the exact charge and platform usage of each run.

### Tips for reliable recurring monitoring

- Keep the same query and filter scope between scheduled runs.
- Use `offerId` as the primary deduplication key.
- Compare `updatedAt`, `expiresAt`, salary fields, and normalized arrays to detect changes.
- Disable details for a broad first-stage feed, then enrich selected offer URLs in a second task.
- Use smaller scheduled runs instead of repeatedly downloading a large catalog.
- Set a realistic `maxPagesPerSearch`; the Actor stops early when no additional records are found.

The Actor does not maintain a hidden cross-run database. Your dataset, storage, or downstream workflow should retain prior snapshots when change history is required.

### Export and integration workflows

After a run, export the default dataset as JSON, CSV, Excel, XML, or RSS.

Common workflows include:

1. Schedule a daily task and append records to a warehouse.
2. Use a webhook to send new vacancies to Make or Zapier.
3. Join `employerId` and `offerId` with internal recruiting data.
4. Load salary fields into a notebook or BI dashboard.
5. Feed vacancy text and technology arrays into a search or RAG index.
6. Send expiring offers to an internal review queue.

Apify integrations can connect datasets to Google Sheets, Slack, GitHub, Airbyte, Keboola, and custom webhooks.

### Run through the Apify API with cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~pracuj-pl-jobs-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "queries": ["data analyst"],
    "location": "Warszawa",
    "includeDetails": true,
    "maxItems": 20
  }'
```

The response contains the run and default dataset identifiers. Poll the run or use a webhook before downloading results.

### Use from JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/pracuj-pl-jobs-scraper').call({
  queries: ['data analyst'],
  location: 'Warszawa',
  includeDetails: true,
  maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Use from Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/pracuj-pl-jobs-scraper').call(run_input={
    'queries': ['data analyst'],
    'location': 'Warszawa',
    'includeDetails': True,
    'maxItems': 20,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use with MCP and AI agents

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/pracuj-pl-jobs-scraper"
```

#### Claude Desktop

Add this server to the Claude Desktop MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/pracuj-pl-jobs-scraper"
    }
  }
}
```

#### Cursor

Open **Settings → MCP**, add a remote HTTP server named `apify`, and use:

```text
https://mcp.apify.com?tools=automation-lab/pracuj-pl-jobs-scraper
```

#### VS Code

Add the same remote HTTP endpoint to your workspace MCP server configuration, then enable the `automation-lab/pracuj-pl-jobs-scraper` tool.

Example prompts:

- “Find three Java developer openings in Kraków and compare their salary and work mode.”
- “Extract this Pracuj.pl search URL and group jobs by employer.”
- “Return current accounting vacancies as a compact feed for my monitoring workflow.”

### Limitations and troubleshooting

Pracuj.pl can change its page structure, filters, and anti-bot rules. The Actor validates the current structured page state and fails clearly when it cannot recognize it.

A search may naturally have no results. Try the same search in a browser, broaden the keyword or location, and confirm that the offer is still active.

Detail fields vary by employer. Salary, external application URL, coordinates, technologies, or remote-recruitment status may be absent.

Expired, withdrawn, login-only, and non-public records are not accessible. The Actor does not solve interactive CAPTCHAs or access private candidate data.

Large detail runs take longer because each vacancy document is fetched through the same cleared browser session.

### Responsible use and legality

This Actor extracts publicly visible vacancy information. Web-scraping rules depend on the jurisdiction, source terms, data type, and intended use.

- Review Pracuj.pl's terms and robots guidance for your use case.
- Respect applicable copyright, database, privacy, and employment laws.
- Avoid excessive collection and retain only data you need.
- Do not use results for unlawful discrimination, spam, or automated application abuse.
- Secure exported datasets and honor valid deletion or correction requests.

You are responsible for deciding whether your collection and downstream processing are lawful.

### FAQ

#### Does it require a Pracuj.pl account?

No. It processes public search and offer pages anonymously.

#### Can it search more than one keyword?

Yes. Add multiple strings to `queries`; the Actor deduplicates overlapping offers by `offerId`.

#### Can it process filters selected on Pracuj.pl?

Yes. Supply the resulting public search URL in `startUrls`. Its encoded search scope is preserved.

#### Why are some salary fields null?

Many employers do not publish salary ranges. `salaryText` comes from the listing, while numeric salary fields require structured detail data.

#### Why did a run fail instead of returning zero records?

The Actor fails when Pracuj.pl returns a persistent challenge or an unrecognized page. This prevents a blocked page from being mistaken for a genuine empty search.

#### Can I monitor new and changed jobs?

Yes. Schedule a consistent input and compare records downstream by `offerId`, `updatedAt`, and the fields important to your workflow. The Actor does not itself retain historical snapshots.

### Related Actors

For salary-focused Polish technology vacancies, use [NoFluffJobs Tech Jobs Scraper](https://apify.com/automation-lab/nofluffjobs-tech-jobs-scraper).

For public ATS boards, [Breezy HR Jobs Scraper](https://apify.com/automation-lab/breezy-hr-jobs-scraper) and [Pinpoint ATS Jobs Scraper](https://apify.com/automation-lab/pinpoint-ats-jobs-scraper) cover their respective sources.

# Actor input Schema

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

Polish or English job keywords, such as Java developer, księgowa, or data analyst.

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

Optional city or region applied to every search query, for example Warszawa, Kraków, or Wrocław.

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

Optional public Pracuj.pl search-result or individual job-offer URLs. Search URLs keep their existing source filters.

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

Open each offer page to add full salary structures, descriptions, technologies, responsibilities, requirements, benefits, and apply links. Disable for faster listing monitoring.

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

Maximum number of unique job records saved across all queries and URLs.

## `maxPagesPerSearch` (type: `integer`):

Maximum Pracuj.pl result pages processed for each query or search URL.

## Actor input object example

```json
{
  "queries": [
    "Java developer"
  ],
  "location": "Kraków",
  "startUrls": [],
  "includeDetails": true,
  "maxItems": 10,
  "maxPagesPerSearch": 2
}
```

# Actor output Schema

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

Dataset containing extracted Pracuj.pl job records.

# 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": [
        "Java developer"
    ],
    "location": "Kraków",
    "startUrls": [],
    "includeDetails": true,
    "maxItems": 10,
    "maxPagesPerSearch": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/pracuj-pl-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": ["Java developer"],
    "location": "Kraków",
    "startUrls": [],
    "includeDetails": True,
    "maxItems": 10,
    "maxPagesPerSearch": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/pracuj-pl-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": [
    "Java developer"
  ],
  "location": "Kraków",
  "startUrls": [],
  "includeDetails": true,
  "maxItems": 10,
  "maxPagesPerSearch": 2
}' |
apify call automation-lab/pracuj-pl-jobs-scraper --silent --output-dataset

```

## MCP server setup

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