HH.kz Job Scraper — Vacancies, Salaries & Employers avatar

HH.kz Job Scraper — Vacancies, Salaries & Employers

Pricing

from $2.70 / 1,000 result items

Go to Apify Store
HH.kz Job Scraper — Vacancies, Salaries & Employers

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

Samat Makatov

Maintained by Community

Actor stats

0

Bookmarked

14

Total users

14

Monthly active users

4 days ago

Last modified

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 median salaryFromConverted/salaryToConverted by query and experience: USD, EUR and RUR offers are converted to KZT (or your currency) 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: true adds 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 employerId of several competitors at once ("123401, 1245405"), scheduled daily with onlyNew: 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"]), with searchTotal as market size; maxItems up 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.

FieldTypeDefaultAllowed values / notes
querystring–hh search syntax: "exact phrase", OR, NOT, !word.
queriesstring[][]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.
sitestringhh.kzhh.kz, hh.ru, hh.uz
areastring–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.
searchFieldsstring[]allname, company_name, description
excludeWordsstring[][]Exclude vacancies containing these words.
professionalRolesstring[][]Role ids or exact Russian names (96 programmer, 18 accountant). Reference → Professional roles.
industrystring[][]Industry ids (7 IT, 43 finance) or sub-industry 7.540.
employerIdstring–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.
experiencestring""One of noExperience, between1And3, between3And6, moreThan6.
employmentstring[][]full, part, project, volunteer, probation
schedulestring[][]fullDay, shift, flexible, remote, flyInFlyOut
workFormatstring[][]ON_SITE, REMOTE, HYBRID, FIELD_WORK
partTimestring[][]See Reference.
labelsstring[][]not_from_agency, with_address, accredited_it, low_performance, …
salaryFrominteger–Salary range must include this amount (in currency).
currencystringKZTKZT, USD, EUR, RUR (Russian rubles, as hh writes them), UZS, KGS, … — full list in Reference → Currencies. Also the currency of salaryFromConverted / salaryToConverted.
onlyWithSalarybooleanfalseDrop vacancies without salary.
periodstring""1, 3, 7, 30 days (server-side).
sinceHoursinteger–Published within N hours; switches sort to newest and stops paging at the first older vacancy.
onlyNewbooleanfalseOutput only vacancies no earlier run with the same filters delivered — see Monitoring with onlyNew. Keeps one row per vacancy (dedupe stays on).
sortstringpublication_timepublication_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).
maxItemsinteger501–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.
maxItemsPerQueryinteger–With several queries: at most this many per query (maxItems still caps the run).
maxPagesinteger201–20 per search (100 vacancies per page).
detailbooleanfalseOpen 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.
dedupebooleantrueSkip a vacancy id already saved in this run (hh sometimes shows one vacancy on two pages).
fieldsstring[][]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 / cityidTowns (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)

idMeaning
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)

ValueMeaning
noExperienceНет опыта
between1And3От 1 года до 3 лет
between3And6От 3 до 6 лет
moreThan6Более 6 лет

Employment (employment)

ValueMeaning
fullПолная занятость
partЧастичная занятость
projectПроектная работа
volunteerВолонтерство
probationСтажировка

Schedule (schedule)

ValueMeaning
fullDayПолный день
shiftСменный график
flexibleГибкий график
remoteУдаленная работа
flyInFlyOutВахтовый метод

Work format (workFormat)

ValueMeaning
ON_SITEНа месте работодателя
REMOTEУдалённо
HYBRIDГибрид
FIELD_WORKРазъездной

Part-time (partTime)

ValueMeaning
employment_projectProject work
employment_partPart-time employment
temporary_job_trueTemporary job
from_four_to_six_hours_in_a_dayShifts of 4-6 hours a day
only_saturday_and_sundaySaturdays and Sundays only
start_after_sixteenDay starts after 16:00

Labels (labels)

ValueMeaning
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)

ValueMeaning
nameв названии вакансии
company_nameв названии компании
descriptionв описании вакансии

Sort (sort)

ValueMeaning
publication_timeпо дате
salary_descпо убыванию дохода
salary_ascпо возрастанию дохода
relevanceпо соответствию

Currencies (currency)

CodeNameIn 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"
}
FieldDescription
id, url, titlehh vacancy id, canonical URL, title
employerid, name, url, trusted (verified by hh), accreditedIt (accredited IT company), category
salaryFrom, salaryTo, salaryCurrency, salaryGross, salaryMode, salaryFrequencySalary range as posted; salaryGross: false = net ("на руки"); salaryMode = the pay period (MONTH, SHIFT, HOUR, FLY_IN_FLY_OUT, SERVICE)
salaryFromConverted, salaryToConverted, salaryConvertedCurrencyThe 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, lonLocation
experience, employment, schedule, workFormats, workingHours, workScheduleByDaysConditions (codes from Reference)
remote, internship, nightShifts, acceptTemporaryFlags
publishedAt, createdAtLast publication (bump) and creation time, ISO
responsesCountNumber of applications — a competition signal
responsibilitySnippet, requirementSnippetShort text from the search card
professionalRoleIds, professionalRolesRole ids and names, when hh includes them in the page data
keySkills, description, contacts, archived, ageRestrictionWith 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, fetchedAtSearch 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
detailErrorPresent 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 ApifyClient
client = 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 maxItems above 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 and SUMMARY.queries[].uncoveredBySplit say how many), otherwise by experience (always complete), then by professional role, and merged without duplicates; every row keeps the total of the whole search in searchTotal. 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[].splitSearches shows 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 detail take 2–3 minutes and 10 000 about 12 minutes. detail: true opens 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 by area / 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[].repeatedByHh and named in the status; that is why the default is sort: "publication_time" (newest first) — choose relevance only 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 detailError and 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 as DETAIL_PAGE_UNRECOGNIZED in 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 — professionalRoleIds and professionalRoles come from hh's own page data, on search rows and detail rows alike.
  • Run summary — the SUMMARY record 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, with detail: true, how many vacancy pages were read, failed or were unreadable and where the vacancy text came from.
  • Freshness — live at run time. publishedAt changes 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).