# Bazoš Scraper — bazos.sk, .cz, .pl, .at in one run (`richardsolar/bazos-scraper`) Actor

Scrape classified ads from bazos.sk, bazos.cz, bazos.pl and bazos.at in a single deduplicated run. Keyword, category, price and postal-code radius search, promoted-ad detection, GPS coordinates and incremental monitoring for scheduled runs. From $1 per 1000 listings.

- **URL**: https://apify.com/richardsolar/bazos-scraper.md
- **Developed by:** [Richard Solar](https://apify.com/richardsolar) (community)
- **Categories:** E-commerce, Lead generation, Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 listing with details

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/actors/running/actors-in-store.md#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

Bazoš Scraper reads **bazos.sk, bazos.cz, bazos.pl and bazos.at in a single run** and returns one clean dataset, deduplicated across all four. Bazoš is the dominant classifieds network in Slovakia, Czechia, Poland and Austria, and every other tool for it covers one country at a time. That is the difference: you can compare the same model across four markets in one pass instead of running four scrapers and joining the output yourself.

No account, no cookies, no setup. Give it a keyword and press start.

### Why this one

| Capability                   | Here                                                          | Typical alternative                             |
| ---------------------------- | ------------------------------------------------------------- | ----------------------------------------------- |
| **Countries per run**        | All four, deduplicated, subcategories translated between them | One site per run                                |
| **Promoted (TOP) ads**       | Flagged and optionally excluded                               | Returned unlabelled, mixed in with real matches |
| **Price**                    | $1 per 1,000 listings, $0.00005 to start a run                | $2–5 per 1,000, $0.001–0.005 to start a run     |
| **Coordinates**              | Latitude and longitude for every listing                      | Not provided                                    |
| **Broken-markup protection** | Warns when a field stops filling, and can fail the run        | Returns empty columns silently                  |

Two of these are worth expanding on.

**Promoted ads are the reason Bazoš results look wrong.** Bazoš places paid listings above organic ones regardless of what you searched for, so a search for a phone genuinely returns a Volkswagen. On a nationwide search the whole first page is often promoted. `isTopListing` tells you which rows are adverts, so you can filter them, measure them, or leave them.

**Subcategory names are canonical.** Ask for `animals/dogs` and you get `pes` in Slovakia, `psy` in Poland and `hunde` in Austria, without knowing any of that. Over 440 subcategories are mapped this way.

### How much does it cost to scrape Bazoš?

| Mode                   | Effective price  | What you get                                                                  |
| ---------------------- | ---------------- | ----------------------------------------------------------------------------- |
| `scrapeDetails: false` | **$1 per 1,000** | Title, price, city, postal code, views, post date, promoted flag, seller name |
| `scrapeDetails: true`  | **$2 per 1,000** | Everything — full description, every photo URL, coordinates, seller details   |

Details mode opens one page per listing; list-only mode reads twenty listings per page, which is roughly **20x fewer requests** and why it costs half as much.

Starting a run costs $0.00005. **The $5 in free credit you get on signup is worth 5,000 listings in list-only mode, or 2,500 with full details.**

`maxItems` is enforced as listings are collected, not trimmed afterwards, so the Actor never returns — or bills — more than you asked for.

### Monitoring: only what is new

Set `monitorMode: true` and the Actor remembers which listings it has already
returned. The next run skips them, so a schedule costs only what appeared since
last time — and a listing you have already paid for is never charged twice.

```json
{
  "countries": ["sk", "cz"],
  "categories": ["cars/skoda"],
  "priceMax": 5000,
  "sortBy": "newest",
  "maxItems": 500,
  "scrapeDetails": true,
  "monitorMode": true
}
```

Save that as a task and schedule it hourly. The first run returns everything
matching; every run after it returns only the new ads.

Known listings are dropped while reading the results page, so they cost neither
a request nor a charge. The run status says how many were skipped, which is how
you tell "nothing new" apart from "something broke".

Two details worth knowing:

- **Ids are kept for 90 days** by default (`monitorRetentionDays`). After that
  a listing counts as new again.
- **One store per schedule.** The list of delivered ids lives in a named
  key-value store shared by every run of the Actor on your account. Two
  schedules watching different searches need two `monitorStoreName` values, or
  each will hide the other's listings.

### Input examples

**Compare one keyword across the Slovak and Czech markets**

```json
{
  "countries": ["sk", "cz"],
  "keywords": ["iphone 15"],
  "categories": ["mobile"],
  "priceMin": 100,
  "priceMax": 600,
  "sortBy": "cheapest",
  "maxItems": 200,
  "scrapeDetails": true
}
```

**Everything for sale within 25 km of a postal code**

```json
{
  "countries": ["sk"],
  "postalCode": "82102",
  "radiusKm": 25,
  "sortBy": "newest",
  "maxItems": 500,
  "scrapeDetails": false
}
```

**Browse a whole category, no keyword**

```json
{
  "countries": ["sk", "cz", "pl", "at"],
  "categories": ["realEstate"],
  "sortBy": "newest",
  "maxItems": 1000,
  "scrapeDetails": false
}
```

### Output example

Each listing comes back as 31 separate fields:

```json
{
  "listingId": "195384958",
  "url": "https://mobil.bazos.sk/inzerat/195384958/apple-iphone-16-pro.php",
  "country": "sk",
  "categories": ["mobile"],
  "categorySlug": "mobil",
  "subcategory": "apple",
  "subcategoryLabel": "Apple",
  "title": "Apple iPhone 16 Pro 256 GB",
  "description": "Telefón je používaný približne 2 roky, batéria 91 %.",
  "descriptionShort": "Telefón je používaný približne 2 roky…",
  "price": 700,
  "priceText": "700 €",
  "priceType": "fixed",
  "currency": "EUR",
  "city": "Bratislava",
  "postalCode": "82108",
  "latitude": 48.170639,
  "longitude": 17.147464,
  "sellerName": "Jana",
  "sellerUserId": "13127821",
  "phoneMasked": "094...",
  "viewCount": 370,
  "publishedAt": "2026-09-10",
  "isTopListing": false,
  "topUntil": null,
  "topCount": null,
  "mainImage": "https://www.bazos.sk/img/1/958/195384958.jpg",
  "thumbnailUrl": "https://www.bazos.sk/img/1t/958/195384958.jpg",
  "images": [
    "https://www.bazos.sk/img/1/958/195384958.jpg",
    "https://www.bazos.sk/img/2/958/195384958.jpg"
  ],
  "sourceUrl": "https://mobil.bazos.sk/inzerat/195384958/apple-iphone-16-pro.php",
  "scrapedAt": "2026-09-10T18:33:08.318Z"
}
```

#### Output fields

| Field                                         | Description                                                       |
| --------------------------------------------- | ----------------------------------------------------------------- |
| `listingId`, `url`                            | Listing id and canonical URL. The id is unique within a country.  |
| `country`, `category`, `subcategory`          | Where it came from. Category keys are the same on all four sites. |
| `title`, `description`                        | Title and the full description, line breaks preserved.            |
| `price`, `priceText`, `priceType`, `currency` | Numeric price plus the label as displayed, and how it was stated. |
| `city`, `postalCode`, `latitude`, `longitude` | Location, split into separate fields.                             |
| `sellerName`, `phoneMasked`                   | Who is selling. See the note on phone numbers below.              |
| `viewCount`, `publishedAt`                    | Views, and the date the ad was posted.                            |
| `isTopListing`, `topCount`, `topUntil`        | Whether the listing is a paid promotion.                          |
| `images`, `mainImage`, `thumbnailUrl`         | Every photo URL, with a designated main one.                      |
| `sourceUrl`, `scrapedAt`                      | Where and when this row was collected.                            |

### What can you use it for?

- **Arbitrage and resale** — compare the same model across Slovak, Czech, Polish and Austrian markets in one dataset.
- **Price research** — track what an item actually sells for, with real asking prices rather than retail listings.
- **Market monitoring** — schedule a run and get only the listings posted since last time.
- **Lead generation** — seller names and locations for a given category and region.

### How to scrape Bazoš data

1. Click **Try for free**.
2. Type what you're looking for in **Keywords** — for example `iphone`.
3. Pick one or more **Countries**. Slovakia is selected by default.
4. Optionally narrow by **Categories**, **price range**, or **postal code and radius**.
5. Set **Maximum listings** to whatever you need.
6. Press **Start** and download the results as JSON, CSV, Excel or XML.

### Tips

#### Scope to a category rather than excluding promoted ads

Searching `iphone` with no category returned 25% unrelated results. The same search with `categories: ["mobile"]` returned 100% phones, using fewer requests. `excludeTopListings` also exists, but it suppresses the label rather than the irrelevance, and costs about five times as many requests.

#### Sort order

`sortBy` accepts `newest`, `cheapest`, `mostExpensive`, `mostViewed` and `leastViewed`, and is applied by Bazoš itself. With the default `newest`, Bazoš still places promoted listings first.

#### One list, two levels

**Categories** holds both. The twenty categories come first — `Mobile phones`, `Cars` — and every subcategory follows as `Mobile phones › Apple`. Pick either, or mix them:

```json
{ "categories": ["books", "mobile/apple"] }
```

One selection covers all four sites. Where a concept exists in one country and not another — Austria has no saws under House & garden — that combination is skipped with a warning rather than wasting a request.

Each selection runs as its own search and they share `maxItems`, so four subcategories across four countries is sixteen searches splitting the cap.

#### Searching near a location

Set `postalCode` and `radiusKm` together. A radius of `0` returns only that exact postal code.

### FAQ

#### Can I get the seller's full phone number?

No, and neither can any other tool without an account. Bazoš publishes only a three-character prefix and reveals the rest exclusively to phone-verified logged-in users. This Actor returns the prefix Bazoš makes public (`phoneMasked`) and does not attempt to work around that restriction.

#### How accurate are the coordinates?

They locate the postal code, not the seller's address — Bazoš does not publish an exact position. Two listings in the same postal code share coordinates. Good for mapping and regional analysis, not for finding a specific address.

#### Does it work on all four Bazoš sites?

Yes, and in the same run. The four sites share one layout, so every field is available on each. Currencies, category names and subcategory names are localised automatically.

#### Is `publishedAt` the date the ad was posted?

Yes. It is read from the listing itself and is distinct from `scrapedAt`, which records when the Actor collected the row.

#### Is scraping Bazoš legal?

Scraping publicly available data is generally legal, but this Actor can collect personal data such as seller names and locations. You are responsible for having a lawful basis to process it under GDPR, and for how you store and use it. If you are unsure, take legal advice — and consider turning off listing details if you only need prices.

#### Something looks wrong

Report it on the **Issues** tab. Bazoš changes its markup occasionally; this Actor checks the live site daily and fixes are usually quick.

# Actor input Schema

## `countries` (type: `array`):

Which Bazoš sites to search. All four share the same categories, so one search runs across every country you pick.

## `keywords` (type: `array`):

Search terms. Each keyword is searched separately and results are deduplicated. Leave empty to browse a category without searching.

## `categories` (type: `array`):

What to search. Pick a whole category, or one of its subcategories — the twenty categories are listed first, then every subcategory as `Category › Subcategory`. Each choice runs as its own search and they share the listing cap. Leave empty to search everything.

## `priceMin` (type: `integer`):

Applied by Bazoš itself, not filtered afterwards, so it does not waste requests. In the currency of each country searched.

## `priceMax` (type: `integer`):

Applied by Bazoš itself, not filtered afterwards. In the currency of each country searched.

## `postalCode` (type: `string`):

Search near this postal code, e.g. 82108. Combine with the radius below. Leave empty to search the whole country.

## `radiusKm` (type: `integer`):

How far from the postal code to search. 0 returns only that exact postal code. Ignored when no postal code is set.

## `sortBy` (type: `string`):

Result order, applied by Bazoš. Note that with the newest-first default, Bazoš places promoted listings at the top.

## `maxItems` (type: `integer`):

Hard cap on listings returned, shared across every country, keyword and category combination. The Actor never exceeds it, so you are never billed for overshoot.

## `maxPagesPerSearch` (type: `integer`):

Result pages to read per combination, 20 listings each. 0 means no limit — stop only at Maximum listings or the end of results.

## `scrapeDetails` (type: `boolean`):

Open each listing for the full description, all photo URLs, GPS coordinates and the seller's masked phone. Turn off to read results pages only — about 20x fewer requests and much cheaper, but you get only what the results page shows.

## `excludeTopListings` (type: `boolean`):

Bazoš injects paid listings into unrelated results — a search for a phone can return cars. They are always flagged as isTopListing; turn this on to drop them entirely.

## `monitorMode` (type: `boolean`):

Skip listings that an earlier run already returned, so a scheduled run gives you only what appeared since. Skipped listings are not opened and not charged. Leave off for one-off runs.

## `monitorStoreName` (type: `string`):

Named key-value store holding the ids already returned. Leave empty to use one named after the Actor. Give two schedules two different names when they watch different searches, or each will hide the other’s listings.

## `monitorRetentionDays` (type: `integer`):

How long an id stays remembered. Older ids are dropped, so the store does not grow forever and a listing reposted long afterwards is reported again.

## `startUrls` (type: `array`):

Bazoš search or listing URLs to scrape directly, instead of building a search from the fields above. Listing URLs are scraped as details; anything else is treated as a results page.

## `proxyConfiguration` (type: `object`):

Bazoš blocks some datacenter IPs outright. Apify Proxy is strongly recommended; the Actor retires a blocked address immediately and settles on working ones.

## `minCleanFieldRatio` (type: `number`):

Advanced. Every field has an expected fill rate; the run warns and names any field that drops below its own. Leave at 1 and the run only warns. Lower it to fail the run when more than this fraction of fields are affected — 0.5 fails when half of them are, which usually means Bazoš changed its markup and the data is not worth having.

## Actor input object example

```json
{
  "countries": [
    "sk"
  ],
  "keywords": [
    "iphone"
  ],
  "categories": [],
  "radiusKm": 25,
  "sortBy": "newest",
  "maxItems": 10,
  "maxPagesPerSearch": 0,
  "scrapeDetails": true,
  "excludeTopListings": false,
  "monitorMode": false,
  "monitorStoreName": "",
  "monitorRetentionDays": 90,
  "startUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "minCleanFieldRatio": 1
}
```

# Actor output Schema

## `results` (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 = {
    "countries": [
        "sk"
    ],
    "keywords": [
        "iphone"
    ],
    "categories": [],
    "sortBy": "newest",
    "maxItems": 10,
    "scrapeDetails": true,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("richardsolar/bazos-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 = {
    "countries": ["sk"],
    "keywords": ["iphone"],
    "categories": [],
    "sortBy": "newest",
    "maxItems": 10,
    "scrapeDetails": True,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("richardsolar/bazos-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "countries": [
    "sk"
  ],
  "keywords": [
    "iphone"
  ],
  "categories": [],
  "sortBy": "newest",
  "maxItems": 10,
  "scrapeDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call richardsolar/bazos-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,richardsolar/bazos-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Jt3o2xf33imABjTKE/builds/wgRAMItZB5xfygZbH/openapi.json
