# Boss.az Azerbaijan Jobs Scraper (`zinin/boss-az`) Actor

Walk boss.az's own job sitemap and pull public job listings from Azerbaijan: title, employer, location, salary (AZN), education/experience requirements, and contact details — straight from each job's own public page.

- **URL**: https://apify.com/zinin/boss-az.md
- **Developed by:** [Tim Zinin](https://apify.com/zinin) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.70 / 1,000 job founds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Boss.az Azerbaijan Jobs Scraper

Boss.az is one of Azerbaijan's leading job boards. This Actor walks its own public job sitemap and visits each job's own page to return one row per posting — title, employer, location, salary (AZN, when published), education/experience requirements, category, and contact email/phone. No login, no browser, no search query.

### What you get

- **Live jobs straight from boss.az's own sitemap**, not a stale export.
- **Full job detail, including data the page's own SEO markup leaves empty.** boss.az's schema.org listing always ships an empty description — this Actor reads the same embedded data the page itself uses to render, which also carries the real description, requirements, responsibilities, and contact email/phone.
- **Salary in AZN when the employer published one** — read as real numbers, never estimated when it's missing (roughly a third of postings don't disclose one).
- **Optional keyword filter.** Keep only jobs whose title contains your term — applied after fetching, since there is no server-side search available here.
- **Honest closed/removed handling.** A posting that's expired or no longer exists still answers HTTP 200 on this board (its own SPA quirk) — this Actor checks the page's own status field instead of trusting the HTTP code, and skips those for free.
- Runs on Apify: schedule it, monitor it, call it from the API or the MCP server, export to JSON, CSV or Excel, or push results straight into your own pipeline.

### How to run it

1. Click **Try for free** — no card needed on the free plan.
2. Set **Max jobs to return** (or leave the default).
3. Optionally add a **Keyword filter** to only keep matching titles.
4. Press **Start**. Results appear in the dataset — read them in the UI, pull them from the API, or have a webhook push them onward.

### Pricing

Pay-per-event: **$0.005 per run start + $0.002 per job found**. No monthly seat, no minimum. 100 jobs cost about **$0.21**; 1,000 jobs about **$2.01**.

A closed/removed posting, a keyword that matched nothing, or a sitemap that failed to load is still logged with `found: false` and the reason where one exists — and it is **not** charged for. You pay for jobs actually delivered, not for attempts. Note: boss.az's whole current market is roughly 600 open postings at any given time — this is a national, not global, board.

### Input

| Field | Required | What it does |
|---|---|---|
| `max_items` | no | Target number of job rows to deliver (default 20, max 200). This is a target, not a guarantee — some listed jobs turn out already closed. |
| `freshness_days` | no | Skip sitemap entries not updated in this many days (default 30). boss.az's "last modified" date also moves when an employer pays to renew ("bump") an old posting, so this is a recency signal, not an exact posting age. |
| `keyword_filter` | no | Case-insensitive substring match against each job's title, applied on this Actor's side. Leave empty to keep every job found. |
| `fetch_full_description` | no | Include the full description, requirements, and responsibilities text in the output row (default `true`). The job's own page is fetched either way — this only controls whether the text is kept. |
| `sitemap_override_url` | no | Advanced/diagnostic: override the sitemap URL this Actor walks. Leave empty for normal use. |

```json
{
    "max_items": 3
}
```

### Output

One dataset row per job found. This is a real row from a real run:

```json
{
    "found": true,
    "url": "https://boss.az/vacancies/269855",
    "job_id": "269855",
    "title": "Satış təmsilçisi OTC (aptek qrupu)",
    "company": "GRAND MEDİCİNE MMC",
    "company_url": "https://boss.az/companies/63576",
    "location": "Bakı",
    "country": "AZ",
    "employment_type": null,
    "posted_date": "2026-06-29T08:07:21.000Z",
    "salary_raw": "AZN 700",
    "description": "Grand Medicine MMC vitamin, dəstək məhsulları və OTC məhsullarının satışı sahəsində fəaliyyət göstərən inkişaf etməkdə olan şirkətdir...",
    "description_is_teaser": false,
    "source_board": "boss-az",
    "scraped_at": "2026-07-30T07:55:54.680Z",
    "category": "Satış məsləhətçisi",
    "education": "Ali",
    "experience": "1 ildən 3 ilə qədər",
    "email": "info@grandmedicine.az",
    "phones": ["(051) 230-90-09"],
    "requirements": "* Satış sahəsində təcrübə üstünlükdür * OTC, vitamin və ya aptek sektorunda təcrübə arzuolunandır...",
    "responsibilities": "* Təyin olunmuş bölgədə apteklərin ziyarət edilməsi * Məhsulların apteklərə təqdimatı və satışı..."
}
```

| Field | What it means |
|---|---|
| `found` | Whether this row is a real job (`true`) or a notice/error row (`false`) |
| `url` | Direct link to the job posting — the unique key for this row |
| `job_id` | boss.az's own numeric vacancy id |
| `title` | Job title |
| `company` | Hiring company name |
| `company_url` | Link to the company's boss.az profile page, when known — `null` otherwise |
| `location` | City as boss.az shows it |
| `country` | Always `"AZ"` — this board covers Azerbaijan only |
| `employment_type` | Always `null` — boss.az does not publish a discrete employment-type field on this board |
| `category` | boss.az's own job category label (not translated) |
| `posted_date` | ISO 8601 timestamp |
| `salary_raw` | Salary in AZN as published (e.g. `"AZN 750–800"`), or `null` — roughly a third of postings don't disclose one; this Actor never estimates or invents a figure |
| `education` / `experience` | Free-text requirements, exactly as the employer wrote them |
| `email` / `phones` | Contact details the employer published for applicants — `phones` is a list, may be empty |
| `description` | Full job description (HTML stripped, entities decoded), up to 600 characters, or `null` when `fetch_full_description` is off |
| `requirements` / `responsibilities` | Separate text blocks the employer wrote, same truncation as `description` |
| `description_is_teaser` | Always `false` when `description` is present — every row comes from the job's own full page, never a search-result snippet |
| `source_board` | Always `"boss-az"` |
| `scraped_at` | When this Actor fetched the row |

