HH.ru Scraper icon

HH.ru Scraper

Scrape HH.ru (HeadHunter) job listings by filters or URLs. Extract 50+ fields including salaries, experience, schedules, employment types and job…

Start using this actor on Apify ↗Need a custom scraper?Contact us ↗

HH.ru Scraper at a glance

HH.ru Scraper is a ready-to-run Apify actor from abotapi for collecting jobs data. Its documented output includes id, change type (incremental mode), url, title and published, which you can export as JSON, CSV or Excel or read through the Apify API. It costs $2.00 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify.

Runs on
Apify cloud: console, API, schedules and integrations
Data type
Jobs, Automation, Developer Tools
Region
Europe
Pricing
$2.00 per 1,000 results (Free plan), from $1.00 on paid plans
Output
Documented below · JSON, CSV, Excel
Inputs
25 options
Run success
100.0% of completed public runs in the last 30 days

Scrape HH.ru (HeadHunter) job listings by filters or URLs. Extract 50+ fields including salaries, experience, schedules, employment types and job roles. Optional enrichment adds full descriptions, required skills, contact details and employer logos.

What HH.ru Scraper can do

  • Three ways to find data. Build a search from keywords, area and filters, paste hh.ru search URLs as-is, or hand in specific vacancy links or IDs and get one full detail card per entry.
  • 50+ fields per vacancy. Salary ranges, GPS coordinates, metro stations, employer logos and badges, full HTML and plain-text descriptions, and key skills, plus employer details.
  • Detail on demand. Turn full detail-page enrichment on or off; results still stream into the dataset as each one finishes, so a mid-run stop keeps everything collected so far.
  • Full filter coverage. Search field (title-only or everywhere), experience, employment, schedule, salary range, only-with-salary, professional role, industry and sort order.
  • Built for schedules. Incremental mode returns only new and changed vacancies on recurring runs, and a run that can't reach hh.ru fails loudly instead of returning an empty dataset.
  • Clear about hh.ru's own 2000-result cap. Slice one broad search into narrower ones by area, salary band or role to capture everything beyond it.

Choose what to collect

These inputs let you configure HH.ru Scraper - Jobs, Salaries, Skills & Employers. Open the actor on Apify to enter your values and review the current options.

Supported input fields
InputWhat it controls
modestringSearch mode = type your keywords + area + filters and let the scraper build URLs. URL mode = paste any hh.ru search URL already refined in a browser (recommended for complex filters or saved searches). Vacancy mode = paste a list of specific vacancy URLs or IDs and get the full detail card for each (no search performed).

Choices: search, url, vacancy

queriesarrayOne or more keywords. Each keyword runs as a separate search. Examples: 'python', 'AI engineer', 'data scientist', 'Java middle'. Russian keywords are fine.
searchFieldstringControls WHERE hh.ru looks for your keyword. Vacancy title only (default) returns the roles whose TITLE matches your keyword, the relevant results you expect when you search by job title. Everywhere is hh.ru's own default: it matches the keyword anywhere in the vacancy (title, description, or company) and mixes in loosely-related roles, so a search for 'Продуктовый аналитик' also returns marketing directors and sales managers, switch to it only if you deliberately want that broad reach. 'Company name' and 'Description' restrict the match to those fields.

Choices: name, everywhere, company_name, description

areasarrayOptional. One or more hh.ru area IDs. Leave empty to search all of Russia (defaults to 113 = whole country). Common values: 1=Moscow, 2=Saint Petersburg, 113=Russia (whole country), 4=Novosibirsk, 88=Kazan, 1438=Yekaterinburg, 5=Krasnodar, 76=Rostov-on-Don, 78=Voronezh, 66=Nizhny Novgorod. Full list: https://api.hh.ru/areas
experiencestringFilter candidates by required experience.

Choices: any, noExperience, between1And3, between3And6, moreThan6

