# hh.ru (HeadHunter) Job Scraper (`memo23/hh-ru-scraper`) Actor

Scrape job vacancies from hh.ru (HeadHunter) — title, salary with gross/net flag, employer rating, key skills, metro and GPS coordinates, full description. Works with any search URL, catalog page, or keywords. Built-in residential proxy, monitoring mode for new-only feeds. JSON/CSV.

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

## Pricing

from $2.00 / 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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## hh.ru (HeadHunter) Job Scraper — vacancies, salaries, employer ratings & key skills

Scrape job vacancies from **hh.ru**, Russia's largest job board (and the HeadHunter network across the CIS). Paste any hh.ru search URL, catalog page, or direct vacancy link — or just type keywords — and get clean, structured vacancy data: title, salary range, employer profile with rating, full description, key skills, metro stations, and exact coordinates.

![How hh.ru Job Scraper works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-hh.png)

### Why use this hh.ru scraper?

- **Full-depth rows, not snippets.** Every vacancy is parsed from hh.ru's own embedded page data — the same payload the site renders from — so you get fields most scrapers miss: salary with gross/net flag, employer rating and review count, IT-accreditation badge, key skills, metro stations, and GPS coordinates.
- **Three ways to start.** hh.ru search URLs (with all your filters applied), direct vacancy URLs, or plain keywords + region ID. Mix them in one run.
- **Built-in residential proxy at no extra cost.** hh.ru blocks datacenter and most foreign IPs; this actor routes all traffic through its own residential pool. No proxy setup, no extra proxy bill.
- **Monitoring mode.** Run it on a schedule and receive only vacancies you haven't seen before — a ready-made "new jobs since last run" feed.
- **Honest pagination.** hh.ru serves at most 2,000 results per query (40 pages × 50). The actor tells you when your query exceeds the cap so you can split it by region or keyword instead of silently missing data.

### Overview