A run whose keyword filter matched nothing (or whose entire candidate batch turned out closed/filtered) pushes:

```json
{ "found": false, "error": "", "source_board": "boss-az", "scraped_at": "..." }
```

A run whose sitemap failed to load pushes an error row with a non-empty `error` (e.g. `"http 404"`) — never the same shape as "no matches".

### Other tools we built

#### Related tools

Related tools for adjacent workflows in jobs and hiring.

| Actor | What it does |
|---|---|
| [XING Jobs (DACH) Scraper](https://apify.com/zinin/xing-jobs) | Pair it in the jobs and hiring workflow: Walk xing.com's own job sitemap and pull public job listings from Germany/Austria/Switzerland: title,... |
| [Jobs.ge Georgia Jobs Scraper](https://apify.com/zinin/jobs-ge) | Pair it in the jobs and hiring workflow: Search Jobs.ge (Georgia, the country's oldest job board) and get public job listings: title, employer,... |
| [Computrabajo LatAm Jobs Scraper](https://apify.com/zinin/computrabajo-jobs) | Pair it in the jobs and hiring workflow: Search Computrabajo (Mexico, Colombia, Chile, Argentina, Peru) by keyword and get public job listings:... |
| [jobs.ch Swiss Jobs Scraper](https://apify.com/zinin/jobs-ch-swiss) | Pair it in the jobs and hiring workflow: Search jobs.ch (Switzerland) by keyword and get public job listings: title, company, location, employment... |
| [Job Postings Aggregator](https://apify.com/zinin/job-postings-aggregator) | Pair it in the jobs and hiring workflow: Pull every open role from a company's public applicant-tracking system (Greenhouse, Lever, Ashby) and... |

### FAQ

**Does it need an API key / login?** No — it reads boss.az's public sitemap and public job pages, no session required.

**Why do I sometimes get fewer jobs than `max_items`?** Some listed jobs turn out already closed by the time this Actor visits them — boss.az's own site quirk is that a closed or missing posting's page still answers HTTP 200, so this Actor checks the page's own status data instead and skips those for free, trying extra candidates to compensate.

**How stable is the source?** Boss.az does not expose the full detail fields in standard JobPosting markup; the Actor reads the structured hydration data used by the site's own frontend. A major frontend redesign can require a parser update, and the Actor reports that as an error rather than returning guessed fields.

**Why is `salary_raw` sometimes `null`?** Because that employer didn't publish one on boss.az. This Actor never estimates or guesses a number.

**Can I filter by keyword?** Yes, via `keyword_filter` — a case-insensitive match against the job title, applied after this Actor fetches each candidate page (boss.az's own job search needs a browser session and is not used here).

**How big is this market?** boss.az's own sitemap lists roughly 600 vacancy pages at any given time — a national Azerbaijan job board, not a global one.

**Can I call it from an AI agent?** Yes — standard Apify Actor, callable from the Apify API, the SDK, or the Apify MCP server.

**What this is NOT.** It does not apply to jobs on your behalf, does not cover job boards outside boss.az, and does not invent a salary figure when the source has none.

Found a wrong result, or need a check we don't run? Open an issue on this Actor's page.

***

Built by [zinin](https://apify.com/zinin). Questions? Telegram [@timzinin](https://t.me/timzinin).

# Actor input Schema

## `max_items` (type: `integer`):

How many job rows to deliver, at most. This Actor walks boss.az's own job sitemap and visits each candidate job page individually — some listed jobs turn out already closed by the time they're visited, which is normal, not a fault. Extra candidates are attempted automatically to compensate, so this number is a target, not a guarantee.

## `freshness_days` (type: `integer`):

Skip sitemap entries not updated within this many days. boss.az's own sitemap 'last modified' date also moves when an employer renews ("bumps") an old posting, so this is a rough recency filter, not an exact posting-age filter.

## `keyword_filter` (type: `string`):

Optional case-insensitive substring match against each job's title, applied on this Actor's side after fetching the job's own page. boss.az's job search itself needs a browser session and is not used here — there is no server-side keyword search on this Actor. Leave empty to keep every job found.

## `fetch_full_description` (type: `boolean`):

Include the job's full description text in the output row. This Actor already fetches each job's own page to get any data at all (title, company, location...), so the description costs no extra request either way — this setting only controls whether it's kept in the row.

## `sitemap_override_url` (type: `string`):

Advanced: override the boss.az sitemap URL this Actor walks. Leave empty to use the live boss.az sitemap. Mainly useful for diagnostics.

## Actor input object example

```json
{
  "max_items": 3,
  "freshness_days": 30,
  "fetch_full_description": true
}
```

# Actor output Schema

## `results` (type: `string`):

API URL for the default dataset items produced by this run.

# 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 = {
    "max_items": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("zinin/boss-az").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 = { "max_items": 3 }

# Run the Actor and wait for it to finish
run = client.actor("zinin/boss-az").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 '{
  "max_items": 3
}' |
apify call zinin/boss-az --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/0FPAFUkAYWBKt6LTP/builds/3a3UzidLbpoqo1IXx/openapi.json
