HH.kz Job Scraper — Vacancies, Salaries & Employers
Pricing
from $2.70 / 1,000 result items
HH.kz Job Scraper — Vacancies, Salaries & Employers
hh.kz (HeadHunter Kazakhstan) vacancies for recruiters, salary benchmarking, B2B lead-gen and AI agents: all site filters (city, role, industry, employer, experience, schedule, format, salary), salary range, employer, address, optional full vacancy text and skills.
Pricing
from $2.70 / 1,000 result items
Rating
0.0
(0)
Developer
Samat Makatov
Maintained by CommunityActor stats
0
Bookmarked
14
Total users
14
Monthly active users
4 days ago
Last modified
Categories
Share
Structured vacancies from hh.kz (HeadHunter Kazakhstan), the country's largest job board — also works for hh.ru and hh.uz. Every hh.kz search filter is available: city or region, professional role, industry, employer, experience, employment type, schedule, work format, salary with currency, labels such as "no agencies", exclusion words, publication period and sort. Each vacancy comes with salary range (also converted to one currency at hh's own exchange rates), employer (id, verified, accredited IT), address with coordinates, experience, schedule, work format, publication date and number of responses; detail: true adds the full description, key skills and contacts published by the employer. Several searches can run in one go, a scheduled run can return only vacancies it has not delivered before (onlyNew), and a search bigger than hh's 2000-result cap is read in parts. Built for recruiters, HR analytics, B2B sales teams and AI agents.
No API key, no proxy, no browser — plain HTTP to the public hh.kz pages (hh's official API now answers 403 to anonymous clients, so the actor reads the data embedded in the site pages).
Need it tailored to your workflow? Missing a field, a filter, another source or a different output format? Open an issue and describe what you need — we read every request and adapt the actor.
Нужна доработка под вашу задачу? Не хватает поля, фильтра или другого формата выгрузки — откройте тикет и опишите, что нужно: читаем каждый запрос и дорабатываем актор.
Use cases
- Salary benchmarking — several positions in one run (
queries: ["бухгалтер", "кассир", "менеджер по продажам"],onlyWithSalary: true,maxItemsPerQuery), then mediansalaryFromConverted/salaryToConvertedbyqueryandexperience: USD, EUR and RUR offers are converted to KZT (or yourcurrency) at hh's own rates. The Salaries view shows exactly these columns. - B2B lead generation — companies that are hiring are companies that are growing:
professionalRoles+area+ the Employers view gives a fresh list of employers with ids and pages;detail: trueadds the full vacancy text and key skills (hh now shows contacts only after a click, so they are rarely in the data). - Competitor hiring monitor — the
employerIdof several competitors at once ("123401, 1245405"), scheduled daily withonlyNew: true: each run lists only the vacancies they opened since the last one, with pay. - Fresh-vacancy alerts —
onlyNew: true+sinceHours: 24, hourly, for a role in your city: every vacancy reaches your Slack/Telegram once, even when the employer bumps it. - Labour-market research — demand by region (
area), industry (industry) and work format (workFormat: ["REMOTE"]), withsearchTotalas market size;maxItemsup to 10 000 reads a big search past hh's 2000 cap. - Job-search agents — feed an LLM with description + key skills to match candidates.
Input
All fields are optional, but give at least one of query / queries, employerId, professionalRoles.
| Field | Type | Default | Allowed values / notes |
|---|---|---|---|
query | string | – | hh search syntax: "exact phrase", OR, NOT, !word. |
queries | string[] | [] | More searches with the same filters, one after another (up to 50; query runs first). Each row's query names its search. A vacancy two searches find is saved once, under the first, unless dedupe is off. |
site | string | hh.kz | hh.kz, hh.ru, hh.uz |
area | string | – | Area id, Russian name or latin alias; several comma-separated ("160,159", "almaty, Астана"). Empty = the whole country of the site (hh.kz → Kazakhstan 40, hh.ru → Russia 113, hh.uz → Uzbekistan 97). See Reference → Areas. |
searchFields | string[] | all | name, company_name, description |
excludeWords | string[] | [] | Exclude vacancies containing these words. |
professionalRoles | string[] | [] | Role ids or exact Russian names (96 programmer, 18 accountant). Reference → Professional roles. |
industry | string[] | [] | Industry ids (7 IT, 43 finance) or sub-industry 7.540. |
employerId | string | – | Number from https://hh.kz/employer/<id>; several separated by commas ("123401, 1245405") are searched together. A pasted employer link is read as its id. |
experience | string | "" | One of noExperience, between1And3, between3And6, moreThan6. |
employment | string[] | [] | full, part, project, volunteer, probation |
schedule | string[] | [] | fullDay, shift, flexible, remote, flyInFlyOut |
workFormat | string[] | [] | ON_SITE, REMOTE, HYBRID, FIELD_WORK |
partTime | string[] | [] | See Reference. |
labels | string[] | [] | not_from_agency, with_address, accredited_it, low_performance, … |
salaryFrom | integer | – | Salary range must include this amount (in currency). |
currency | string | KZT | KZT, USD, EUR, RUR (Russian rubles, as hh writes them), UZS, KGS, … — full list in Reference → Currencies. Also the currency of salaryFromConverted / salaryToConverted. |
onlyWithSalary | boolean | false | Drop vacancies without salary. |
period | string | "" | 1, 3, 7, 30 days (server-side). |
sinceHours | integer | – | Published within N hours; switches sort to newest and stops paging at the first older vacancy. |
onlyNew | boolean | false | Output only vacancies no earlier run with the same filters delivered — see Monitoring with onlyNew. Keeps one row per vacancy (dedupe stays on). |
sort | string | publication_time | publication_time (newest first, the complete list), relevance, salary_desc, salary_asc. relevance puts the best matches first but past the first ~100 vacancies hh's relevance order shifts while paging (see Limits). |
maxItems | integer | 50 | 1–10 000, for the whole run (all queries together). hh serves at most 2000 per search; above that the search is read in parts — see More than 2000 vacancies. |
maxItemsPerQuery | integer | – | With several queries: at most this many per query (maxItems still caps the run). |
maxPages | integer | 20 | 1–20 per search (100 vacancies per page). |
detail | boolean | false | Open each vacancy: description, key skills, archived flag, professional roles, coordinates; contacts only when hh puts them on the page (rare: hh now loads them after a click). +1 request per vacancy. |
dedupe | boolean | true | Skip a vacancy id already saved in this run (hh sometimes shows one vacancy on two pages). |
fields | string[] | [] | Keep only these output fields, in this order (names from Output). id, url and detailError are always kept. Letter case and spaces are forgiven ("salary from" → salaryFrom); an unknown name is skipped with a "did you mean" warning in the status and SUMMARY; if no name is valid the run stops before anything is charged except the start. |
Every filter is applied by hh itself, so counts match the site.
Wrong values. A non-numeric employerId stops the run before any request. The select fields (site, experience, employment, schedule, workFormat, partTime, labels, searchFields, currency, period, sort) accept only the values listed in Reference: Apify refuses any other value before the run starts and shows the allowed list — no run, no charge. The free-text filters area, professionalRoles and industry must name something known: an unknown city, role name or a non-numeric industry stops the run with a "did you mean" hint (only the start is charged). A filter is never dropped silently — that would quietly search the whole country. Numeric area and role ids that are not in the tables below (for example hh.ru cities) are passed to hh as they are, with a warning in the log.
Reference
Areas (area)
Kazakhstan = 40. Regions and their towns (hh area ids). Russian names and these latin aliases also work: kazakhstan→40, kz→40, almaty→160, astana→159, nur-sultan→159, shymkent→205, karaganda→177, karagandy→177, aktobe→154, aktau→152, atyrau→153, pavlodar→181, oskemen→194, ust-kamenogorsk→194, semey→185, kostanay→172, kostanai→172, kyzylorda→174, oral→193, uralsk→193, petropavlovsk→180, petropavl→180, taraz→187, taldykorgan→188, turkestan→192, kokshetau→176, temirtau→190, ekibastuz→198, zhezkazgan→166, rudny→182, konaev→171, kapchagay→171, atyrau-region→17955.
| Region / city | id | Towns (id) |
|---|---|---|
| Абайская область | 17951 | Арташат 11484, Аягоз (Абайская область) 157, Батпак 5118, Жезкент 6989, Калбатау 11163, Кокпекты 6513, Курчатов (Казахстан) 5051, Маканчи 6512, Семей 185, Урджар 6453, Чарск (Шар) 3704 |
| Акмолинская область | 17952 | Акколь 2728, Астраханка 6529, Атбасар 3663, Бурабай 5129, Державинск 11076, Ерейментау (Акмолинская область) 165, Есиль 6292, Жаксы 5124, Жибек Жолы 11330, Зеренда 11183, Кокшетау 176, Косшы 6393, Макинск 2950, Софиевка (Казахстан) 6186, Степногорск 2437, Степняк 5164, Тасты-Талды 7003, Щучинск 197, Дамса (Акмолинская область) 18129 |
| Актюбинская область | 17953 | Актобе 154, Алга (Актюбинская область) 156, Жем 6947, Кандыагаш 3074, Карауылкельды 11078, Кобда 11768, Мартук (Актюбинская область) 11291, Хромтау 195, Шалкар 6348, Эмба 6948 |
| Алматы | 160 | – |
| Алматинская область | 17954 | Алатау 11524, Байсерке ( Алматинская область) 11293, Боралдай 11180, Ельтай 11329, Есик 6287, Казцик 11237, Каргалы 11258, Каскелен 2653, Кеген 6495, Конаев 171, Междуреченское 11238, Нарынкол 6494, Отеген-Батыр 6299, Рыскулово 6501, Талгар 3048, Узынагаш (Алматинская область) 6248, Чунджа 4637, Шамалган 11231, Шелек 6108 |
| Астана | 159 | – |
| Атырауская область | 17955 | Аккистау 11083, Атырау 153, Кульсары 3034, Макат (Атырауская область) 11292, Тенгизское нефтяное месторождение 18564 |
| Восточно-Казахстанская область | 17956 | Алтай (Зыряновск) 169, Глубокое (Восточно-Казахстанская область) 6431, Зайсан 168, Новая Бухтарма 11082, Риддер (Восточно-Казахстанская область) 183, Серебрянск 2755, Солнечное (Глубоковский район) 6480, Улкен-Нарын 6935, Усть-Каменогорск 194, Чапаево 6473, Шемонаиха (Восточно-Казахстанская область) 196 |
| Жамбылская область | 17957 | Аса 6493, Бауыржан Момышулы 6488, Жанатас 167, Каратау 178, Кордай 4491, Кулан 6487, Мерке 6486, Мойынкум 6485, Сарыкемер 6484, Тараз 187, Шу 2729 |
| Жетысуская область | 17958 | Актогай (Жетысуская область) 6365, Балпык-Би (Жетысуская область) 6497, Достык (Жетысуская область) 17633, Жансугуров 6496, Жаркент 6104, Кабанбай 6460, Карабулак (Жетысуская область) 6358, Матай 11333, Сарканд 4304, Сарыозек 6459, Талдыкорган 188, Текели 189, Ушарал 6349, Уштобе 6250 |
| Западно-Казахстанская область | 17959 | Аксай (Казахстан) 150, Дарьинское 6483, Жангала 6482, Жанибек 6481, Жымпиты 6479, Каратобе 6478, Перемётное 6477, Сайхин 6476, Тайпак 6475, Таскала 6474, Уральск 193, Чингирлау 6472 |
| Карагандинская область | 17960 | Абай 6251, Атасу 6351, Балхаш 164, Караганда 177, Каркаралинск 6342, Осакаровка 5117, Приозёрск (Карагандинская область) 6395, Сарань 6017, Темиртау 190, Шахтинск 6290 |
| Костанайская область | 17961 | Айет 6782, Аркалык 161, Аулиеколь 5053, Боровской 6778, Бауманское (Костанайская область) 17639, Житикара 6322, Карабалык 5054, Качар 5052, Костанай 172, Кушмурун 6780, Лисаковск 6297, Рудный 182, Сарыколь 6779, Тобыл 11723, Торгай 191, Фёдоровка 6781 |
| Кызылординская область | 17962 | Айтеке-Би 11071, Аральск 158, Байконур (Кызылординская область) 2226, Жалагаш (Кызылординская область) 6347, Жанакорган 6446, Жосалы (Кызылординская область) 6346, Казалы (Кызылординская область) 175, Кызылорда 174, Саксаульский 5126, Теренозек 11194, Торетам 6344, Шиели 6324 |
| Мангистауская область | 17963 | Актау 152, Баутино 162, Бейнеу (Мангистауская область) 163, Жанаозен 2510, Жетыбай (Мангистауская область) 6525, Курык 11162, Мангистау 6244, Шетпе 6524 |
| Павлодарская область | 17964 | Аксу (Павлодарская область) 151, Иртышск 11332, Павлодар 181, Солнечный (ПГТ, Павлодарская область) 186, Торткудук 6366, Экибастуз 198 |
| Северо-Казахстанская область | 17965 | Бесколь 5055, Новоишимское 5056, Петропавловск 180, Рассвет (Кызылжарский район) 11275, Сергеевка (Северо-Казахстанская область) 6060, Тайынша 5042, Талшик 6325 |
| Туркестанская область | 17966 | Аксукент 6254, Арысь (Туркестанская область) 6300, Арысь (ЮКО) 155, Асыката 6511, Атакент 6510, Жетысай 2952, Жетысу 11331, Казыгурт 6509, Карабулак (Сайрамский район) 11072, Кентау (Туркестанская область) 173, Ленгер (Туркестанская область) 179, Мырзакент 6503, Сайрам 6502, Сарыагаш 2951, Село имени Турара Рыскулова 11073, Темирлановка 11525, Туркестан 192, Шардара 6388, Шаульдер 6500, Шаян 6499, Шолаккорган 6498 |
| Улытауская область | 17967 | Жайрем 6343, Жезказган 166, Каражал 6471, Сатпаев 184 |
| Шымкент | 205 | – |
Other countries: Russia 113 (Moscow 1, St Petersburg 2), Uzbekistan 97, Kyrgyzstan 48, Belarus 16 — full tree at https://api.hh.ru/areas.
Professional roles (professionalRoles)
Industries (industry)
| id | Meaning |
|---|---|
5 | Перевозки, логистика, склад, ВЭД |
7 | Информационные технологии, системная интеграция, интернет |
8 | Электроника, приборостроение, бытовая техника, компьютеры и оргтехника |
9 | Телекоммуникации, связь |
11 | СМИ, маркетинг, реклама, BTL, PR, дизайн, продюсирование |
13 | Строительство, недвижимость, эксплуатация, проектирование |
15 | Автомобильный бизнес |
19 | Лесная промышленность, деревообработка |
24 | Металлургия, металлообработка |
27 | Продукты питания |
29 | Сельское хозяйство |
33 | Тяжелое машиностроение |
34 | Химическое производство, удобрения |
36 | Государственные организации |
37 | Общественная деятельность, партии, благотворительность, НКО |
39 | Образовательные учреждения |
41 | Розничная торговля |
42 | Товары народного потребления (непищевые) |
43 | Финансовый сектор |
44 | Услуги для бизнеса |
45 | Добывающая отрасль |
46 | Энергетика |
47 | Нефть и газ |
48 | Медицина, фармацевтика, аптеки |
49 | Услуги для населения |
50 | Гостиницы, рестораны, общепит, кейтеринг |
51 | ЖКХ |
52 | Искусство, культура |
388 | Промышленное оборудование, техника, станки и комплектующие |
389 | Управление многопрофильными активами |
Experience (experience)
| Value | Meaning |
|---|---|
noExperience | Нет опыта |
between1And3 | От 1 года до 3 лет |
between3And6 | От 3 до 6 лет |
moreThan6 | Более 6 лет |
Employment (employment)
| Value | Meaning |
|---|---|
full | Полная занятость |
part | Частичная занятость |
project | Проектная работа |
volunteer | Волонтерство |
probation | Стажировка |
Schedule (schedule)
| Value | Meaning |
|---|---|
fullDay | Полный день |
shift | Сменный график |
flexible | Гибкий график |
remote | Удаленная работа |
flyInFlyOut | Вахтовый метод |
Work format (workFormat)
| Value | Meaning |
|---|---|
ON_SITE | На месте работодателя |
REMOTE | Удалённо |
HYBRID | Гибрид |
FIELD_WORK | Разъездной |
Part-time (partTime)
| Value | Meaning |
|---|---|
employment_project | Project work |
employment_part | Part-time employment |
temporary_job_true | Temporary job |
from_four_to_six_hours_in_a_day | Shifts of 4-6 hours a day |
only_saturday_and_sunday | Saturdays and Sundays only |
start_after_sixteen | Day starts after 16:00 |
Labels (labels)
| Value | Meaning |
|---|---|
with_address | Только с адресом |
accept_handicapped | Только доступные для людей с инвалидностью |
not_from_agency | Без вакансий агентств |
accept_kids | Только доступные для соискателей от 14 лет |
accredited_it | Только аккредитованные ИТ-компании |
low_performance | Только вакансии, у которых меньше 10 откликов |
internship | Стажировка |
night_shifts | Вечерние или ночные смены |
with_salary | Указан доход |
accept_teens | Только доступные для соискателей от 16 лет |
accept_labor_contract | Трудовой договор |
Search fields (searchFields)
| Value | Meaning |
|---|---|
name | в названии вакансии |
company_name | в названии компании |
description | в описании вакансии |
Sort (sort)
| Value | Meaning |
|---|---|
publication_time | по дате |
salary_desc | по убыванию дохода |
salary_asc | по возрастанию дохода |
relevance | по соответствию |
Currencies (currency)
| Code | Name | In active use on hh.kz |
|---|---|---|
AZN | Манаты (₼) | no |
BYR | Белорусские рубли (Br) | no |
EUR | Евро (€) | yes |
GEL | Грузинский лари (₾) | no |
KGS | Кыргызский сом (сом) | no |
KZT | Тенге (₸) | yes |
RUR | Рубли (₽) | no |
UAH | Гривны (₴) | no |
USD | Доллары ($) | yes |
UZS | Узбекский сум (so'm) | no |
Examples
Salary benchmark — accountants in Almaty and Astana with stated salary
{ "query": "бухгалтер", "area": "160,159", "searchFields": ["name"], "onlyWithSalary": true, "labels": ["not_from_agency"], "maxItems": 1000 }
Hourly alert — new remote Python vacancies in Kazakhstan
{ "query": "python", "workFormat": ["REMOTE"], "sinceHours": 2, "maxItems": 100 }
B2B leads — companies hiring sales managers in Karaganda, with the full vacancy text
{ "professionalRoles": ["70"], "area": "karaganda", "labels": ["not_from_agency"], "detail": true, "maxItems": 200 }
Competitor hiring monitor — all open vacancies of one employer
{ "employerId": "1374179", "detail": true, "maxItems": 500 }
Daily competitor monitor — only the vacancies two banks opened since the last run
{ "employerId": "123401, 1245405", "onlyNew": true, "sort": "publication_time", "maxItems": 200 }
Salary benchmark for three positions in one run, salaries in KZT
{ "queries": ["бухгалтер", "кассир", "менеджер по продажам"], "searchFields": ["name"], "area": "almaty", "onlyWithSalary": true, "maxItemsPerQuery": 300, "maxItems": 900 }
Whole market — every vacancy for "менеджер" in Kazakhstan (more than hh's 2000 per search)
{ "query": "менеджер", "searchFields": ["name"], "maxItems": 10000 }
Senior IT market — 3+ years experience, salary from 1 000 000 ₸, highest paid first
{ "industry": ["7"], "experience": "between3And6", "salaryFrom": 1000000, "currency": "KZT", "sort": "salary_desc", "maxItems": 300 }
Output
One dataset item per vacancy, saved as soon as it is ready (per search page; with detail: true per 10 vacancies). Use fields to keep only some of the fields below. Views: Overview, Employers (lead-gen), Salaries (benchmark), Full vacancy (detail mode). Example (real run, trimmed, detail: false):
{"id": "136428479","url": "https://hh.kz/vacancy/136428479","title": "Senior Python разработчик","employer": { "id": "11630327", "name": "My Startups", "url": "https://hh.kz/employer/11630327", "trusted": true, "accreditedIt": false, "category": "COMPANY" },"salaryFrom": null, "salaryTo": null, "salaryCurrency": null, "salaryGross": null,"salaryFromConverted": null, "salaryToConverted": null, "salaryConvertedCurrency": null,"areaId": "160", "areaName": "Алматы", "address": "Алматы, улица Абдуллы Розыбакиева, 247А", "lat": 43.202449, "lon": 76.89197,"experience": "between3And6", "employment": "full", "schedule": "fullDay","workFormats": ["ON_SITE"], "workingHours": ["HOURS_8"], "workScheduleByDays": ["FIVE_ON_TWO_OFF"],"remote": false, "internship": false, "nightShifts": false,"publishedAt": "2026-09-13T04:22:13.287Z", "createdAt": "2026-08-20T04:22:13.287Z", "responsesCount": 457,"responsibilitySnippet": "Разработка и поддержка бэкэнд приложений. Проектирование архитектуры. Разработка API…","requirementSnippet": "Глубокое знание языка программирования Python…","keySkills": null, "description": null, "contacts": null,"site": "hh.kz", "query": "python developer", "searchTotal": 261, "fetchedAt": "2026-09-13T08:12:14.505Z"}
| Field | Description |
|---|---|
id, url, title | hh vacancy id, canonical URL, title |
employer | id, name, url, trusted (verified by hh), accreditedIt (accredited IT company), category |
salaryFrom, salaryTo, salaryCurrency, salaryGross, salaryMode, salaryFrequency | Salary range as posted; salaryGross: false = net ("на руки"); salaryMode = the pay period (MONTH, SHIFT, HOUR, FLY_IN_FLY_OUT, SERVICE) |
salaryFromConverted, salaryToConverted, salaryConvertedCurrency | The same range in the run's currency (KZT by default) at the exchange rates hh states on its search page, rounded to whole units. Same pay period and gross/net as posted. null when there is no salary or hh states no rate for that currency (hh.kz lists KZT, USD, EUR; RUR is hh's base) |
areaId, areaName, address, lat, lon | Location |
experience, employment, schedule, workFormats, workingHours, workScheduleByDays | Conditions (codes from Reference) |
remote, internship, nightShifts, acceptTemporary | Flags |
publishedAt, createdAt | Last publication (bump) and creation time, ISO |
responsesCount | Number of applications — a competition signal |
responsibilitySnippet, requirementSnippet | Short text from the search card |
professionalRoleIds, professionalRoles | Role ids and names, when hh includes them in the page data |
keySkills, description, contacts, archived, ageRestriction | With detail: true; contacts is null unless the vacancy page carries them (hh now loads contacts after a click, so this is rare) |
site, query, searchTotal, fetchedAt | Search scope, the search (of query / queries) that found the vacancy, total vacancies hh reports for that search (the whole search, also when it was read in parts), fetch time |
detailError | Present only when the vacancy page could not be opened (removed, hh error, block): the row keeps its search data |
Use it from code / agents
curl -X POST "https://api.apify.com/v2/acts/yadroo~hh-kz-vacancies/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"query":"бухгалтер","area":"almaty","onlyWithSalary":true,"maxItems":100}'
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('yadroo/hh-kz-vacancies').call({ query: 'python', workFormat: ['REMOTE'], sinceHours: 24 });const { items } = await client.dataset(run.defaultDatasetId).listItems();
from apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("yadroo/hh-kz-vacancies").call(run_input={"employerId": "1374179", "detail": True})items = client.dataset(run["defaultDatasetId"]).list_items().items
MCP: add https://mcp.apify.com to Claude / Cursor / any MCP client and call the yadroo/hh-kz-vacancies tool with the same JSON input.
Pricing
Pay per event: $0.02 per run start + $0.003 per vacancy. No proxy or browser costs.
Store discounts: Bronze −5 %, Silver and above −10 % on the vacancy price; the start event is the same on every plan; platform usage is included.
Your maximum cost per run is respected: the run stops before the first vacancy it would not pay for, keeps every vacancy saved so far and ends with "Stopped at your spending limit: N rows delivered". In detail mode no vacancy page is opened that the limit would not pay for.
Typical runs: 50 vacancies ≈ $0.17; a 1000-vacancy salary benchmark ≈ $3.02; an hourly onlyNew alert that finds 10 new vacancies ≈ $0.05 (vacancies delivered before are skipped, not billed); a 10 000-vacancy market snapshot ≈ $30.02. detail: true costs the same per vacancy but takes ~1 s per vacancy longer.
Limits & FAQ
- More than 2000 vacancies — hh serves at most 2000 results per search. With
maxItemsabove 2000, a bigger search is read in parts: by region or city (when their counts add up to at least 98 % of the search: vacancies filed under a whole region or the country without a city are in no part — 13 of 6608 in our test on 2026-10-21 — and the status andSUMMARY.queries[].uncoveredBySplitsay how many), otherwise by experience (always complete), then by professional role, and merged without duplicates; every row keeps the total of the whole search insearchTotal. Rows then come part by part, each part newest first (the order hh pages without repeats). A part that still has more than 2000 after all three is cut at 2000 and the status says so.SUMMARY.queries[].splitSearchesshows how many parts were read. The first page of a search that gets split only serves to count it (one extra request). - Speed and the run timeout — a search page of 100 vacancies takes ~1.6 s at the top and 4–6 s deeper, with a 0.7 s pause between pages. Measured in the Apify cloud on 2026-10-21: 50 vacancies in ~6 s; 5000 vacancies (one search read as 23 parts, 66 pages) in 5 min 46 s, about 870 vacancies a minute; so 2000 vacancies without
detailtake 2–3 minutes and 10 000 about 12 minutes.detail: trueopens one page per vacancy at a polite pace: about 23 vacancies a minute, ~1,300 in the default 1-hour timeout. Vacancies are saved as they are ready; a run that nears its timeout stops starting new pages ~90 s before it and ends SUCCEEDED with "Stopped before the run timeout: N rows saved". For 2000 vacancies with detail, raise the run timeout to 2 hours or split the search byarea/professionalRoles. - Rate limits and blocks — ~0.7 s between search pages and ~1 s between vacancy pages; 429/5xx and network errors are retried with backoff. A 403 or a captcha page is an anti-bot wall: the run stops at once and does not try to get around it (no proxy, no captcha solving). Everything saved before stays in the dataset and the status says where hh blocked; if that happens on the first page, the run fails with that message and only the start is charged.
- Relevance order and complete lists — hh reshuffles its relevance order while you page through a search, so deeper pages repeat vacancies from earlier ones and about as many are never shown. Measured on 2026-10-21 ("менеджер" in Astana, 1598 vacancies): by relevance 1306 distinct vacancies, newest first all 1599. Repeats are dropped (no duplicate rows), counted in
SUMMARY.queries[].repeatedByHhand named in the status; that is why the default issort: "publication_time"(newest first) — chooserelevanceonly when the best matches on the first page matter more than completeness. The first page (100 vacancies) is not affected. - Vacancy pages that fail — a removed vacancy (404), a page hh does not serve after retries, or a page that carries no vacancy text this actor can read keeps its search data with
detailErrorand is billed like any row (it is never passed off as detail data); 5 failures in a row stop the run with a clear status. The first unreadable vacancy page is saved asDETAIL_PAGE_UNRECOGNIZEDin the run's key-value store, so a change of hh's page can be reported and fixed. - Contacts — only what the vacancy page itself carries. hh now loads an employer's contacts separately, after a click and often only for signed-in users, so the page — and
contacts— is almost always empty (null). Contacts behind a click or a login are not collected. - Professional roles in output —
professionalRoleIdsandprofessionalRolescome from hh's own page data, on search rows and detail rows alike. - Run summary — the
SUMMARYrecord of the run's key-value store lists the search URL, hh's total, pages read, per query (queries) hh's total, rows saved and parts read, the onlyNew memory record and how many vacancies it skipped, the exchange rates used, and, withdetail: true, how many vacancy pages were read, failed or were unreadable and where the vacancy text came from. - Freshness — live at run time.
publishedAtchanges when an employer bumps a vacancy. - Roadmap — employer profile mode (company description, all vacancies, rating), salary statistics output.
Monitoring with onlyNew
With onlyNew: true the actor remembers the id of every vacancy it delivered, in the named key-value store hh-kz-vacancies-seen of your Apify account, and skips those vacancies in later runs (skipped vacancies are not billed). The memory is one record per set of filters — site, queries, area, roles, industries, employers, experience, employment, schedule, work format, labels, salary and excluded words — and one per saved task, so two schedules never hide vacancies from each other. Changing sort, period, sinceHours, maxItems, detail or fields keeps the memory; changing a filter starts a new one. A vacancy that an employer bumps keeps its id and does not come again.
The first run returns every matching vacancy up to maxItems; vacancies cut off by maxItems, your spending limit or the run timeout are not remembered and come in the next run. Up to 50 000 ids are kept per record (the oldest are dropped first). To start over, delete the record in Storage → Key-value stores → hh-kz-vacancies-seen (its name is in SUMMARY.onlyNew.record). For hourly alerts, add sinceHours (e.g. 24): paging then stops at the first older vacancy, so the run stays short.
Made by Yadroo. Sibling actors: krisha-kz (real estate), kolesa-kz (cars), kaspi-kz-products (marketplace prices), autoscout24-cars (EU cars).