# robota.ua Scraper: Ukraine Job Vacancies (`reventadata/robota-ua-scraper`) Actor

Scrape robota.ua job vacancies by keyword: title, employer, city, stated salary, posting time and link. Optionally open each vacancy for the full description, address, category, skills and the contacts the employer publishes. Filter by city, salary band and words. Unofficial.

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

## Pricing

from $1.50 / 1,000 results

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?

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

## robota.ua Scraper

> **Unofficial.** This Actor is not affiliated with, endorsed by or sponsored by robota.ua. It reads the vacancy data robota.ua shows to every visitor of its public job board. robota.ua is a trademark of its owner.

Search Ukraine's robota.ua job board by keyword and get clean, structured vacancy rows: title, employer, city, stated salary, posting time and a link, with optional full vacancy pages (description, exact posting time, address, category, skills, contacts the employer publishes). Built by reventadata.

### What you can do with it

- Track vacancies for one or many keywords (job titles, skills, trades) across Ukraine.
- Filter after fetching by city, salary band, and words that must or must not appear.
- Add `includeDetails` to get the full description, the exact posting time and the contacts the employer published.

### Input

| Field | What it does |
|---|---|
| `searchQueries` | One robota.ua search per term (python, водій, sales manager). Empty = the site's default-ranked list across all topics. |
| `maxItems` | Total vacancies to save across all queries. |
| `maxPages` | Result pages to walk per query (20 vacancies each). |
| `includeDetails` | Open every kept vacancy for the full page fields. One extra request per vacancy. |
| `city` | Keep only vacancies whose city name contains this text (case and accent insensitive). Applied after fetching. |
| `minSalary` / `maxSalary` / `onlyWithSalary` | Salary band on the stated range. The site gives no currency field. Applied after fetching. |
| `includeKeywords` / `excludeKeywords` | Words that must / must not appear in title, company or listing snippet. |
| `proxyConfiguration` | Apify Proxy settings. Apify Proxy is on by default. |

Example input:

```json
{
  "searchQueries": ["python"],
  "maxItems": 20,
  "maxPages": 1,
  "includeDetails": true
}
```

### Output

One row per vacancy. A real row from the example task run on 2026-11-10 (`includeDetails` on; long text fields shortened here):

```json
{
  "id": "11405348",
  "url": "https://robota.ua/company3799787/vacancy11405348",
  "title": "Data scientist",
  "company": "SpaceCrew Finance Company",
  "companyId": "3799787",
  "companyLogo": "https://company-logo-frankfurt.rabota.ua/3799787_20230714131712.jpeg",
  "location": "Київ",
  "cityId": "1",
  "scheduleIds": [
    "9",
    "1"
  ],
  "salaryFrom": null,
  "salaryTo": null,
  "salaryComment": null,
  "snippet": "Привіт! Ми SpaceCrew Finance GroupМіжнародна fintech-група, яка створює технологічні продукти у сфері фінансів, data science та digital solutions. Уже багато років ми розвиваємо власну екосистему сервісів, об'єднуючи сильних людей, сучасні технології...",
  "postedText": "9 годин тому",
  "isHot": false,
  "isActive": true,
  "isAnonymous": false,
  "publicationType": "OPTIMUM",
  "benefits": [],
  "applyUrl": null,
  "matchedKeyword": "python",
  "page": 1,
  "detailFetched": true,
  "postedAt": "2026-11-10T13:03:08.840000+02:00",
  "description": "Привіт! Ми SpaceCrew Finance Group\nМіжнародна fintech-група, яка створює технологічні продукти у сфері фінансів, data science та digital solutions. Уже багато років ми розвиваємо власну екосистему сер...",
  "address": null,
  "district": null,
  "metro": null,
  "latitude": 50.4500351,
  "longitude": 30.5241356,
  "category": "Фінансові послуги",
  "schedules": [
    "в офісі/на місці",
    "повна зайнятість"
  ],
  "isRemote": false,
  "skills": [
    "Мова програмування python",
    "R Developer",
    "Machine Learning Engineer",
    "Дата Саєнтист",
    "Середній розробник Python"
  ],
  "contactName": "Олена Кучерявенко",
  "contactPhones": [],
  "contactSocials": [
    "https://t.me/KuOlena"
  ],
  "companyVerified": true,
  "companyFoundedYear": 2016,
  "companySize": "від 250 до 500",
  "companyBenefits": [
    "Офіс біля метро",
    "Корпоративні заходи",
    "Компенсація спортзала",
    "Компенсація навчання",
    "Гнучкий графік"
  ],
  "scrapedAt": "2026-11-10T20:40:01+00:00"
}
```

