# Robota.ua Scraper — Ukraine Jobs Board Data (`studio-amba/robota-ua-scraper`) Actor

Scrape Robota.ua, Ukraine's major jobs board: job title, company, salary (UAH), city, work mode, employment type and full description. Filter by profession keyword and city.

- **URL**: https://apify.com/studio-amba/robota-ua-scraper.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 result 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?

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

## Robota.ua Scraper — Ukraine Jobs Board

Scrape [Robota.ua](https://robota.ua), one of Ukraine's largest jobs boards,
into clean structured data. Job title, company, salary in UAH, city, work
mode, employment type, perks and the full description. Filter by profession
keyword and, optionally, one Ukrainian city.

Robota.ua carries hundreds of thousands of live vacancies nationwide. This
actor reads the public search results and, by default, each vacancy's own
detail page for the full record.

### What you get

One row per vacancy, with:

- Salary range in UAH when the employer discloses it, plus the exact text
  as shown on the page
- Company name, city, address and metro station text
- Work mode (on-site / remote / hybrid) and employment type (full-time /
  part-time / project)
- Perks and benefits (medical insurance, bonuses, regular salary review, etc.)
- Full plain-text job description
- The site's own "hot" urgency badge and relative posted time

### Who it is for

- Recruiters and staffing agencies tracking open roles across Ukraine
- Salary benchmarking and compensation research for the Ukrainian market
- Labour-market analysts and NGOs monitoring employment trends
- Job aggregators and boards that need a Ukraine feed alongside the rest of Europe

### How to scrape Robota.ua data

1. Set **Profession / keyword** to a Ukrainian job title, e.g. `водій`
   (driver), `менеджер з продажу` (sales manager), `кухар` (cook),
   `бухгалтер` (accountant). Robota.ua resolves this against its own
   profession dictionary, so a real, common job title works best — a
   made-up or misspelled keyword returns zero results by design (see
   Limitations).
2. Optionally set **City** to restrict results to one Ukrainian city.
   Leave empty to search all of Ukraine.
3. Set **Max results** to cap the run. Robota.ua returns 9 vacancies per
   page, so the actor pages through search results until the cap is hit.
4. Leave **Fetch vacancy detail pages** on (default) for the full record —
   address, work mode, employment type, posted time, perks and the full
   description. Turn it off for a faster listing-only scan with just
   title, company and salary (when shown on the card). This changes how
   COMPLETE each record is, not just how many you get.
5. Run the actor. Results stream into the dataset and can be exported as
   JSON, CSV or Excel.

#### Example inputs

Drivers, nationwide:

```json
{
  "searchQuery": "водій",
  "maxResults": 100
}
```

Sales managers in Kyiv:

```json
{
  "searchQuery": "менеджер з продажу",
  "city": "Київ",
  "maxResults": 50
}
```

Fast listing-only scan of accountant vacancies:

```json
{
  "searchQuery": "бухгалтер",
  "fetchDetails": false,
  "maxResults": 200
}
```

### Input reference

| Field | Type | Description |
|---|---|---|
| `searchQuery` | string | Ukrainian job title / profession. Default `водій` (driver). Must resolve against Robota.ua's own keyword dictionary — see Limitations. |
| `city` | select | One Ukrainian city, or empty for all of Ukraine. |
| `maxResults` | integer | Stop after this many vacancies. Default 30, max 2000. |
| `fetchDetails` | boolean | On by default. Opens each vacancy's detail page for address, work mode, employment type, posted time, perks and the full description. Off = a faster listing-only scan with just title, company and salary (when shown on the card) — no address, work mode, employment type, perks or description. This changes how COMPLETE each record is, not just how many you get. |
| `proxyConfiguration` | object | RESIDENTIAL + country UA, required (see below). |

### Output fields

| Field | Type | Example |
|---|---|---|
| `vacancyId` | string | `"9876543"` |
| `companyId` | string | `"1234567"` |
| `title` | string | `"Водій категорії В"` |
| `company` | string | null | `"Нова Пошта"` |
| `salaryMin` | number | null | `48000` (null when not disclosed — very common) |
| `salaryMax` | number | null | `69600` |
| `salaryCurrency` | string | `"UAH"` |
| `salaryRaw` | string | null | `"48 000 — 69 600 ₴"` |
| `city` | string | null | City input echo |
| `address` | string | null | `"вул. Хрещатик, 1, м. Хрещатик"` (detail page only) |
| `workMode` | string | null | `"В офісі/на місці"` (detail page only) |
| `employmentType` | string | null | `"Повна зайнятість"` (detail page only) |
| `isHot` | boolean | `true` when the listing carries the "Гаряча" urgency badge |
| `postedRelative` | string | null | `"5 годин тому"` (site shows no absolute date) |
| `perks` | array | Benefit chips (detail page only) |
| `description` | string | null | Full vacancy description (detail page only) |
| `url` | string | `"https://robota.ua/company1234567/vacancy9876543"` |
| `source` | string | `"robota.ua"` |
| `scrapedAt` | string | ISO 8601 timestamp |
| `searchQuery` | string | null | Profession keyword input echo |
| `citySlug` | string | null | Resolved Robota.ua city URL slug, null for nationwide |

#### Example output

```json
{
  "vacancyId": "9876543",
  "companyId": "1234567",
  "title": "Водій категорії В",
  "company": "Нова Пошта",
  "salaryMin": 48000,
  "salaryMax": 69600,
  "salaryCurrency": "UAH",
  "salaryRaw": "48 000 — 69 600 ₴",
  "city": "Київ",
  "address": "вул. Хрещатик, 1, м. Хрещатик",
  "workMode": "В офісі/на місці",
  "employmentType": "Повна зайнятість",
  "isHot": true,
  "postedRelative": "5 годин тому",
  "perks": ["Медичне страхування", "Регулярний перегляд зарплат"],
  "description": "Компанія шукає водія категорії В...",
  "url": "https://robota.ua/company1234567/vacancy9876543",
  "source": "robota.ua",
  "scrapedAt": "2026-08-25T10:00:00.000Z",
  "searchQuery": "водій",
  "citySlug": null
}
```

### A note on salary

Many Ukrainian job listings do not disclose a salary at all — `salaryMin`
and `salaryMax` are `null` in that case, never coerced to 0. This is the
market's own norm, not a gap in the scraper. When a salary is shown it is
usually a range before tax, sometimes with a note about a possible bonus.
Address, work mode, employment type, perks and the full description are
only available with `fetchDetails` on, since none of them appear on the
listing card.

### Proxy

RESIDENTIAL + country UA is required. Robota.ua sits behind a Cloudflare
managed-challenge gate that binds the clearance to the browser's own TLS/JA
fingerprint, not just the cookie or the IP — a Ukrainian residential IP
driven by a real browser is the only combination that clears it. The actor
handles the challenge for you; every listing and detail page is fetched
through the same warmed browser session. Do not switch this off.

### Cost

Pricing is pay per result. Every result costs one real browser render
(listing card) plus, with `fetchDetails` on, a second browser render for
the detail page — there is no plain-HTTP shortcut on this site, so
per-result cost is materially higher than a warm-once site. Turning
`fetchDetails` off roughly halves the per-result browser work but drops
address, work mode, employment type, perks and the description.

A run's usage cost only settles after it reports SUCCEEDED. A dataset read
taken while a run is still in progress shows a cost far below the final
figure, so size your spend from a completed run, not a partial one.

### Limitations

- `searchQuery` must resolve against Robota.ua's own profession dictionary
  (exact match, not fuzzy). A made-up or misspelled keyword returns a
  clear error rather than an empty dataset. Any real, common Ukrainian job
  title works — the dictionary backs the site's own search autocomplete,
  so it is broad.
- Salary is null on most listings — see above.
- City filtering covers the popular cities Robota.ua surfaces on its own
  homepage. Leave `city` empty to search nationwide.
- "Show contacts" details (recruiter phone/email) sit behind a login/apply
  wall on the site itself and are not scraped. When an employer types a
  phone number directly into their own description text, the site renders
  its "Показати контакти" (show contacts) widget inline around it — that
  phrase can appear inside `description` in that case. This is the site's
  own rendering, not scraper noise.
- The site is Ukrainian-language; field values are returned as published.

### Maintained by Studio Amba

We run 700+ scrapers for European websites, and the priority is keeping
every one of them working. Automated runs test this actor against the live
site and verify the output is complete. When the website changes, the
scraper usually gets repaired the same day, without you having to report
anything. Questions and issues go straight to the people who built it, and
most get an answer the same day.

### Need this data on a schedule, or a custom version?

We run this scraper as a managed service for businesses: scheduled runs,
deduplication, delta detection, and delivery to your inbox, Google Sheets,
or API, maintenance included. We can also build a custom version with your
exact fields and filters, or combine multiple sources into one feed.

See [studioamba.dev/services](https://studioamba.dev/services/) or email
<hello@studioamba.dev> for a free data sample.

# Actor input Schema

## `searchQuery` (type: `string`):

A Ukrainian job title or profession to search, e.g. 'водій' (driver), 'менеджер з продажу' (sales manager), 'кухар' (cook), 'бухгалтер' (accountant). Must match a known Robota.ua profession — the site resolves it to its own keyword dictionary, so exact common job titles work best. Leave empty for the default ('водій').

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

Restrict results to one Ukrainian city. Leave empty to search all of Ukraine.

## `maxResults` (type: `integer`):

Stop after this many vacancies. Robota.ua returns 9 listings per page, so a search is fetched page by page until this cap is reached.

## `fetchDetails` (type: `boolean`):

On (default): open each vacancy's detail page to get address, work mode, employment type, posted time, perks and the full description. Off: a faster listing-only scan with just title, company and salary (when shown on the card). This flag changes how COMPLETE each record is, not just how many you get.

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

RESIDENTIAL + country UA is required. Robota.ua sits behind a Cloudflare managed challenge (see docs/site-recon/robota-ua.md); a Ukrainian residential IP driven by a real browser is the only combination that clears it. Do not switch this off.

## Actor input object example

```json
{
  "searchQuery": "водій",
  "city": "",
  "maxResults": 8,
  "fetchDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "UA"
  }
}
```

# 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 = {
    "searchQuery": "водій",
    "city": "",
    "maxResults": 8,
    "fetchDetails": true,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "UA"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/robota-ua-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 = {
    "searchQuery": "водій",
    "city": "",
    "maxResults": 8,
    "fetchDetails": True,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "UA",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/robota-ua-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 '{
  "searchQuery": "водій",
  "city": "",
  "maxResults": 8,
  "fetchDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "UA"
  }
}' |
apify call studio-amba/robota-ua-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,studio-amba/robota-ua-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/VHyFHgr5vB6UrV709/builds/8NgARuNeRkKyOZyVK/openapi.json