| | |
|---|---|
| **Target site** | [hh.ru](https://hh.ru) — HeadHunter, the largest job board in Russia and the CIS |
| **Entity** | Job vacancy (one dataset row per vacancy) |
| **Input** | Search/catalog/vacancy URLs, or keywords + area ID |
| **Output** | JSON / CSV / Excel via Apify Dataset |
| **Coverage** | All hh.ru regions, including regional subdomains (spb.hh.ru, kazan.hh.ru, …) |

### Supported inputs

| Input | Example | What happens |
|---|---|---|
| Search URL | `https://hh.ru/search/vacancy?text=python&area=1` | Walks every result page (50 vacancies each) and scrapes each vacancy |
| Search URL with filters | `https://hh.ru/search/vacancy?text=аналитик&salary=150000&only_with_salary=true` | All hh.ru search filters are respected — the actor scrapes exactly what the URL returns |
| Catalog page | `https://hh.ru/vacancies/programmist` | SEO catalog listings work the same as search URLs |
| Direct vacancy URL | `https://hh.ru/vacancy/123456789` | Scrapes just that vacancy |
| Keywords | `searchKeywords: ["python developer"]` + `area: "1"` | Each keyword becomes a search; the optional area ID narrows the region |

Common area IDs: `1` Moscow · `2` Saint Petersburg · `113` all Russia · `3` Yekaterinburg · `4` Novosibirsk · `88` Kazan · `40` Kazakhstan.

### Use cases

- **Salary benchmarking** — hh.ru is one of the few boards where employers publish exact salary ranges with gross/net flags.
- **Recruiting & sourcing intelligence** — track which companies are hiring for which skills, in which regions, at what pay.
- **Job aggregation** — feed a job site or Telegram channel with structured postings, deduplicated by monitoring mode.
- **Market research** — measure demand per skill (`keySkills`), per region, per work format (remote / hybrid / on-site).
- **Competitor watch** — schedule a search for a competitor's name and get alerted to every new opening.
- **Lead generation** — employer name, website, and hh.ru profile URL in every row; opt-in email enrichment adds a contact email.

### How it works

1. **Classify** each start URL: search/catalog listing vs direct vacancy page.
2. **Parse the embedded JSON state** hh.ru ships inside every page — no fragile CSS selectors for core fields.
3. **Walk the pagination** (0-based `?page=N`) up to the last page reported by the site, stopping early at your `maxItems`.
4. **Fetch vacancy pages in parallel** (sliding-window concurrency, browser-grade TLS fingerprints, automatic retries across two independent HTTP stacks).
5. **Push one structured row per vacancy** with employer fields merged in. A JSON-LD fallback keeps rows flowing even if hh.ru changes its state format.

### Input configuration

Minimal example:

```json
{
    "startUrls": ["https://hh.ru/search/vacancy?text=python&area=1"],
    "maxItems": 100
}
````

Keyword example:

```json
{
    "searchKeywords": ["data engineer", "ml engineer"],
    "area": "113",
    "maxItems": 500
}
```

Monitoring example (schedule daily, get only new vacancies):

```json
{
    "startUrls": ["https://hh.ru/search/vacancy?text=devops&area=2"],
    "monitoringMode": true,
    "maxItems": 1000
}
```

| Field | Type | Default | Notes |
|---|---|---|---|
| `startUrls` | array | — | hh.ru URLs; takes priority over keywords |
| `searchKeywords` | array | — | One search per keyword |
| `area` | string | — | Numeric hh.ru area ID for keyword searches |
| `maxItems` | integer | 1000 | Hard cap on scraped vacancies |
| `monitoringMode` | boolean | false | Only return vacancies not delivered on previous runs |
| `resetMonitoringState` | boolean | false | One-shot: clear the "already seen" record |
| `enrichEmails` | boolean | false | Opt-in employer contact-email discovery (billed per found email) |
| `maxConcurrency` | integer | 10 | Parallel vacancy fetches |
| `proxy` | object | built-in | Leave empty — residential routing is included |

### Output overview

One row per vacancy. Employer fields are merged inline — no separate employer rows, no padding rows. You only pay for real vacancies.

### Output sample

```json
{
    "type": "vacancy",
    "vacancyId": "134753776",
    "vacancyUrl": "https://hh.ru/vacancy/134753776",
    "title": "Агент / Менеджер по продаже недвижимости",
    "companyId": "2910677",
    "companyName": "РЕАЛИСТ - ГК АЛЕКСАНДР Недвижимость",
    "companyUrl": "https://hh.ru/employer/2910677",
    "companyWebsite": "http://www.realist-estate.ru",
    "companyTrusted": true,
    "companyAccreditedIT": false,
    "logoUrl": "https://img.hhcdn.ru/employer-logo-original/1493659.png",
    "salary": { "from": 250000, "to": null, "currency": "RUB", "gross": false, "mode": "MONTH" },
    "areaName": "Санкт-Петербург",
    "countryCode": "RU",
    "address": {
        "displayName": "Санкт-Петербург, Большой Сампсониевский проспект, 28к2",
        "city": "Санкт-Петербург",
        "street": "Большой Сампсониевский проспект",
        "building": "28к2"
    },
    "coordinates": { "latitude": 59.963778, "longitude": 30.343392 },
    "metroStations": [
        { "name": "Выборгская", "lineColor": "#D6083B" },
        { "name": "Горьковская", "lineColor": "#0078C9" }
    ],
    "experience": "noExperience",
    "employmentForm": "FULL",
    "workFormats": ["ON_SITE", "HYBRID"],
    "workSchedule": ["FIVE_ON_TWO_OFF"],
    "workingHours": ["HOURS_8"],
    "keySkills": ["Деловое общение", "Активные продажи", "Навыки презентации"],
    "description": "<p><strong>…full vacancy description as HTML…</strong></p>",
    "descriptionText": "…full vacancy description as plain text…",
    "contactInfo": null,
    "publishedAt": "2026-07-08T12:41:12.000+03:00",
    "validThrough": "2026-08-07T12:41:12+03:00",
    "scrapedAt": "2026-07-11T19:23:03.511Z"
}
```

### Key output fields

| Field | Description |
|---|---|
| `title`, `description`, `descriptionText` | Vacancy title; full description as HTML and as plain text |
| `salary` | `{from, to, currency, gross, mode, frequency}` — currency normalized to ISO (RUB), `gross` distinguishes pre/post-tax; `null` when the employer hides pay |
| `companyName`, `companyUrl`, `companyWebsite` | Employer name, hh.ru profile, and the employer's own site when published |
| `companyRating`, `companyReviewsCount` | hh.ru employer review score (when the employer has reviews) |
| `companyTrusted`, `companyAccreditedIT` | hh.ru verification badge; Russian IT-company accreditation flag |
| `keySkills` | The vacancy's skill tags — ideal for demand analytics |
| `experience` | `noExperience` / `between1And3` / `between3And6` / `moreThan6` |
| `workFormats`, `workSchedule`, `workingHours` | On-site/hybrid/remote, shift pattern, hours per day |
| `address`, `coordinates`, `metroStations` | Street address, GPS coordinates, and metro stations with line colors |
| `contactInfo` | Recruiter name/email/phones — only when the employer publishes contacts |
| `publishedAt`, `validThrough` | Posting date and expiry timestamp |

### FAQ

**How many results can one query return?**
hh.ru serves at most 2,000 results per search (40 pages × 50). The actor warns you in the log when your query matches more — split it by region (`area`), salary band, or narrower keywords to cover everything.

**Do I need a proxy?**
No. hh.ru rejects datacenter and most foreign IPs, so the actor ships with built-in residential routing at no extra cost. The proxy input exists only as an override for users who insist on their own pool.

**Is the salary gross or net?**
Both occur; every salary object carries a `gross` boolean straight from hh.ru (`true` = before tax, `false` = "на руки").

**Why is `contactInfo` usually null?**
hh.ru employers rarely publish recruiter contacts on the public page. When they do, the actor captures name, email, and phone numbers. For a contact email on other rows, enable `enrichEmails`.

**Does it work for hh.kz / hh.uz and other national sites?**
This actor targets hh.ru (including all regional subdomains). Kazakhstan and Uzbekistan vacancies posted on hh.ru (e.g. `area=40`) are covered; the separate national domains are not.

**What language is the data in?**
Whatever the employer wrote — mostly Russian, with English postings common in IT. Fields like `workFormats` and `experience` are hh.ru's own stable enum codes, so your pipelines don't depend on Russian labels.

**Can I get only new vacancies on a schedule?**
Yes — enable `monitoringMode` and put the actor on an Apify schedule. The first run seeds your baseline; every later run returns only unseen vacancy IDs (skipped vacancies are never charged).

### Support

Found an issue or need a field added? Open an issue on the actor's **Issues tab** in Apify Console — it's monitored, and runs are covered by automatic failure alerting on our side. Typical response time is under 24 hours.

### Additional services

- **Custom fields or filters** — need employer headcount, response statistics, or a filter the input doesn't expose? Ask via the Issues tab.
- **Custom scrapers** — we build and maintain scrapers for job boards and directory sites; see the profile for the full portfolio.

### Explore more scrapers

More job-board actors by the same author: StepStone, TotalJobs, CharityJob, s1jobs, Goodmoves, AmbitionBox, and more — see the [author's Apify profile](https://apify.com/memo23) for the complete list.

### ⚠️ Disclaimer

This actor collects only publicly available data from hh.ru vacancy pages — the same information any visitor sees in a browser. It does not bypass authentication, does not collect personal data of applicants, and respects hh.ru's per-query result limits. You are responsible for how you use the data: comply with hh.ru's Terms of Service, applicable data-protection laws (including GDPR/152-ФЗ where relevant), and use the data only for lawful purposes. This project is not affiliated with, endorsed by, or connected to HeadHunter Group PLC.

### SEO Keywords

hh.ru scraper, headhunter scraper, hh.ru job scraper, hh.ru parser, hh.ru api alternative, scrape hh.ru vacancies, hh.ru vacancy export, headhunter jobs api, hh.ru data extraction, парсер hh.ru, парсер вакансий hh, выгрузка вакансий hh.ru, скрапер hh.ru, russian job board scraper, hh.ru salary data, hh.ru to csv, hh.ru to json, job scraping russia, headhunter vacancy scraper, hh.ru monitoring

# Actor input Schema

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

Full hh.ru URLs to crawl. Search URLs (e.g. `https://hh.ru/search/vacancy?text=python&area=1`), catalog pages (e.g. `https://hh.ru/vacancies/programmist`), and direct vacancy URLs (`https://hh.ru/vacancy/123456789`) can be mixed in the same list.

## `searchKeywords` (type: `array`):

One search per keyword — each entry becomes `https://hh.ru/search/vacancy?text={keyword}`. Ignored when hh.ru URLs are provided above.

## `area` (type: `string`):

hh.ru numeric area ID applied to every keyword search. Common values: `1` Moscow, `2` Saint Petersburg, `113` all Russia, `3` Yekaterinburg, `4` Novosibirsk, `40` Kazakhstan, `97` Uzbekistan. Leave empty to search everywhere. Ignored when hh.ru URLs are provided above.

## `enrichEmails` (type: `boolean`):

If enabled, tries to find a contact email for each employer by reading its own website (the vacancy page often links it) or discovering it by name. Adds contactEmail + contactWebsite columns plus a detailed emailEnrichment object. Best-effort, billed per contact email found; only charged when an email is returned, never for misses.

## `monitoringMode` (type: `boolean`):

When enabled, vacancies whose ID has already been delivered to you are silently skipped (no detail page is fetched and no charge applies for them). The first run after enabling monitoring returns every match — that builds your baseline. Every subsequent run returns only new postings. Combine with Apify's scheduler for a 'jobs posted since last run' feed.

## `resetMonitoringState` (type: `boolean`):

One-shot toggle: clear the saved 'vacancies already seen' record at the start of this run. Use this when you change search URL, want to rebuild the baseline, or recover from a missed delivery. Has no effect when monitoring mode is off.

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

Hard cap on the number of vacancies collected. Note: hh.ru serves at most 2,000 results per search query (40 pages × 50) — narrow by region or keyword to reach deeper inventory.

## `maxConcurrency` (type: `integer`):

Maximum number of vacancy pages processed in parallel.

## `minConcurrency` (type: `integer`):

Minimum number of vacancy pages processed in parallel.

## `maxRequestRetries` (type: `integer`):

Number of retries before a failed request is given up.

## `proxy` (type: `object`):

Leave empty — the actor already routes all traffic through its own built-in residential proxy at no extra cost to you (hh.ru blocks datacenter IPs). Only set this if you want to use your own proxies.

## Actor input object example

```json
{
  "startUrls": [
    "https://hh.ru/search/vacancy?text=python&area=1"
  ],
  "enrichEmails": false,
  "monitoringMode": false,
  "resetMonitoringState": false,
  "maxItems": 1000,
  "maxConcurrency": 10,
  "minConcurrency": 1,
  "maxRequestRetries": 5
}
```

# 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 = {
    "startUrls": [
        "https://hh.ru/search/vacancy?text=python&area=1"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/hh-ru-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 = { "startUrls": ["https://hh.ru/search/vacancy?text=python&area=1"] }

# Run the Actor and wait for it to finish
run = client.actor("memo23/hh-ru-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    "https://hh.ru/search/vacancy?text=python&area=1"
  ]
}' |
apify call memo23/hh-ru-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=memo23/hh-ru-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "hh.ru (HeadHunter) Job Scraper",
        "description": "Scrape job vacancies from hh.ru (HeadHunter) — title, salary with gross/net flag, employer rating, key skills, metro and GPS coordinates, full description. Works with any search URL, catalog page, or keywords. Built-in residential proxy, monitoring mode for new-only feeds. JSON/CSV.",
        "version": "0.0",
        "x-build-id": "EZJlr1uGsexL5mE3J"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/memo23~hh-ru-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-memo23-hh-ru-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/memo23~hh-ru-scraper/runs": {
            "post": {
                "operationId": "runs-sync-memo23-hh-ru-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/memo23~hh-ru-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-memo23-hh-ru-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "startUrls": {
                        "title": "hh.ru URLs",
                        "type": "array",
                        "description": "Full hh.ru URLs to crawl. Search URLs (e.g. `https://hh.ru/search/vacancy?text=python&area=1`), catalog pages (e.g. `https://hh.ru/vacancies/programmist`), and direct vacancy URLs (`https://hh.ru/vacancy/123456789`) can be mixed in the same list.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "searchKeywords": {
                        "title": "Search keywords",
                        "type": "array",
                        "description": "One search per keyword — each entry becomes `https://hh.ru/search/vacancy?text={keyword}`. Ignored when hh.ru URLs are provided above.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "area": {
                        "title": "Area ID (region filter for keyword searches)",
                        "type": "string",
                        "description": "hh.ru numeric area ID applied to every keyword search. Common values: `1` Moscow, `2` Saint Petersburg, `113` all Russia, `3` Yekaterinburg, `4` Novosibirsk, `40` Kazakhstan, `97` Uzbekistan. Leave empty to search everywhere. Ignored when hh.ru URLs are provided above."
                    },
                    "enrichEmails": {
                        "title": "Enrich with employer contact emails (experimental, billed per email)",
                        "type": "boolean",
                        "description": "If enabled, tries to find a contact email for each employer by reading its own website (the vacancy page often links it) or discovering it by name. Adds contactEmail + contactWebsite columns plus a detailed emailEnrichment object. Best-effort, billed per contact email found; only charged when an email is returned, never for misses.",
                        "default": false
                    },
                    "monitoringMode": {
                        "title": "Monitoring mode (only return vacancies not seen on previous runs)",
                        "type": "boolean",
                        "description": "When enabled, vacancies whose ID has already been delivered to you are silently skipped (no detail page is fetched and no charge applies for them). The first run after enabling monitoring returns every match — that builds your baseline. Every subsequent run returns only new postings. Combine with Apify's scheduler for a 'jobs posted since last run' feed.",
                        "default": false
                    },
                    "resetMonitoringState": {
                        "title": "Reset monitoring state (one-shot)",
                        "type": "boolean",
                        "description": "One-shot toggle: clear the saved 'vacancies already seen' record at the start of this run. Use this when you change search URL, want to rebuild the baseline, or recover from a missed delivery. Has no effect when monitoring mode is off.",
                        "default": false
                    },
                    "maxItems": {
                        "title": "Maximum items to scrape",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Hard cap on the number of vacancies collected. Note: hh.ru serves at most 2,000 results per search query (40 pages × 50) — narrow by region or keyword to reach deeper inventory.",
                        "default": 1000
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Maximum number of vacancy pages processed in parallel.",
                        "default": 10
                    },
                    "minConcurrency": {
                        "title": "Min concurrency",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Minimum number of vacancy pages processed in parallel.",
                        "default": 1
                    },
                    "maxRequestRetries": {
                        "title": "Max request retries",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Number of retries before a failed request is given up.",
                        "default": 5
                    },
                    "proxy": {
                        "title": "Proxy configuration (optional override)",
                        "type": "object",
                        "description": "Leave empty — the actor already routes all traffic through its own built-in residential proxy at no extra cost to you (hh.ru blocks datacenter IPs). Only set this if you want to use your own proxies."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