Notes on the fields:

- Salary is exactly what the employer states. `salaryTo` is empty for an open-ended "from X" offer, and both are empty when no figure is stated. The site's data has no currency field.
- `postedText` is the site's relative text ("10 годин тому"). The exact `postedAt` (Kyiv time with offset) comes only with `includeDetails`.
- `contactPhones` and `contactSocials` hold what the employer published on the vacancy; in the 20-row example task run on 2026-11-10, 3 vacancies had a phone and 7 a social link.
- Fields that need the vacancy page are `null` when `includeDetails` is off.

### Limits

- Defaults: `maxItems` 100 and `maxPages` 10 per query (20 vacancies per page), so a default run saves up to 100 vacancies. Raise `maxItems` and `maxPages` for more; `maxPages` goes up to 500.
- A search with no matches finishes with a clear "0 results" message. If robota.ua's protection blocks every request and no vacancy was saved, the run fails with a message saying so instead of reporting an empty success. If a page is blocked after some vacancies were saved, the run keeps them and the log says which page failed.
- With `includeDetails` on, each vacancy costs one extra request, so the same `maxItems` takes longer.
- robota.ua sits behind Cloudflare. The Actor uses Apify Proxy by default (no group named); if runs report a block, switch `proxyConfiguration` to residential.

### Pricing

For current pricing and details, see the Store page.

### Legal

Collects only data robota.ua shows publicly without a login. You are responsible for using it in line with robota.ua's terms and applicable law, including data-protection rules for any personal data in the rows.

# Actor input Schema

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

Job titles or keywords, one robota.ua search per term (for example python, водій, sales manager). Leave empty to list the site's default-ranked vacancies across all topics.

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

Total number of vacancies to save across all queries. Each result page holds 20 vacancies.

## `maxPages` (type: `integer`):

Result pages to walk per query (20 vacancies each). The Actor stops earlier at the last page the site has. The default of 10 gives up to 200 vacancies per query.

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

Open every kept vacancy to add the full description, exact posting time, address, category, skills, schedules and the contacts the employer publishes. This costs one extra request per vacancy, so runs are slower. Off: each row carries the listing snippet and relative posting time.

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

Keep only vacancies whose city name contains this text, ignoring case and accents (for example Київ or Львів). Applied after fetching, so combine it with a query; it does not widen the search.

## `minSalary` (type: `integer`):

Keep only vacancies whose stated salary range reaches at least this amount, as the site states it (the API gives no currency). Vacancies with no stated salary are dropped when this is set. Applied after fetching.

## `maxSalary` (type: `integer`):

Keep only vacancies whose stated salary range starts at or below this amount. Vacancies with no stated salary are dropped when this is set. Applied after fetching.

## `onlyWithSalary` (type: `boolean`):

Drop vacancies that state no salary figure.

## `includeKeywords` (type: `array`):

Keep only vacancies whose title, company or listing snippet contains every one of these words, ignoring case and accents.

## `excludeKeywords` (type: `array`):

Drop vacancies whose title, company or listing snippet contains any of these words, ignoring case and accents.

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

robota.ua sits behind Cloudflare, which challenged a home IP and passed a datacenter IP in testing. Apify Proxy is on by default with no group named; if runs report a block, try the residential group.

## Actor input object example

```json
{
  "searchQueries": [
    "python"
  ],
  "maxItems": 20,
  "maxPages": 1,
  "includeDetails": false,
  "onlyWithSalary": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Items scraped from the target website.

# 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": [
        "python"
    ],
    "maxItems": 20,
    "maxPages": 1,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("reventadata/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 = {
    "searchQueries": ["python"],
    "maxItems": 20,
    "maxPages": 1,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("reventadata/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 '{
  "searchQueries": [
    "python"
  ],
  "maxItems": 20,
  "maxPages": 1,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call reventadata/robota-ua-scraper --silent --output-dataset

```

## MCP server setup

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