employmentarrayMulti-select. Leave empty to get all types.
schedulearrayMulti-select. Leave empty for all schedules.
Show 18 more inputs
More input fields
InputWhat it controls
salaryMinintegerMinimum monthly salary in RUB. Listings without a salary are still returned unless you also enable 'Only with salary'.
onlyWithSalarybooleanIf on, only listings that publish a salary range are returned.
orderBystringHow to order results. Default = relevance (hh.ru's own default).

Choices: relevance, publication_time, salary_desc, salary_asc, distance

professionalRolearrayOptional. Numeric professional role IDs to filter by. Examples: 96=Programmer/Developer, 156=Software engineer, 165=Data Analyst, 10=Project Manager. Full taxonomy: https://api.hh.ru/professional_roles
industryarrayOptional. Numeric industry IDs. Examples: 7=IT/Telecom, 9=Marketing/PR, 29=Finance. Full taxonomy: https://api.hh.ru/industries
urlsarrayOne or more full hh.ru search URLs. Tip: open hh.ru in your browser, pick keywords + area + filters, then paste the resulting URL here. Pagination starts at page in URL and walks forward.
vacancyInputarrayOne entry per vacancy you want a full detail card for. Accepts full URLs (https://hh.ru/vacancy/123456789), mobile URLs (https://m.hh.ru/vacancy/123456789), or bare numeric IDs (123456789). Each entry fetches that vacancy's page directly, no search runs, so hh.ru's 2000-result cap does not apply. Duplicate IDs are removed. Removed or archived vacancies are omitted from the dataset (never charged); each skipped ID is named in the run log and summarised in the run status message.
maxPagesintegerHow many result pages to walk per query / URL (Search and URL modes only; ignored in Vacancy mode). hh.ru returns 50 listings per page, so 2 pages ≈ 100 listings. Maximum is 40 pages, hh.ru's own hard cap is 2000 results per filter, so any single search beyond ~2000 matches must be split into narrower slices (by area, salary band, or role) to capture the rest. The run logs a warning when a search exceeds what's reachable.
maxListingsintegerHard cap across the whole run. 0 = unlimited (bounded only by Max pages).
fetchDetailsbooleanAdds the most valuable fields: full HTML description + plain-text version, keySkills array, employer logos, validThroughTime, hr-brand status, work format details, and metro station list. Turn off for a faster run with just the SERP-level fields. Note on contact info: hh.ru hides phone / email / advertiser name behind a login wall, so contactInfo.phones / .email / .name will be empty for non-authenticated scrapes. The actor returns contactInfo.contactsHidden=true for those listings. Some employers paste their contact details into the descriptionText (search the description if you need it). Each delivered vacancy whose detail page is read is charged as one detail-page event on top of the per-result charge; vacancies whose detail page is refused, and vacancies incremental mode suppresses as unchanged, are not charged.
resumeFromRunIdstringPaste a previous run ID or dataset ID to continue a large pull without returning or charging for vacancies already collected there. Use this after an interrupted run, or to keep extending one walk-all pull across separate runs. For recurring daily monitoring of the same search, use Incremental mode below instead.
incrementalModebooleanTurn this on for daily or recurring monitoring. The first run returns all matching vacancies as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED vacancies. Turn on "Emit unchanged" or "Emit expired" only when you also want those vacancies returned (and billed). State is kept separately per mode + search/URL/vacancy-list configuration; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.
stateKeystringOptional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the mode + search/URL/vacancy settings, different searches then never mix state with each other.
emitUnchangedbooleanOff by default. Turn on to also return vacancies that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you specifically want the full snapshot every run.
emitExpiredbooleanOff by default. Turn on to also return vacancies that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search, not when Max listings capped it or when Resume was used. This returns, and bills, extra synthetic rows, so leave it off unless you need expiry tracking.
mcpConnectorsarrayOptionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON, the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).
notionParentPageUrlstringURL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.
maxNotifyListingsintegerCap on items written to each connector per run. Does not affect the dataset.

Fields in the output

The documented dataset includes the fields below. Availability can depend on the source page and selected mode.

vacancyIdID
changeTypeChange type (incremental mode)
urlURL (link)
nameTitle
publicationDatePublished
company.nameCompany
company.isAccreditedITIT-accredited
salaryFromSalary from
salaryToSalary to
salaryCurrencyCurrency
area.nameCity
address.metroStationsMetro
Show 13 more fields
address.latLat
address.lngLng
workExperienceExperience
employmentFormEmployment
workFormatsFormat
workScheduleSchedule
keySkillsKey skills
responsesCountResponses
totalResponsesCountTotal responses
changedFieldsChanged fields (incremental mode)
firstSeenAtFirst seen (incremental mode)
lastSeenAtLast seen (incremental mode)
detailFetcheddetailFetched

Example output

An example from this actor’s documentation. Values are illustrative; this is not a fresh live result.

{
  "vacancyId": "100000001",
  "url": "https://hh.ru/vacancy/100000001",
  "name": "Senior Python-разработчик",
  "publicationDate": "2026-05-05T09:00:00.000+03:00",
  "creationDate": "2026-05-01T09:00:00.000+03:00",
  "lastChangeTime": "2026-05-04T09:00:00.000+03:00",
  "validThroughTime": "2026-06-04T09:00:00.000+03:00",
  "isAdv": false,
  "searchUrl": "https://hh.ru/search/vacancy?text=python&area=1&page=0",
  "searchSessionId": "00000000-0000-0000-0000-000000000000",
  "company": {
    "id": 1000000,
    "name": "ООО «Пример»",
    "isAccreditedIT": true,
    "isTrusted": true,
    "siteUrl": "https://www.example.com/",
    "logoUrl": "https://hh.ru/employer-logo-original/0000000.png",
    "badges": [
      {
        "type": "hrbrand",
        "description": "Пример награды"
      }
    ]
  },
  "salaryFrom": 200000,
  "salaryTo": 300000,
  "salaryCurrency": "RUR",
  "salaryGross": false,
  "salaryMode": "MONTH",
  "salaryFrequency": "TWICE_PER_MONTH",
  "area": {
    "id": 1,
    "name": "Москва",
    "path": ".113.1."
  },
  "address": {
    "city": "Москва",
    "street": "Тверская улица",
    "lat": 55.7558,
    "lng": 37.6173,
    "metroStations": [
      {
        "id": 1,
        "name": "Охотный Ряд",
        "lineColor": "#000000"
      }
    ],
    "district": "Тверской район"
  },
  "workExperience": "between3And6",
  "employment": "FULL",
  "employmentForm": "FULL",
  "workSchedule": "remote",
  "workFormats": [
    "REMOTE"
  ],
  "acceptHandicapped": false,
  "acceptLaborContract": true,
  "responsesCount": 42,
  "totalResponsesCount": 100,
  "onlineUsersCount": 5,
  "professionalRoleIds": [
    96,
    156
  ],
  "description": "<p>Обязанности: разработка и поддержка сервисов. Требования: опыт с Python 3+ года. Условия: удалённая работа, ДМС.</p>",
  "descriptionText": "Обязанности: разработка и поддержка сервисов. Требования: опыт с Python 3+ года. Условия: удалённая работа, ДМС.",
  "keySkills": [
    "Python",
    "Django",
    "PostgreSQL",
    "Docker",
    "Git"
  ],
  "contactInfo": {
    "name": null,
    "email": null,
    "phones": [],
    "contactsHidden": false
  },
  "detailScraped": true,
  "scrapedAt": "2026-05-05T12:00:00.000Z"
}

Ways to use this data

  • Recruiting and talent sourcing: build a candidate-facing job feed, or watch a market for hiring signals by company, role or region.
  • Salary and compensation research: collect published salary ranges by role, region, and experience level to benchmark pay.
  • Job aggregators and alert bots: feed vacancies into your own site, Telegram bot or newsletter, filtered by keyword, area or schedule.
  • Market and competitor monitoring: track which companies are hiring, for which roles, and how listings change over time with incremental mode.
  • Targeted outreach: hand in a specific list of vacancy URLs or IDs to get full detail cards, for example to reach out to companies that just posted a role.

Before you run

Start with a small input and check the resulting records against your expected fields. Source content and actor options can change; the current Apify listing is the reference for availability and pricing.

Questions about this actor

What data does HH.ru Scraper return?

The documented output for HH.ru Scraper includes id, change type (incremental mode), url, title, published, company, it-accredited and salary from. Availability of each field depends on the source page and the selected mode.

How much does HH.ru Scraper cost?

It costs $2.00 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify. The Apify listing shows the current rate for every plan.

Can I get only new or changed vacancies on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new, updated and reappeared vacancies, and unchanged ones are not billed unless you turn on emitUnchanged.

Why does search mode only match vacancy titles by default?

searchField defaults to "name" so a keyword search stays relevant. hh.ru's own default behavior matches the keyword anywhere (title, description or company), which mixes in loosely related roles. Set "searchField": "everywhere" if you deliberately want that wider reach.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

Ready to collect with HH.ru Scraper?

Run it on Apify with your own input and export the results as JSON, CSV or Excel.