# HH.RU Jobs Scraper — Russian Hiring Intelligence (`khadinakbar/hh-ru-jobs-scraper`) Actor

Search public HH.RU vacancies and return normalized roles with employer, location, salary, skills, schedule, publication time and a clean description. Use for recruitment research, job alerts and Russian labor-market analysis.

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

## Pricing

from $3.00 / 1,000 job scrapeds

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 web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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 Jobs Scraper — Russian Job Vacancies API & Salary Data

**HH.RU Jobs Scraper** is an Apify Actor that searches public job vacancies on [HH.RU](https://hh.ru) (HeadHunter) via the documented public vacancy API and returns a clean, AI-ready job feed for recruitment research, salary benchmarking, job alerts, and Russian labor-market analysis. It returns structured records with employer, location, salary range, skills, schedule, experience level, and source URLs — no login required.

### Best fit and connected workflows

Choose this Actor when you need public HH.RU vacancies filtered by role, region, experience, schedule, or salary disclosure.

Start with [Jobs Scraper](https://apify.com/khadinakbar/jobs-scraper) when the research spans several international job platforms, then use this Actor for the HH.RU portion of the workflow.

Choose [Ashby Jobs Scraper](https://apify.com/khadinakbar/ashby-jobs-scraper) when the input starts with known Ashby employer boards. This Actor's focused scope is public HH.RU vacancy data, including the source's employer, salary, skills, schedule, and regional fields.

#### Common use cases

- **Recruiting intelligence:** compare hiring demand by role, region, experience, and work schedule.
- **Salary research:** focus on vacancies that publish pay and retain the source currency and range.
- **Job alerts:** schedule a bounded query and use `jobId` to detect newly observed vacancies.
- **Skills analysis:** extract requested skills and professional roles across vacancies.
- **AI-agent workflows:** return concise job records that are easy to filter, summarize, and pass into downstream research.

### Practical scenario: from search query to skills brief

A labor-market analyst starts with `searchQuery: "data engineer"`, selects the relevant HH.RU areas, and sets a modest `maxResults`. The Actor returns one normalized row per vacancy with stable `jobId`, employer, salary fields, schedule, skills, publication time, and source URLs. The analyst then groups skills across the dataset, compares disclosed salary ranges in the original currency, and schedules the same bounded input to observe newly listed roles.

### Input

The default input searches for `software engineer` vacancies from the available public search period and returns a bounded job dataset.

| Field | Type | Required | Description |
|---|---|---|---|
| `searchQuery` | string | Yes\* | Free-text search (e.g. `data engineer`). Supports HH.RU boolean operators. |
| `vacancyUrls` | array | Yes\* | Public `hh.ru/vacancy/<id>` URLs to enrich directly. Takes precedence over search. |
| `areaIds` | array | No | HH.RU numeric geographic IDs (e.g. `1` = Moscow, `2` = Saint Petersburg). Empty = all regions. |
| `experience` | string | No | Experience filter: `noExperience`, `between1And3`, `between3And6`, `moreThan6`. |
| `scheduleType` | string | No | `any`, `fullDay`, `shift`, `flexible`, `remote`, `flyInFlyOut`, or `watch`. |
| `onlyWithSalary` | boolean | No | Return only vacancies that publish compensation. |
| `publishedWithinDays` | integer | No | Limit to vacancies posted within N days. Default `30`. Max `30`. |
| `maxResults` | integer | No | Max vacancies returned. Default `20`. Max `100`. |
| `includeJobDetails` | boolean | No | Fetch full detail per vacancy. Default `true`. |
| `responseFormat` | string | No | `concise` (compact metadata) or `detailed` (full description). Default `concise`. |

\*Provide either `searchQuery` or `vacancyUrls`.

Example input:

```json
{
  "searchQuery": "data engineer",
  "areaIds": ["1"],
  "experience": "between1And3",
  "scheduleType": "remote",
  "publishedWithinDays": 7,
  "maxResults": 20,
  "includeJobDetails": true,
  "responseFormat": "concise"
}
```

`areaIds` uses HH.RU's numeric geographic identifiers (for example, `1` is Moscow). Leave it empty to search every area.

### Output: data fields you receive

Each dataset row is one normalized public vacancy.

| Field | Type | Description |
|---|---|---|
| `jobId` | string | Stable HH.RU vacancy identifier |
| `title` | string | Job title |
| `companyName` | string | Employer name |
| `location` | string | City or region |
| `schedule` | string | Work schedule (e.g. Remote work) |
| `employmentType` | string | Full-time, part-time, contract |
| `experience` | string | Required experience level |
| `salaryMin` | number | Published salary floor |
| `salaryMax` | number | Published salary ceiling |
| `salaryCurrency` | string | Salary currency code (e.g. `RUR`) |
| `salaryGross` | boolean | Whether salary is before tax |
| `skills` | array | Requested skill keywords |
| `professionalRoles` | array | HH.RU professional role categories |
| `description` | string | Public job description |
| `postedAt` | string | ISO timestamp when the vacancy was published |
| `jobUrl` | string | Direct public vacancy URL |
| `sourceUrl` | string | API provenance URL |
| `source` | string | Always `hh.ru` |
| `scrapedAt` | string | ISO timestamp of data collection |

The default key-value store always contains:

- `OUTPUT` — compact result outcome for API and agent use.
- `RUN_SUMMARY` — page, item, route, warning, and charge diagnostics.

Illustrative record shape:

```json
{
  "jobId": "123456",
  "title": "Data Engineer",
  "companyName": "Example Labs",
  "location": "Moscow",
  "schedule": "Remote work",
  "experience": "Between 1 and 3 years",
  "salaryMin": 250000,
  "salaryMax": 350000,
  "salaryCurrency": "RUR",
  "skills": ["Python", "SQL"],
  "professionalRoles": ["Data analyst"],
  "description": "Build reliable data pipelines…",
  "postedAt": "2026-07-15T12:00:00+0300",
  "jobUrl": "https://hh.ru/vacancy/123456",
  "source": "hh.ru"
}
```

### How it works

- The Actor calls HH.RU's documented public vacancy API with the `HH-User-Agent` header.
- A Russia-targeted residential session handles anonymous API traffic.
- Temporary source responses are retried, and useful listing data is retained when optional detail enrichment is unavailable.
- Source-access outcomes remain distinct from a valid search with no matching vacancies.
- The public vacancy API limits a search window to 30 days and practical pagination to its own documented result cap.

### Pricing

This Actor uses **Pay per event + platform usage**. A job event is charged only for a validated vacancy persisted to the dataset; duplicate and unpersisted records are excluded from job-result billing. The `maxResults` field keeps the requested result volume bounded. See the live Pricing tab for current event details.

#### Event-count example

A bounded request returning twenty validated vacancies records twenty `job-scraped` events in addition to the actor-start event and Apify platform usage. Set `maxResults` to define the result boundary before each request.

### Use with AI agents (MCP)

This Actor is exposed in the Apify MCP server as `apify--hh-ru-jobs-scraper`. AI agents like Claude, ChatGPT, and Gemini can call it directly to fetch live Russian job market data.

**Tool description:** Search public HH.RU (HeadHunter) job vacancies through the public API. Use for Russian labor-market research, salary benchmarking, job alerts, and hiring intelligence. Returns one record per vacancy with employer, location, salary, skills, publication time, and source URL, with one event recorded per validated vacancy.

#### Agent prompt card

Copy this into Claude, ChatGPT, or any MCP-connected agent:

> Search HH.RU for remote data engineering vacancies published in the last
> 7 days. For each result, return the title, company, salary range, required
> skills, and the source job URL. Summarize recurring skill demand across
> the results. Read `OUTPUT.outcome` before summarizing the
> dataset and preserve `sourceUrl` for provenance.

#### Python agent example

```python
from apify_client import ApifyClient
import os

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('khadinakbar/hh-ru-jobs-scraper').call(run_input={
    'searchQuery': 'data engineer',
    'areaIds': ['1'],
    'scheduleType': 'remote',
    'publishedWithinDays': 7,
    'maxResults': 20,
    'responseFormat': 'concise',
})
for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item['title'], item['salaryMin'], item['skills'])
```

### API example

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('khadinakbar/hh-ru-jobs-scraper').call({
    searchQuery: 'data engineer',
    areaIds: ['1'],
    scheduleType: 'remote',
    publishedWithinDays: 7,
    maxResults: 20,
    responseFormat: 'concise',
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Best results and outcome guidance

HH.RU requests use an identifying `HH-User-Agent` header and a consistent Russia-targeted residential session. The Actor retries temporary source responses and keeps useful listing data when optional detail enrichment is unavailable.

- Start with a broad role query and a modest `maxResults`, then add one area, experience, or schedule filter at a time.
- Use HH.RU numeric area identifiers and leave `areaIds` empty when the brief covers every region.
- Set `onlyWithSalary: true` when disclosed compensation is essential to the analysis.
- Choose `concise` for compact agent comparisons and `detailed` when the workflow needs more description text.
- Read `OUTPUT` for the compact outcome and `RUN_SUMMARY` for page, route, warning, and event diagnostics.

### Related Actors

- Choose Ashby Jobs Scraper when the next search starts from known Ashby employer boards; its linked workflow appears in the Best fit section above.
- Start with Jobs Scraper when the research combines several large job platforms, then compare its HH.RU segment with this focused dataset through the linked workflow above.
- Choose [Built In Jobs Scraper](https://apify.com/khadinakbar/built-in-jobs-scraper) when the next workflow focuses on technology-company vacancies and salary data outside HH.RU.

### Design note

While reviewing and testing this Actor, I found that its compact response keeps identifiers, source links, salary fields, skills, and a bounded description easy to compare. A practical workflow confirms a broad query with a small result cap, then adds one filter at a time so the final scheduled input remains easy to explain and reproduce.

### FAQ

**How do I scrape HH.RU job vacancies?** Provide a `searchQuery` (e.g. `software engineer`) and optionally filter by `areaIds`, `experience`, `scheduleType`, or `onlyWithSalary`. The Actor calls HH.RU's public vacancy API and returns structured records with employer, salary, skills, and source URLs.

**What data fields does HH.RU Jobs Scraper return?** Each vacancy includes `title`, `companyName`, `location`, `salaryMin`/`Max`/`Currency`, `skills`, `professionalRoles`, `experience`, `schedule`, `employmentType`, `postedAt`, and `jobUrl`. See the Output table above for the full list.

**Can I search several regions?** Yes. Add multiple HH.RU numeric area IDs to `areaIds`, or leave the array empty for an unrestricted geographic search.

**Can I retrieve known vacancies directly?** Yes. Put public HH.RU vacancy links in `vacancyUrls`; the Actor uses those known listings as the primary input mode.

**Why are some salary fields empty?** HH.RU listings include compensation only when the employer publishes it. The Actor preserves that distinction rather than estimating a range.

**How can an AI agent analyze an HH.RU vacancy set?** Call `apify--hh-ru-jobs-scraper` through the Apify MCP server with a search query or known vacancy URLs, then compare salary, skills, location, and source provenance from the structured rows.

**Which response format should an agent choose?** Start with `concise` for compact comparisons and use `detailed` when the workflow needs more of each public job description.

### Data provenance and responsible use

Rows are derived from public HH.RU vacancy search and detail pages, with the exact `sourceUrl` retained for provenance. Respect HH.RU's terms, applicable data-protection laws, and your users' expectations, and preserve human review for decisions that affect individuals.

# Actor input Schema

## `searchQuery` (type: `string`):

Use this when you want HH.RU vacancies matching a role, skill, or Boolean search expression. Enter text such as 'data engineer' or 'Python AND SQL'. Defaults to 'software engineer' when Vacancy URLs are empty. This is NOT a job URL or an employer ID.

## `areaIds` (type: `array`):

Use this when the search must be limited to one or more HH.RU geographic area IDs. Enter numeric strings such as '1' for Moscow or '2' for Saint Petersburg; leave empty for all areas. Defaults to an unrestricted search. This is NOT a country-code field or a free-text location.

## `experience` (type: `string`):

Use this when vacancies should be filtered by HH.RU's experience category. Choose any, noExperience, between1And3, between3And6, or moreThan6; default is any. The returned record still exposes the listing's experience label. This is NOT a numeric years-of-experience range.

## `employmentType` (type: `string`):

Use this when you need an HH.RU employment filter. Choose any, full, part, project, volunteer, probation, or flyInFlyOut; default is any. The actor returns the type supplied by each listing. This is NOT a workplace or schedule filter.

## `scheduleType` (type: `string`):

Use this when you need an HH.RU work-schedule filter. Choose any, fullDay, shift, flexible, remote, flyInFlyOut, or watch; default is any. The actor returns the schedule shown on each job. This is NOT an employment-contract filter.

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

Use this when you only need vacancies that disclose a salary. Set true to exclude listings without a salary range; default is false. Salary values stay null when the source does not provide them. This is NOT a minimum-salary threshold.

## `publishedWithinDays` (type: `integer`):

Use this when results should be limited to recently posted vacancies. Choose an integer from 1 through 30; default is 30, the maximum HH.RU public API period. This is NOT a historical archive setting.

## `sortOrder` (type: `string`):

Use this to choose whether HH.RU orders matches by relevance or publication time. Choose relevance or publication\_time; default is publication\_time. Salary sorting is intentionally excluded because it creates ambiguous null-salary ordering. This is NOT a local post-processing rule.

## `vacancyUrls` (type: `array`):

Use this when you already know public HH.RU vacancy pages to enrich. Add URLs such as 'https://hh.ru/vacancy/123456'; when supplied they take precedence over the search fields. This is NOT for employer, resume, or external application URLs.

## `maxResults` (type: `integer`):

Use this to cap the total number of persisted jobs and job events in the run. Choose an integer from 1 through 100; default is 20. This is NOT a per-page limit — see the Pricing tab for current per-job cost.

## `includeJobDetails` (type: `boolean`):

Use this to request each vacancy's public detail endpoint for skills and the full description. Default is true; set false for a faster listing-level feed with description snippets. This does not request private applicant or recruiter data. This is NOT an authorization setting.

## `responseFormat` (type: `string`):

Use this to control the description length returned to agent workflows. Choose concise for up to 800 characters or detailed for up to 5,000; default is concise. Both formats preserve the same normalized job fields. This is NOT an export file-format setting.

## Actor input object example

```json
{
  "searchQuery": "data engineer",
  "areaIds": [
    "1"
  ],
  "experience": "between1And3",
  "employmentType": "full",
  "scheduleType": "remote",
  "onlyWithSalary": false,
  "publishedWithinDays": 7,
  "sortOrder": "publication_time",
  "vacancyUrls": [
    "https://hh.ru/vacancy/123456"
  ],
  "maxResults": 20,
  "includeJobDetails": true,
  "responseFormat": "concise"
}
```

# Actor output Schema

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

No description

## `output` (type: `string`):

No description

## `runSummary` (type: `string`):

No description

# 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 = {
    "searchQuery": "software engineer",
    "areaIds": [
        "1"
    ],
    "experience": "any",
    "employmentType": "any",
    "scheduleType": "any",
    "publishedWithinDays": 30,
    "sortOrder": "publication_time",
    "vacancyUrls": [],
    "maxResults": 20,
    "responseFormat": "concise"
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/hh-ru-jobs-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 = {
    "searchQuery": "software engineer",
    "areaIds": ["1"],
    "experience": "any",
    "employmentType": "any",
    "scheduleType": "any",
    "publishedWithinDays": 30,
    "sortOrder": "publication_time",
    "vacancyUrls": [],
    "maxResults": 20,
    "responseFormat": "concise",
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/hh-ru-jobs-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 '{
  "searchQuery": "software engineer",
  "areaIds": [
    "1"
  ],
  "experience": "any",
  "employmentType": "any",
  "scheduleType": "any",
  "publishedWithinDays": 30,
  "sortOrder": "publication_time",
  "vacancyUrls": [],
  "maxResults": 20,
  "responseFormat": "concise"
}' |
apify call khadinakbar/hh-ru-jobs-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/KbEN5fql7SFbalcEl/builds/vrWCyvO7nND58KbD2/openapi.json
