# Boliga Denmark Real Estate Scraper (`scraptivo/boliga-dk-scraper`) Actor

Collect property listings from Boliga.dk across Denmark by zip code, location query, or Boliga URLs, with optional listing details including agent contact, BBR data, sales history, and price analytics.

- **URL**: https://apify.com/scraptivo/boliga-dk-scraper.md
- **Developed by:** [Scraptivo](https://apify.com/scraptivo) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 listings

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

**Boliga Denmark Real Estate Scraper** collects property listings from [Boliga.dk](https://www.boliga.dk) and turns them into structured data for Danish market research, investment analysis, and lead generation. Provide a zip code such as `9500`, a location query such as `København`, or a Boliga search URL, then export price, address, rooms, energy class, and agent contact to JSON, CSV, or Excel. Use it to monitor listings, compare municipalities, and schedule recurring collection. Pricing starts at **$1.00 per 1,000 listings**, with optional listing details at **$2.00 per 1,000**.

### What can you automate with Boliga Denmark Real Estate Scraper?

- **Build Danish listing databases** — Collect properties by zip code, free-text query, or Boliga search and listing URLs.
- **Enrich with full listing data** — Add agent contact, BBR building data, sales history, price analytics, and photo galleries when **Extract Listing Details** is on.
- **Filter by property type and price** — Narrow by villa, apartment, price range, rooms, size, build year, days for sale, and energy class.
- **Track market movement** — Sort by days for sale, price, views, or price per m² to spot stale inventory or price changes.
- **Schedule recurring collection** — Run daily or weekly and push new listings into Sheets, a CRM, or an alert workflow.

### Who is this scraper for?

| Team | Workflow |
|---|---|
| Real estate investors | Compare asking prices, price/m², and sales history across Danish municipalities. |
| Market researchers | Monitor inventory, days on market, and energy labels by zip code. |
| Lead-generation teams | Collect agent names, phone numbers, and emails when detail extraction is enabled. |
| Proptech products | Feed structured Boliga listings into dashboards and alerts. |

### What data can you collect from Boliga.dk?

| Data group | Example fields | How it helps |
|---|---|---|
| Listing identity | listing ID, address, zip code, city, coordinates, property type | Identify each property and deduplicate with the listing ID. |
| Commercial | price, price/m², days for sale, sort metadata | Compare asking prices and time on market. |
| Property | rooms, living area, lot size, basement size, build year, energy class | Filter by size, age, and energy rating. |
| Media | image URLs, full photo gallery | Review listing presentation. |
| Agent contact | agent name, phone, email, homepage, brokerage URL | Appear when **Extract Listing Details** succeeds. |
| BBR and analytics | BBR building data, sales history, price changes, municipality stats | Appear when detail extraction is enabled. |

Basic search-card fields are always collected. Agent contact, BBR data, and sales history appear only when **Extract Listing Details** is on.

### How to use Boliga Denmark Real Estate Scraper

1. Open the [Boliga Denmark Real Estate Scraper](https://apify.com/scraptivo/boliga-dk-scraper) on Apify.
2. Enter Danish zip codes, location queries, or paste Boliga search or listing URLs.
3. Set property filters and toggle **Extract Listing Details** if you need agent contact or BBR data.
4. Run the Actor — it writes one dataset row per listing.
5. Export the dataset or connect it to your workflow.

```json
{
    "searchQueries": ["9500"],
    "propertyTypes": ["villa", "ejerlejlighed"],
    "priceMin": 100000,
    "priceMax": 3000000,
    "sort": "daysForSale-a",
    "extractDetails": true,
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": ["RESIDENTIAL"]
    }
}
```

### Example workflow

#### Build a weekly North Jutland villa watchlist

1. Schedule a Monday run with `searchQueries` = `["9500"]`, `propertyTypes` = `["villa"]`, and `sort` = `"daysForSale-a"`.
2. Enable **Extract Listing Details** when you need agent phone and sales history.
3. Keep rows inside your price and room band using `price` and `rooms`.
4. Send new records to Google Sheets through a webhook after each run.
5. Deduplicate user-side against the stable listing ID.

The Actor does not merge results across runs — those steps happen in your pipeline.

### Automate and integrate your results

- **Schedules** — Run **weekly** for a market snapshot or **daily** when monitoring new inventory in a zip code.
- **Webhooks** — Push completed runs into Google Sheets, Make, Zapier, Slack, or a CRM.
- **Exports and API** — Download JSON, CSV, Excel, or HTML from the Apify Console, or start a run from the API:

```shell
curl -X POST "https://api.apify.com/v2/acts/scraptivo~boliga-dk-scraper/runs?token=YOUR-APIFY-TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "searchQueries": ["9500"],
    "maxItems": 20,
    "extractDetails": false
  }'
```

Use the listing ID as the stable deduplication key across runs.

### Input reference

| Field | Type | Required | Default | What it controls |
|---|---|---:|---|---|
| `startUrls` | array | No | — | Boliga search or listing URLs. |
| `searchQueries` | array | No | `9500` | Danish zip codes or free-text location queries. |
| `propertyTypes` | array | No | all | Villa, rækkehus, ejerlejlighed, and other Boliga types. |
| `priceMin` / `priceMax` | integer | No | — | Asking price range in DKK. |
| `roomsMin` / `roomsMax` | integer | No | — | Room count range. |
| `sizeMin` / `sizeMax` | integer | No | — | Living area range in m². |
| `lotSizeMin` / `lotSizeMax` | integer | No | — | Plot size range in m². |
| `buildYearMin` / `buildYearMax` | integer | No | — | Construction year range. |
| `daysForSaleMin` / `daysForSaleMax` | integer | No | — | Days on market range. |
| `energyClassMin` / `energyClassMax` | string | No | — | Energy label range. |
| `zipCodes` | string | No | — | Comma-separated zip codes applied to all queries. |
| `municipality` | integer | No | — | Danish municipality code (kommunekode). |
| `sort` | string | No | `daysForSale-a` | Sort order for search results. |
| `hideBrokerListings` | boolean | No | `false` | Exclude standard broker listings. |
| `hideSelfSale` | boolean | No | `false` | Exclude private self-sale listings. |
| `hideForeclosure` | boolean | No | `false` | Exclude foreclosure listings. |
| `extractDetails` | boolean | No | `false` | Fetch agent contact, BBR data, sales history, and analytics. |
| `detailConcurrency` | integer | No | `10` | Parallel detail requests when extraction is on (1–50). |
| `maxItems` | integer | No | `0` | Maximum listings (`0` = unlimited). |
| `proxyConfiguration` | object | No | residential | Proxy settings. Residential proxy is recommended. |

#### Can I paste a Boliga search URL instead of filters?

Yes. When `startUrls` are provided, query parameters from those URLs drive the search. Listing URLs scrape those specific properties.

### Output example

```json
{
    "id": "995530789",
    "url": "https://www.boliga.dk/adresse/thostruphovgaardsvej-4-9500-hobro-995530789",
    "address": "Thostruphovgaardsvej 4",
    "zipCode": "9500",
    "city": "Hobro",
    "price": 2495000,
    "propertyType": "Villa",
    "rooms": 5,
    "size": 180,
    "lotSize": 1200,
    "buildYear": 1978,
    "energyClass": "D",
    "daysForSale": 42,
    "pricePerSqm": 13861
}
```

When `extractDetails` is enabled, the same row can also include agent contact, BBR data, sales history, and a full image gallery.

### How much does it cost to scrape Boliga.dk?

Billing is pay-per-event. A one-time **Actor Start** fee of **$0.00005** applies per run.

| Event | When it is charged | Price |
|---|---|---|
| Listing | Each property row from search results | **$1.00 per 1,000** |
| Listing Details | Each listing successfully enriched when `extractDetails` is on | **$2.00 per 1,000** |

A listing-only run of 1,000 properties costs about **$1.00** plus Actor Start. Adding details on every listing costs about **$3.00** plus Actor Start. Apify plan discounts may reduce these prices. Platform compute and proxy usage are billed separately on your Apify plan.

### Reliability and responsible use

- **Residential proxy recommended** — Default input uses Apify residential proxies for reliable Boliga runs.
- **Conditional fields** — Agent contact, BBR data, and sales history appear only when detail extraction succeeds.
- **Public data** — The Actor collects publicly visible listing information from Boliga.dk.
- **User responsibility** — Use collected data in line with applicable laws and Boliga terms.

### Frequently asked questions

#### Can I scrape Boliga listings by Danish zip code?

Yes. Add zip codes to `searchQueries`, such as `9500`, or set `zipCodes` to a comma-separated list like `2100,2200,9500`.

#### Can I schedule Boliga Denmark Real Estate Scraper to run automatically?

Yes. Create an Apify schedule on a saved task. Separate tasks per municipality or zip code make monitoring easier.

#### What counts as one result?

Each property written to the dataset counts as one **Listing** event. When `extractDetails` is enabled, each successfully enriched listing also counts as one **Listing Details** event.

#### Why are some agent fields empty?

Agent phone, email, and BBR fields appear only when **Extract Listing Details** is on and Boliga publishes them for that listing.

#### How do I avoid duplicate records?

Within one run, listings are unique by listing ID. Across runs the Actor appends results. Deduplicate user-side against the listing ID when combining datasets.

#### Do I need a proxy?

Residential proxy is recommended for reliable runs on Apify Cloud. The default input enables Apify residential proxies.

### Related Scraptivo automations

- [Funda Netherlands Real Estate Scraper](https://apify.com/scraptivo/funda-nl-scraper) — Dutch property listings
- [Idealista Scraper](https://apify.com/scraptivo/idealista-scraper) — Spanish and Portuguese property listings
- [Realestate.com.au Scraper](https://apify.com/scraptivo/realestate-com-au-scraper) — Australian property listings
- [Daft.ie Property Scraper](https://apify.com/scraptivo/daft-ie-scraper) — Irish property listings
- [Autotrader Scraper](https://apify.com/scraptivo/autotrader-scraper) — UK vehicle listings

### Support and custom workflows

Need a different field, source, or delivery workflow? Contact Scraptivo at scraptivo@gmail.com. Include the Actor name, sample URL, required fields, and expected volume so we can assess the request.

# Actor input Schema

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

Paste Boliga search result URLs (e.g. https://www.boliga.dk/resultat?searchTab=0\&zipCodes=9500) or listing URLs (e.g. https://www.boliga.dk/adresse/thostruphovgaardsvej-4-9500-hobro-995530789). Query parameters from search URLs are used as filters. Listing URLs scrape those specific properties.

## `searchQueries` (type: `array`):

Danish zip codes (e.g. 9500) or free-text location queries (e.g. Hobro, København). Zip codes use the zipCodes filter; other text uses Boliga's q search.

## `propertyTypes` (type: `array`):

Leave empty for all property types.

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

Minimum asking price in Danish kroner.

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

Maximum asking price in Danish kroner.

## `roomsMin` (type: `integer`):

Minimum number of rooms.

## `roomsMax` (type: `integer`):

Maximum number of rooms.

## `sizeMin` (type: `integer`):

Minimum living area in square meters.

## `sizeMax` (type: `integer`):

Maximum living area in square meters.

## `lotSizeMin` (type: `integer`):

Minimum plot/lot size in square meters.

## `lotSizeMax` (type: `integer`):

Maximum plot/lot size in square meters.

## `buildYearMin` (type: `integer`):

Minimum construction year.

## `buildYearMax` (type: `integer`):

Maximum construction year.

## `daysForSaleMin` (type: `integer`):

Minimum days the listing has been on the market.

## `daysForSaleMax` (type: `integer`):

Maximum days the listing has been on the market.

## `energyClassMin` (type: `string`):

Minimum energy label (e.g. A, B, C).

## `energyClassMax` (type: `string`):

Maximum energy label (e.g. C, D).

## `zipCodes` (type: `string`):

Comma-separated Danish zip codes applied to all search queries (e.g. 2100,2200,9500).

## `municipality` (type: `integer`):

Danish municipality code (kommunekode), e.g. 846 for Mariagerfjord.

## `sort` (type: `string`):

How to sort search results.

## `hideBrokerListings` (type: `boolean`):

Exclude standard broker listings from results.

## `hideSelfSale` (type: `boolean`):

Exclude private / self-sale listings.

## `hideForeclosure` (type: `boolean`):

Exclude foreclosure listings.

## `extractDetails` (type: `boolean`):

When enabled, fetches full listing details for each result (agent contact, BBR building data, sales history, price analytics, full photo gallery). Charges an extra listing-details event per enriched listing.

## `detailConcurrency` (type: `integer`):

Maximum number of listings processed in parallel when detail extraction is enabled.

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

Maximum number of listings to scrape (0 = unlimited).

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

Proxy settings. Residential proxy is recommended for reliable runs on Apify Cloud.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.boliga.dk/resultat?searchTab=0&sort=daysForSale-a&zipCodes=9500"
    }
  ],
  "searchQueries": [
    "9500"
  ],
  "sort": "daysForSale-a",
  "hideBrokerListings": false,
  "hideSelfSale": false,
  "hideForeclosure": false,
  "extractDetails": false,
  "detailConcurrency": 10,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

JSON array of scraped property listings

## `runStats` (type: `string`):

Aggregate run statistics including record counts and timestamps

# 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 = {
    "startUrls": [
        {
            "url": "https://www.boliga.dk/resultat?searchTab=0&sort=daysForSale-a&zipCodes=9500"
        }
    ],
    "searchQueries": [
        "9500"
    ],
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scraptivo/boliga-dk-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 = {
    "startUrls": [{ "url": "https://www.boliga.dk/resultat?searchTab=0&sort=daysForSale-a&zipCodes=9500" }],
    "searchQueries": ["9500"],
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("scraptivo/boliga-dk-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 '{
  "startUrls": [
    {
      "url": "https://www.boliga.dk/resultat?searchTab=0&sort=daysForSale-a&zipCodes=9500"
    }
  ],
  "searchQueries": [
    "9500"
  ],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call scraptivo/boliga-dk-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scraptivo/boliga-dk-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/P9MhhPXRJAePkJfVG/builds/7SgMjTnRWKWWAEKu0/openapi.json
