# DBA.dk Scraper (`lowlanddata/dba-dk-scraper`) Actor

DBA.dk, short for Den Blå Avis, is where Danish second-hand goods have been listed since the newspaper era, and its krone stays pegged to the euro, so a price series needs no FX column. Rows give price, locality, trade type and a retailer-or-private flag. No seller names or coordinates collected.

- **URL**: https://apify.com/lowlanddata/dba-dk-scraper.md
- **Developed by:** [Lowland Data](https://apify.com/lowlanddata) (community)
- **Categories:** E-commerce, Automation, Business
- **Features:** Limited permissions
- **Stats:** 7 total users, 4 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.40 / 1,000 results

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

## DBA.dk Scraper

DBA.dk is short for Den Blå Avis, the classifieds paper Denmark read before it was a website, and it is still where Danish second-hand goods get listed. The krone is pegged to the euro, so a DBA price series stays comparable to euro figures over time without an FX column.

Each listing comes back as a flat row: price in whole kroner, locality, trade type, posting timestamp, the seller's spec picks such as brand and condition, the site's own badges, photos at full resolution, and the retailer or private flag. A posting-date window and a price band are inputs, so you can pull one month at a time and keep a clean series going.

**Vehicles too.** Set `vehicleType` and the same run searches DBA Mobility, the site's vehicle side: cars, motorcycles, scooters, ATVs, caravans, motorhomes, boats, trucks, buses, construction machines, tractors and farm equipment. Those rows carry make, model, year, mileage, fuel, gearbox and the vertical's own specifications, and you filter on them before anything is read.

**It runs, every time, and you can check that before you spend anything.** [lowlanddata.com/status/dba-dk-scraper](https://lowlanddata.com/status/dba-dk-scraper/) is this actor's public health record: every run of the last 30 days, the success rate, the daily canary, failures included. Full input/output reference on the [tool page](https://lowlanddata.com/tools/dba-dk-scraper/).

No login, no CAPTCHA solving, no private endpoints. The actor reads what DBA.dk shows a logged-out visitor, paces its requests and stays on standard datacenter proxies - which is also why a scoped run finishes in seconds.

### Quick start (30 seconds)

1. Put what you'd type in the DBA.dk search box into **searchQuery**, e.g. `cykel`.
2. Click **Start**. That's the whole minimum setup.
3. When the run finishes, open the dataset's **Overview** tab for a clean table, or **Export** it as CSV/Excel/JSON.

Optional knobs: paste dba.dk search links instead of typing a query, several queries in one run, a category, a region, a town or a postcode with a radius, private or business sellers, item condition, a price band in Danish kroner and newest-first sorting for monitoring. For vehicles, pick a `vehicleType` instead of a category and add make, model, year, mileage, fuel, gearbox and body type. Any input works on a daily Schedule.

### What you can build with it

- **Watch a niche for underpriced listings.** Run `searchQuery: "el-cykel"` with `priceMax: 15000` and `sortBy: "date"` hourly. Every new listing arrives with `priceAmount` parsed and give-aways (`priceAmount: 0`) included.
- **Scrape the searches you already use.** Set the filters on dba.dk, copy the address from the browser and paste it into `startUrls`: the run returns exactly what that page lists, as many links as you like in one run.
- **Compare several products in one go.** `searchQueries` takes a list (`iphone 14`, `iphone 15`, `iphone 15 pro`) with the same category, place, seller type, condition and price filters for all of them; a listing two searches both find comes back once.
- **Everything within 30 km of Odense.** `location: "Odense"` with `radiusKm: 30`, or a postcode (`5000`) as the starting point, and a category such as `Cykler` or `Sofaer og lænestole` if you want one product group, no coordinates to look up.
- **Map second-hand prices by locality.** Every listing carries its `city`: chart what the same bike costs in Copenhagen versus Aarhus without touching a coordinate.
- **Track retailer vs. private supply.** The `sellerType` flag tells you how much of any category is professional traders, market structure no DBA.dk page shows you.
- **Filter by brand without opening a listing.** `attributes` carries the seller's spec picks - brand, condition, whatever the category offers - so a brand filter is one column, not a title search.
- **Price a used car by make, model and year.** `vehicleType: "car"`, `make: "Volkswagen"`, `model: "Golf"`, `yearMin: 2016`, `mileageMaxKm: 120000`: every match comes back with `year`, `mileageKm`, `fuel` and `priceAmount` as columns, ready for a regression or a pivot table.
- **Watch for a particular boat, caravan or tractor.** The same run takes `boat`, `caravan`, `motorhome`, `tractor` and the other vehicle types, newest first, so a daily schedule with `postedAfter` set to yesterday is an alert feed.
- **Compare dealers and private sellers.** `sellerType` splits a vehicle search into dealers and private sellers, and the row says which each listing is.
- **Feed an AI agent or a pipeline.** Every field is structured and predictable, and the site's nested data is flattened to plain columns, so an assistant can consume it directly with no parsing step.

### What you get

Each listing is one dataset item:

```json
{
  "listingId": "474000001",
  "url": "https://www.dba.dk/recommerce/forsale/item/474000001",
  "title": "Cykel str. 20",
  "priceAmount": 600,
  "currency": "DKK",
  "postedAt": "2026-08-21T06:06:40.000Z",
  "city": "Odense",
  "tradeType": "Til salg",
  "sellerType": "private",
  "attributes": { "brand": "Trek" },
  "labels": ["private"],
  "imageUrl": "https://images.dba.dk/dynamic/default/item/474000001/original",
  "imageUrls": ["https://images.dba.dk/dynamic/default/item/474000001/sized"],
  "description": "Cykel str. 20, næsten ny. Sender gerne.",
  "adId": "474000001",
  "adType": 67,
  "listingType": "bap"
}
```

Field notes, so you know exactly what you are buying:

- `priceAmount` is in whole Danish kroner; `0` covers give-away listings. Listings without a price carry no amount.
- `tradeType` is the site's own label for the ad type: for sale, give-away or wanted ad.
- `attributes` is whatever the seller picked from the category's spec fields, one key per spec. Which keys appear depends on the category - a bike has `brand`, a phone has `model`. Absent when the seller picked nothing.
- `labels` are the site's own badges by id: `retailer` or `private`, plus the shipping and buy-now badges where a listing carries them.
- `imageUrl` is the original photo; `imageUrls` the sized variants the site serves - up to eight from the search page, or the full gallery (up to 24) when **Fetch details** is on.
- `description` is the seller's full free-text description, read from the listing's own page. It appears only when **Fetch details** (`scrapeDetails`) is on - the search results do not carry it. The "Brugerprofil" (seller profile) section is never read, so no name or profile contact reaches the output.
- `city` is locality-level. Seller names, shop names and map coordinates are not collected.
- `postedAt` reflects publication or the seller's last bump.
- `adId`, `adType` and `listingType` are DBA.dk's own identifiers, for anyone reconciling against the site.

#### Vehicle rows

A vehicle search returns rows of this shape instead (a car here; each vehicle type adds only the fields it has):

```json
{
  "listingId": "25514498",
  "vehicleType": "car",
  "title": "Toyota Verso-S",
  "url": "https://www.dba.dk/mobility/item/25514498",
  "priceAmount": 28999,
  "currency": "DKK",
  "city": "Haarby",
  "postedAt": "2026-11-02T10:43:09.000Z",
  "sellerType": "private",
  "make": "Toyota",
  "model": "Verso-S",
  "variant": "D-CAT 150 T3+ aut.",
  "year": 2012,
  "mileageKm": 236000,
  "fuel": "diesel",
  "transmission": "automatic",
  "vehicleClass": "passenger_car",
  "imageUrl": "https://images.dbastatic.dk/dynamic/default/item/25514498/0c548be1-dfd5-4e6a-b65e-2840f3305a67",
  "imageUrls": [
    "https://images.dbastatic.dk/dynamic/default/item/25514498/0c548be1-dfd5-4e6a-b65e-2840f3305a67"
  ],
  "adId": "25514498"
}
```

- `vehicleType` is one of `car`, `motorcycle`, `scooter`, `atv`, `caravan`, `motorhome`, `boat`, `truck`, `bus`, `construction`, `tractor`, `farm-equipment`.
- `make`, `model`, `variant` and `year` are the seller's picks. A year the site states as 0 is left out rather than passed on as 0.
- `mileageKm` is in kilometres. A mileage the site states in miles is left out rather than converted wrongly.
- `fuel` is `petrol`, `diesel`, `electric`, `hybrid_petrol`, `hybrid_diesel`, `plugin_petrol`, `plugin_diesel`, `cng`, `gas_petrol` or `gas_diesel`; `transmission` is `automatic` or `manual`. Both are in English whatever the language of the site, so a column filter needs no translation.
- `engineVolumeCc` (cars, motorcycles, scooters, ATVs, motorhomes), `electricRangeKm`, `operatingHours`, `warrantyMonths` and `vehicleClass` appear when the listing states them.
- Boats add `boatType`, `engineHp`, `engineType`, `engineFuel`, `lengthFeet`, `widthCm` and `topSpeedKnots`.
- With **Fetch details** on, or in a row read by `listingIds`, a vehicle also carries `description`, `equipment`, the full photo gallery (up to 24) and the specifications of its page: `horsepower`, `co2GramsPerKm`, `drive`, `weightKg`, `doors`, `bodyType`, `firstRegistration` and, for boats, the hull material, draught and engine make.
- Registration plates, chassis numbers, dealer names, dealer cards, seller profiles, street addresses and map coordinates are never read. The specification table is read by label, and a label the actor does not know is dropped, not passed through.

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

$3.00 per 1,000 listings delivered, pay-as-you-go: no subscription, and you pay per result rather than per hour. A run that finds nothing still costs the $0.005 actor start. In plain dollars:

- **100 listings ≈ $0.30**, a daily niche watch.
- **500 listings ≈ $1.50**, a solid market snapshot.
- **A 2,500-listing crawl ≈ $7.50**, a full query window, deduplicated.

The price is all-inclusive. Your runs' platform usage is covered by it, with no separate compute or proxy charges. Runs are fast: a scoped few-hundred-item run typically finishes in under ten seconds. Datacenter proxies are sufficient, no residential proxy surcharge needed.

Free-plan runs are limited to a sample of 5 items, enough to evaluate the output format against your real query.

### Not technical? Let your AI assistant set it up

Copy this into ChatGPT, Claude or any AI assistant, fill in the one line, and follow the conversation:

```text
Help me set up the "DBA.dk Scraper" actor on Apify
(https://apify.com/lowlanddata/dba-dk-scraper). Guide me one step at a time.

What I want to watch: [E.G. "electric bikes under 15000 Danish kroner"]

Guide me to:
1. Propose my input values: searchQuery (what I'd type in the DBA.dk search box),
   or search links copied from dba.dk, an optional category, place (and radius in km),
   seller type and condition, a priceMin/priceMax band in Danish kroner, sortBy "date"
   for newest-first monitoring, and maxItems. For cars, boats and other vehicles: the
   vehicleType, plus make, model, year, mileage, fuel and gearbox.
2. Create a free Apify account (apify.com), open the actor page, paste the values
   into the Input form, and start a run.
3. Set up a daily Schedule in the Apify Console with the same input, plus an email
   or Slack integration so new results reach me automatically.
4. Show me how to export results as CSV/Excel, or read them from the API if I code.
5. If the results are what I wanted, remind me at the end to leave a quick rating on the actor page, and to report anything broken or missing on its Issues tab.
```

### Input

| Field                            | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `searchQuery`                    | What you'd type in the DBA.dk search box. Leave it out when you paste links, pick a category or re-check listings through `listingIds`; with links or ids it is ignored.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `searchQueries`                  | More search queries for the same run, one per line, all with the same category, place, seller type, condition and price filters. Up to 50; a listing found twice comes back once.                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `startUrls`                      | dba.dk search pages to scrape, as you copy them from the browser: a marketplace search with its category, place, seller type, condition, price and shipping filters, or a vehicle search (dba.dk/mobility/search/car and the eleven other vehicle types) with its make, year, mileage and fuel. Each link is scraped as the site shows it, so the form fields stand down; the run status says so. Browse pages are refused. Up to 50.                                                                                                                                                                                                                       |
| `listingIds`                     | Re-check listings you already know instead of searching: listing IDs (the number at the end of every listing address, the `listingId` of every row) or the listings' full addresses, marketplace or vehicle, one per line. Each is read from its own page with title, price, town, seller type, the full description and the photos the page carries, and for a vehicle its make, year, mileage, fuel and specifications. A bare number is looked up on the marketplace first and then among the vehicles. A listing that is gone from the site is skipped, named in the log and not billed. When given, the search fields and links are ignored. Up to 50. |
| `category`                       | One category as dba.dk writes it: a main category (`Sport og friluftsliv`), a sub category (`Sofaer og lænestole`), a product category (`Cykler`), or a path (`Forældre og børn > Legetøj`) when two categories share a name. Accents and capitals are forgiving. Leave out the search query to take the whole category.                                                                                                                                                                                                                                                                                                                                    |
| `vehicleType`                    | Search DBA's vehicle site instead of the marketplace: `car`, `motorcycle`, `scooter`, `atv`, `caravan`, `motorhome`, `boat`, `truck`, `bus`, `construction`, `tractor` or `farm-equipment`. Counts as a search on its own: with nothing else it takes the whole vertical, newest first. Seller type, place, radius, price, order and dates work as for the marketplace; `category` and `condition` do not.                                                                                                                                                                                                                                                  |
| `make`                           | Vehicle make as you would write it (`Toyota`, `Volkswagen`, `Mercedes-Benz`). Capitals and accents are forgiving. A make the site has no listings for stops the run with the makes it does have. Needs `vehicleType`.                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `model`                          | Cars only; needs `make`. A model line (`Golf`, `C-Klasse`) takes every generation of it, a single model (`Golf VII`) just that one. Other vehicles: put the model in `searchQuery`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `yearMin`, `yearMax`             | Model year band. Needs `vehicleType`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `mileageMinKm`, `mileageMaxKm`   | Kilometres driven band. Needs a vehicle type that has the filter (cars and motorcycles do; boats do not).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `horsepowerMin`, `horsepowerMax` | Horsepower (hk) band, where the vertical has the filter.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `fuel`                           | Any of `petrol`, `diesel`, `electric`, `hybrid_petrol`, `hybrid_diesel`, `plugin_petrol`, `plugin_diesel`, `cng`, `gas_petrol`, `gas_diesel`. Several mean "any of these". A vertical only offers the fuels the site lists for it; the run stops and names them when you pick another.                                                                                                                                                                                                                                                                                                                                                                      |
| `transmission`                   | `automatic` or `manual`, where the vertical has the filter.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `bodyType`                       | Cars: any of `convertible`, `coupe`, `crossover`, `hatchback_3door`, `hatchback_5door`, `van`, `mpv`, `pickup`, `sedan`, `estate`, `suv`, `other`. Several mean "any of these".                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `location`                       | A region (`Nordsjælland`, `Fyn`), a town or city district (`Odense`, `Aarhus C`) or a four-digit postcode (`5000`). Needs `radiusKm` when it is a postcode. An unknown place stops the run with a message and the closest names.                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `radiusKm`                       | Search this far (0.5 to 300 km) around the town or postcode in `location`. Not for regions.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `sellerType`                     | `any` (default), `private` or `business`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `condition`                      | Any of `new`, `like-new`, `good`, `worn`, `needs-repair`. Several mean "any of these". About one listing in six states no condition and is left out when you pick one.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `priceMin`                       | Only listings costing at least this many Danish kroner.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `priceMax`                       | Only listings costing at most this many Danish kroner.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `sortBy`                         | `date` (newest first, default), `price_asc`, `price_desc`, or `relevance`. A pasted link keeps its own order.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `postedAfter`                    | Only listings posted on or after this date (YYYY-MM-DD). Stops early with newest-first sorting.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `postedBefore`                   | Only listings posted on or before this date (YYYY-MM-DD).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `maxItems`                       | Stop after this many listings in the whole run (default 1000).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `scrapeDetails`                  | Read each listing's own page for the full description and complete photo set (default off). One extra request per listing.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `proxyConfiguration`             | Proxy settings; keep Apify proxy enabled.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |

A run minimally needs a `searchQuery` (or `searchQueries`), a `category`, a `vehicleType`, search links in `startUrls` or a list of `listingIds`; invalid combinations (like an inverted price band, or a vehicle filter without a `vehicleType`) fail immediately with the reason in the run's status message.

#### Searching vehicles

Pick a `vehicleType` and, if you like, narrow it:

```json
{
  "vehicleType": "car",
  "make": "Volkswagen",
  "model": "Golf",
  "yearMin": 2016,
  "mileageMaxKm": 120000,
  "fuel": ["diesel", "plugin_petrol"],
  "sellerType": "private",
  "priceMax": 150000,
  "maxItems": 500
}
```

The actor reads the site's own filter list for that vehicle type once at the start of the run and turns your make, model, fuel and body type into the ids the site uses, so a name you type is matched against the real list: capitals, accents and `Volkswagen` for the site's `VW` are forgiving. If the name is not on the list the run stops before any listing is read and says which makes or models exist. The same goes for a filter the vertical does not have (a boat has no gearbox).

- Each vehicle type has the filters the site gives it: cars have the most; motorcycles filter on make, year, mileage, horsepower and fuel; boats on make, year and fuel. Seller type, place and price work on all of them.
- `searchQuery` still works inside a vehicle type, as free text, and so do `searchQueries`.
- A vehicle search reaches as far as the site pages, 50 pages of about 49 listings. To see more of a big vertical, cut it by make, by year band or by price band and let the runs merge on `listingId`.
- `postedAfter` stops the walk early with the default newest-first order, as on the marketplace.

#### Re-checking listings you already have

Put their IDs (or their addresses) into `listingIds` and nothing else: the run reads each listing's own page and returns it as a row with the same field names as a search result - `listingId`, `url`, `title`, `priceAmount`, `currency`, `city`, `sellerType`, `imageUrl`, `imageUrls` - plus the full `description` the search page never carries; `imageUrls` holds the photos the listing's page renders, which can be fewer than the search response lists. A price change shows up as a new `priceAmount`; a listing that has been sold, has expired or was taken down is not on the site any more - the run skips it, says so in the log and the status, and does not bill it. Schedule such a run and you have a watch on the exact listings you care about. The fields that only the search response carries (`postedAt`, `tradeType`, `labels`, `attributes`, `adType`, `listingType`) are not on a listing's page and are absent from a row read this way.

#### Using search links

Open dba.dk, search, pick a category or a place, set the filters you want (price, condition, private or business, region, distance, shipping) and copy the address from the browser into `startUrls`. Several links run one after the other, a listing two of them list comes back once, and `maxItems` counts the whole run. Because a link already says everything, `searchQuery`, `category`, `location`, `radiusKm` and the other form fields are ignored when links are given; the run status lists which ones.

A few things to know:

- Every filter in the link goes to the site as it is, including several places or several categories picked at once, which the form fields cannot do. If dba.dk does not recognise a filter, the log and the run status name it instead of silently returning a wider search.
- A link keeps its own order. Only a link sorted newest first lets a `postedAfter` date end the walk early; with any other order the run reads on and keeps what falls in the window.
- A link to a single listing is refused with a pointer to `listingIds`.
- A vehicle search link (dba.dk/mobility/search/car, /mc, /mc/scooter, /mc/atv, /caravan, /caravan/mobilehome, /boat, /b2b/truck, /b2b/bus, /b2b/construction, /b2b/agriculturetractor, /b2b/agriculturetools) is read the same way, with its make, year, mileage and fuel filters. A browse page (dba.dk/mobility/browse/...) lists categories rather than listings and is refused with the search link to use instead.

#### Choosing categories, places, sellers and conditions without a link

`category` takes the name as dba.dk writes it, a main category, a sub category or a product category, and lists the closest names when it does not know yours. Main categories: Bil-, båd- og motorcykeludstyr, Dyr og udstyr, Elektronik og hvidevarer, Erhverv, Forældre og børn, Have og renovering, Kunst og antik, Mode og skønhed, Møbler og indretning, Sport og friluftsliv, Underholdning og hobby. A handful of names exist twice (Legetøj, Møbler, Værktøj); write the path (`Forældre og børn > Legetøj`) and the run knows which you mean.

`location` takes a region (`Nordsjælland`), a town or city district (`Odense`, `Aarhus C`) or a four-digit postcode. On its own a region or a town is the site's own place filter. With `radiusKm` the run searches that many kilometres around the town or postcode instead, which is the only way to use a postcode (the site has no postcode filter). A town's centre is taken from its postcodes. Postcode positions come from the GeoNames postal code data (CC BY 4.0, [geonames.org](https://www.geonames.org)).

`sellerType` and `condition` apply to every query of the run. The five conditions are the site's: `new` (Helt ny), `like-new` (Som ny), `good` (Brugt, god stand), `worn` (Brugt, synlige brugsspor) and `needs-repair` (Skal repareres). About one listing in six states no condition at all, and those drop out as soon as you pick one; leave `condition` empty to keep them.

### Use it from your code

Run the actor and get items straight back with one HTTP call (fine for scoped runs up to ~5 minutes):

```bash
curl "https://api.apify.com/v2/acts/lowlanddata~dba-dk-scraper/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
  -X POST -H "Content-Type: application/json" \
  -d '{"searchQuery": "cykel", "maxItems": 100}'
```

Node.js:

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('lowlanddata/dba-dk-scraper').call({
  searchQuery: 'cykel',
  maxItems: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("lowlanddata/dba-dk-scraper").call(
    run_input={"searchQuery": "cykel", "maxItems": 100})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

For bigger crawls, start the run asynchronously and fetch the dataset when the finished-run webhook fires. Schedules (e.g. a daily price snapshot), webhooks and the Make/Zapier/n8n integrations all work out of the box: this is a standard Apify actor.

### Use it with AI agents (MCP)

Claude, Cursor and other MCP-capable agents can run this scraper as a tool through Apify's hosted MCP server: the agent fills in the search itself, starts the run and reads the results, no glue code.

Claude Code:

```bash
claude mcp add apify --transport http "https://mcp.apify.com?actors=lowlanddata/dba-dk-scraper"
```

Cursor or Claude Desktop (add a custom connector / MCP server with this URL):

```text
https://mcp.apify.com?actors=lowlanddata/dba-dk-scraper
```

**Want the whole family at once?** Point one connector at every tool in the EU Marketplaces bundle:

```text
https://mcp.apify.com?actors=lowlanddata/kleinanzeigen-scraper,lowlanddata/marktplaats-scraper,lowlanddata/tweedehands-scraper,lowlanddata/olx-pl-scraper,lowlanddata/olx-ro-scraper,lowlanddata/olx-pt-scraper,lowlanddata/willhaben-scraper,lowlanddata/finn-no-scraper,lowlanddata/tori-fi-scraper,lowlanddata/blocket-se-scraper,lowlanddata/dba-dk-scraper,lowlanddata/gumtree-uk-scraper,lowlanddata/vinted-scraper,lowlanddata/bol-com-scraper,lowlanddata/subito-scraper,lowlanddata/bazos-cz-scraper,lowlanddata/bazos-sk-scraper,lowlanddata/olx-bg-scraper,lowlanddata/olx-ua-scraper,lowlanddata/willhaben-car-scraper,lowlanddata/kleinanzeigen-free-finds,lowlanddata/olx-listing-watch,lowlanddata/marktplaats-new-listing-alerts,lowlanddata/tweedehands-new-listing-alerts,lowlanddata/kleinanzeigen-deal-radar
```

Sign in with your Apify account when prompted. Runs are billed to it. Setup details per client: [Apify MCP docs](https://docs.apify.com/platform/integrations/mcp), or start from this actor's own MCP page: [apify.com/lowlanddata/dba-dk-scraper/api/mcp](https://apify.com/lowlanddata/dba-dk-scraper/api/mcp).

Prompts that work once connected:

- "Search DBA.dk for 'el-cykel' under 15000 Danish kroner and summarize the price distribution."
- "Get the 100 newest 'iphone 15' listings from DBA.dk and flag private sellers below the median price."
- "Watch DBA.dk for 'kajak' and tell me when something under 3.000 Danish kroner appears."
- "Find diesel Volkswagen Golfs from 2016 or later under 120,000 km on DBA.dk and tell me what the median asking price is."

### Beyond the ~2,600-result window

DBA.dk serves at most 50 pages per query (about 2,650 listings). The run reports honestly when a query is bigger than its window: the status says how many of the matching listings could be read. For full coverage, cut the search into smaller ones and let the run merge them: several `searchQueries`, one `category` per run, a `location` per region, or price bands (`priceMin`/`priceMax`) across runs. A listing found twice comes back once within a run, and overlapping runs merge cleanly on `listingId`.

### Is it legal to scrape DBA.dk?

Listing prices, titles and localities are public commercial information. This actor reads what DBA.dk shows any logged-out visitor, never signs in, bypasses no anti-bot protection, and paces its requests so its load on the site is negligible. It does not collect seller names, shop names or map coordinates; the only seller-derived field is whether a listing comes from a retailer or a private person. Titles are the seller's own words, delivered as-is.

Denmark applies the GDPR, supervised by Datatilsynet. How you store and use the data once it is yours is governed by the law of your own jurisdiction.

This actor is an independent tool. It is not affiliated with, endorsed by or sponsored by DBA.dk or its owners, and trademarks belong to their respective holders.

### Is there a DBA.dk API alternative?

DBA.dk's public API programme is aimed at partners, not ad-hoc listing search. This actor is the practical alternative: the same listings as structured JSON through one HTTP call (`run-sync-get-dataset-items`), on a schedule, or as an MCP tool for AI agents.

### Does DBA.dk block scrapers?

This actor makes ordinary requests: paced, on standard datacenter proxies, load kept negligible. No CAPTCHA fights, no bot-wall cat-and-mouse, which is also why runs are fast and reliable enough for daily schedules. The health record above shows how that holds up day to day.

### How do I monitor DBA.dk prices?

Set `sortBy: "date"` with your query, cap `maxItems` to a page or two, and add a daily (or hourly) Schedule in the Apify Console with an email/Slack integration on the runs. Every new listing lands in your inbox with the price already parsed. The AI-assistant prompt above walks a non-technical user through exactly this setup. Even tighter: set `postedAfter` to yesterday's date: the dataset then contains only the new listings, nothing to dedupe on your side.

### FAQ

**Can I get seller names or phone numbers?** No. The output says whether the seller is a retailer or a private person, and nothing else about them.

**Does it cover cars, boats and property?** Cars and boats yes, and every other vehicle on DBA Mobility: motorcycles, scooters, ATVs, caravans, motorhomes, trucks, buses, construction machines, tractors and farm equipment. Set `vehicleType`. Property is not on DBA.dk.

**What can I filter a vehicle search on?** Make, model (cars), year, mileage, horsepower, fuel, gearbox, body type (cars), seller type, place and radius, and price, wherever the vehicle type has the filter on the site. A filter a vertical does not have makes the run stop and say so, rather than quietly searching wider.

**Do vehicle rows include the registration plate or the seller?** No. The plate, the chassis number, dealer names and profiles, street addresses and coordinates are never read. The seller is a retailer or private flag and the location is the town.

**Can I paste my dba.dk search links?** Yes, put them in `startUrls`, as many as you like. Each is scraped exactly as the site shows it. See Using search links above.

**Can I search several things at once?** Yes. `searchQueries` takes a list, and each query runs with the same category, place, seller type, condition and price filters. The listings come back as one deduplicated dataset.

**Can I search around a town or a postcode?** Yes. Give `location` (`Odense` or `5000`) and `radiusKm`. A region or a town without a radius uses the site's own place filter.

**Can I filter by category, private or business sellers and condition?** Yes: `category`, `sellerType` and `condition` do that. About one listing in six states no condition and is left out when you pick one.

**Can I get only the newest listings?** Yes, set `postedAfter` to a date (yesterday, say) and the dataset contains only listings posted since then. With newest-first sorting the run stops paging as soon as it provably reaches older listings, so a daily watch stays fast and cheap.

**How fresh is the data?** Live at run time: every run queries DBA.dk directly. For continuous freshness, schedule the actor.

**Can I export to Excel or CSV?** Yes, every dataset exports as CSV, Excel, JSON or XML from the Apify Console or API.

**Does it work with Make, Zapier or n8n?** Yes, it is a standard Apify actor; all platform integrations, webhooks and schedules apply.

**Does DBA.dk offer an API I could use instead?** Its API programme is for partners; there is no self-serve listings API. This actor stands in for one: the same listings, structured, one HTTP call away.

**Is it legal to scrape DBA.dk?** Prices, titles and localities are public commercial data, and the output carries no seller identity. See the section above.

**How much do 1,000 DBA.dk listings cost?** $3.00, metered per delivered listing. Nothing is charged when a run fails or comes back empty.

**How do I scrape all listings for a big DBA.dk search?** The site caps any query at 50 pages, around 2,650 results. Slice it by category, by region or by price band (`priceMin`/`priceMax`) and merge the runs on `listingId`: duplicates collapse cleanly. Several `searchQueries` or several links in one run are merged for you.

**How do I bulk-download DBA.dk listings?** That is what a run is. Set `maxItems` to the size you need, up to the ~2,650-listing window per query, then export the dataset as CSV, Excel or JSON from the Console or read it over the API. Beyond one window, split by category, region or price band.

**Can I sort DBA.dk results?** Yes, `sortBy` accepts `date` (the default, newest first), `price_asc`, `price_desc` and `relevance`.

**Can I restrict results to a date range?** `postedAfter` and `postedBefore` (YYYY-MM-DD) bound the window. With the default newest-first order, `postedAfter` lets the run quit early instead of paging through history.

**How do I separate private sellers from shops?** Check `sellerType` on each item: it says retailer or private, and that is the only seller-derived field in the output.

**Does the data pinpoint where a seller lives?** No. You get the locality name in `city` and nothing finer.

**What is in `attributes`?** The spec fields the seller filled in for that category - brand, condition, size, model - one key each, flattened so they land as ordinary columns in an export. Which keys appear depends entirely on the category and on what the seller picked.

**What are `labels`?** DBA.dk's own badges on the listing, by id: `retailer` or `private`, plus the shipping and buy-now badges where a listing carries them.

**How quickly does a run finish?** Scoped runs of a few hundred items usually complete in under ten seconds, fast enough to call synchronously from your code.

**What is the maximum per run?** Whatever you put in `maxItems`; the default is 1,000. On Apify's free plan a run returns at most 5 items.

**Is there a free trial?** Effectively yes: free-plan runs deliver a 5-item sample from your actual query, so you can inspect the output before paying anything.

**Do items include pictures?** Yes. `imageUrl` is the original photo at full resolution; `imageUrls` is an array of the sized variants, up to eight.

**What does a price of 0 mean?** A give-away listing. The actor includes these rather than discarding them.

**Can an AI assistant run this actor?** Yes, via Apify's hosted MCP server, agents like Claude or Cursor can start runs and read results directly. The MCP section above has the exact URLs.

**Why do bumped listings reappear as new?** Because `postedAt` tracks publication or the seller's latest bump: a bump refreshes the timestamp, and the listing surfaces again in date order.

### Related scrapers

Working the Nordic second-hand market? Same output discipline, same public health record:

- [Blocket.se Scraper](https://apify.com/lowlanddata/blocket-se-scraper): Sweden's biggest marketplace.
- [Tori.fi Scraper](https://apify.com/lowlanddata/tori-fi-scraper): Finland's biggest marketplace.

### Troubleshooting

The actor fails fast with the reason in the run's status message:

- **"Provide a searchQuery, a category, a vehicleType, search links in startUrls, or the listingIds to re-check."**: the run needs a scope; add a searchQuery, a category, a vehicleType or a search link.
- **"make, model, year, mileage, horsepower, fuel, transmission and bodyType are vehicle filters ..."**: set `vehicleType` to use them.
- **"make ... was not found among the cars"** (or the boats, and so on): the message lists the makes with listings; a model that is not found lists the models of that make.
- **"... is not a valid filter for boats"**: that vertical does not have the filter on the site; the message lists the ones it has.
- **"category and condition are marketplace filters ..."**: drop them, or drop `vehicleType` to search the marketplace.
- **"category ... was not found on dba.dk."**: use the Danish name as the site writes it; the message lists the closest names. A name that exists twice asks for the path (`Forældre og børn > Legetøj`).
- **"location ... was not found on dba.dk."**: use a region, a town, a city district or a four-digit postcode; the message lists the closest names.
- **"radiusKm needs a location ..."**: a radius is measured around a town or a postcode, not a region and not nothing.
- **"... is a single listing, not a search page."**: put listing addresses in `listingIds` instead of `startUrls`.
- **"... is a browse page ..."**: a dba.dk/mobility/browse link lists categories; use the search link the message names.
- **"DBA.dk did not recognise ..., so that filter was not applied."**: a filter in a pasted link that the site ignores; the results are wider than the link suggests.
- **"priceMin must not be higher than priceMax."** and **"yearMin, mileageMinKm and horsepowerMin must not be higher than their max."**: swap the two values.
- **"The site blocked the run before any results could be fetched. This is usually temporary - retry in a few minutes."**: a temporary block on the first request; a retry usually lands on a clean proxy session.
- **"... the site serves at most 50 pages per search ..."**: the search is bigger than DBA.dk's result window; narrow it with a category, a place or a price band for full coverage.
- **Fewer items than requested on a free plan**: the 5-item free sample cap; run on a paid Apify plan for full results.

### Support

Found an issue or missing a field you need? The fastest route is the actor's **Issues tab** - it is monitored and reports get fixed. For anything private, email **contact@lowlanddata.com**. This actor is actively maintained.

Working well for you? A **rating on this page** takes ten seconds and helps other buyers find it: it is also the clearest signal of what we should build next.

# Actor input Schema

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

What to search for on DBA.dk, exactly as you would type it in the site's search box, e.g. "cykel" or "iphone 15". <b>Ignored when you paste search links or listing IDs below</b>; the run status says so. Leave it out to search a whole category.

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

More searches in the same run, one per line, with the same category, place, seller type, condition and price filters. A listing found by two searches comes back once. <b>Max listings counts the whole run</b>, and the searches run in the order given. Up to 50.

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

Paste search pages copied from dba.dk: a marketplace search (dba.dk/recommerce/forsale/search) with the filters you set on the site (category, place and distance, seller type, condition, price, shipping), or a vehicle search (dba.dk/mobility/search/car, /mc, /boat, /caravan/mobilehome and the other ten) with its make, year, mileage, fuel and the rest. Each link is scraped exactly as the site shows it, so the form fields below stand down for it. <b>Search pages only</b> - for single listings use Specific listing IDs; a browse page (dba.dk/mobility/browse/...) lists categories, not listings. Up to 50.

## `listingIds` (type: `array`):

Re-check listings you already know instead of searching: one listing ID per line (the number at the end of every listing address on DBA.dk, and the <code>listingId</code> of every dataset item), or the listing's full address - marketplace or vehicle. Each one is read from its own page: title, price, town, seller type, the full description and the photos on its page, and for a vehicle its make, year, mileage, fuel and the other specifications. A bare number is looked up on the marketplace first and then among the vehicles. A listing that is gone from the site is skipped, named in the log and not billed. <b>When given, the search fields of this form are ignored</b> and the run status says which. Up to 50.

## `category` (type: `string`):

Limit the search to one category, written as dba.dk writes it: a main category (<code>Sport og friluftsliv</code>), a sub category (<code>Sofaer og lænestole</code>) or a product category (<code>Cykler</code>). Capitals, spaces and accents are forgiving ("Moebler" finds Møbler). When two categories share a name, write the path (<code>Forældre og børn > Legetøj</code>); the run stops and lists the options if you do not. The easiest way to find a name is to browse dba.dk and paste the link into <b>DBA.dk search links</b>. Empty = all categories.

## `vehicleType` (type: `string`):

Search vehicles instead of the marketplace: DBA's vehicle site (DBA Mobility), one kind at a time. The vehicle fields below (make, model, year, mileage, horsepower, fuel, transmission, body type) apply to it; <b>Category and Condition do not</b>. Seller type, place, radius, price, order and dates work as for the marketplace. Leave empty to search the marketplace.

## `make` (type: `string`):

Vehicle make as you would write it: <code>Toyota</code>, <code>Volkswagen</code>, <code>Mercedes-Benz</code>. Capitals and accents are forgiving. When the site has no listings for a make, the run stops and lists the makes it does have. Needs <b>Vehicle type</b>.

## `model` (type: `string`):

Cars only; needs <b>Make</b>. A model line (<code>Golf</code>, <code>C-Klasse</code>) takes every generation of it, a single model (<code>Golf VII</code>) just that one. For other vehicles put the model in Search query. When the model is not found, the run stops and lists the ones the site has for that make.

## `yearMin` (type: `integer`):

Only vehicles of this model year or later. Needs <b>Vehicle type</b>.

## `yearMax` (type: `integer`):

Only vehicles of this model year or earlier.

## `mileageMinKm` (type: `integer`):

Only vehicles that have driven at least this many kilometres. Not every vehicle type has a mileage filter; the run stops and says so when it does not.

## `mileageMaxKm` (type: `integer`):

Only vehicles that have driven at most this many kilometres.

## `horsepowerMin` (type: `integer`):

Only vehicles with at least this many horsepower (hk). Not every vehicle type has the filter; the run stops and says so when it does not.

## `horsepowerMax` (type: `integer`):

Only vehicles with at most this many horsepower (hk).

## `fuel` (type: `array`):

Only vehicles that run on these fuels; pick several to include any of them. Empty = any. A vehicle type only offers the fuels the site lists for it (a boat has petrol, diesel and electric); the run stops and names them when you pick one it does not.

## `transmission` (type: `string`):

Automatic or manual gearbox. Not every vehicle type has the filter (boats do not); the run stops and says so when it does not. Empty = either.

## `bodyType` (type: `array`):

Cars: only these body types; pick several to include any of them. Empty = any. A vehicle type without the filter makes the run stop and say so.

## `location` (type: `string`):

Limit the search to a region (<code>Nordsjælland</code>, <code>Fyn</code>, <code>København og omegn</code>), a town (<code>Odense</code>, <code>Aarhus C</code>) or a four-digit postcode (<code>5000</code>), written as in Danish ("Aarhus" and "Århus" both work). Combine it with <b>Search radius</b> to search around a town or a postcode. When the place is not known the run stops and says so.

## `radiusKm` (type: `number`):

Search this far around the town or postcode in <b>Place</b> (0.5 to 300 km). Needs a town or a postcode, not a region. Empty = the place itself.

## `sellerType` (type: `string`):

Private sellers only, businesses (dealers) only, or both.

## `condition` (type: `array`):

Only listings in these conditions, the five the site offers; pick several to include any of them. Empty = any condition. Listings without a stated condition are left out when you pick one.

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

Only include listings costing at least this many Danish kroner.

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

Only include listings costing at most this many Danish kroner.

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

Order of results: date (newest first, best for monitoring), price_asc, price_desc, or relevance. A pasted link keeps its own order.

## `postedAfter` (type: `string`):

Only include listings posted on or after this date. With newest-first sorting the run stops early once older listings are reached. <b>Format: <code>YYYY-MM-DD</code></b> (for example <code>2026-09-08</code>) or a full ISO timestamp such as <code>2026-09-08T14:30:00Z</code>. Slash dates like <code>08/09/2026</code> are refused on purpose: they are read as September in Europe and August in the United States, and this actor will not guess which you meant.

## `postedBefore` (type: `string`):

Only include listings posted on or before this date. <b>Format: <code>YYYY-MM-DD</code></b> (for example <code>2026-09-08</code>) or a full ISO timestamp such as <code>2026-09-08T14:30:00Z</code>. Slash dates like <code>08/09/2026</code> are refused on purpose: they are read as September in Europe and August in the United States, and this actor will not guess which you meant.

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

Stop after this many listings. Free-plan runs are capped at 5 items. The form starts at 25 for a cheap first run - that is the form's prefill, not a cap on your plan; clear it to use the default of 1000.

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

Read each listing's own page for the seller's full free-text description and the complete photo set, neither of which the search results carry. This makes one extra request per listing, so a run is slower and costs one more page fetch each. The seller-profile section is never read - no name or profile contact reaches the output. Leave off for a fast price-and-photo sweep.

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

Proxy settings. Keep Apify proxy enabled.

## `reportFailures` (type: `boolean`):

When a run fails, send the developer the actor name and build, an error category, the error message (truncated) and a one-way hash of your input - so a bug can be fixed without anyone asking you to reproduce it. <b>Your input itself, your results and your identity are never sent, and successful runs send nothing at all.</b> Switch this off and the actor behaves exactly the same.

## Actor input object example

```json
{
  "searchQuery": "cykel",
  "listingIds": [],
  "sellerType": "any",
  "sortBy": "date",
  "maxItems": 25,
  "scrapeDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "reportFailures": true
}
```

# Actor output Schema

## `listings` (type: `string`):

Scraped DBA.dk listings, one JSON object per listing.

# 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": "cykel",
    "listingIds": [],
    "sortBy": "date",
    "maxItems": 25,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("lowlanddata/dba-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 = {
    "searchQuery": "cykel",
    "listingIds": [],
    "sortBy": "date",
    "maxItems": 25,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("lowlanddata/dba-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 '{
  "searchQuery": "cykel",
  "listingIds": [],
  "sortBy": "date",
  "maxItems": 25,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call lowlanddata/dba-dk-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lowlanddata/dba-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/FGHGf5dOtVisaxbvO/builds/Ku0tbhpzv3p2p4LeG/openapi.json
