# DBA Scraper: Denmark Classifieds, Cars, Prices (`automation_craft/dba-scraper`) Actor

Second hand ads from DBA.dk (Den Blå Avis), Denmark's largest online marketplace: furniture, electronics and 13 vehicle types by word, område, dealer or plate, past the 50 page cap, no login. Fields: pris i kr., mærke, kilometertal, synsdato, CVR. Free price summary per område; pay per ad, API.

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

## Pricing

from $1.89 / 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

### DBA Scraper: Denmark Classifieds, Cars, Prices

**DBA scraper** for DBA.dk (Den Blå Avis), Denmark's largest online marketplace: search DBA's marketplace (general goods:
furniture, electronics, clothes, children's things, art and every other category) and its vehicles (cars, motorcycles, mopeds and
scooters, ATVs, boats, caravans, motorhomes, trucks, buses, construction machinery, tractors, farm machinery, combine harvesters) by
keyword, category, DBA area or town, map radius, DBA's own filters, a dealer, a plate or VIN, a pasted DBA link or an ad id, and get
every ad as one row: title, price in Danish kroner, place and DBA area, map point, photos, private seller or company, and on vehicles
make, model, model year, mileage in km, fuel, gearbox and the vehicle type's own facts. Every search also gives a free price summary
of the ads it met, by DBA area and by category or make. Add the ad page for the full description, every key fact, the inspection
dates, equipment, the shop profile or the dealer card with its CVR number, and on vehicles DBA's own list of similar vehicles and a
market valuation from the asking prices of comparable ads. No login, no cookies, no residential proxy.

Who uses it: resellers and flippers pricing second hand goods and hunting vintage Danish furniture, car, MC, boat, caravan and
machine dealers watching other dealers' stock and prices, buyers abroad looking for Danish design, analysts of
Denmark's second hand and used car markets by area and category, and teams feeding DBA data into their own sheets, apps or AI agents.

### Quick start

1. Open the **Input** tab. In **What to search** pick `Marketplace (general goods)`, `Vehicles (cars, MC, boats and more)` or both.
2. Add **Keywords** (`sofa`, `barnevogn`, `spisebord`), **Marketplace categories** by DBA's Danish name (`Møbler og
   indretning`, `Sofaer og lænestole`, `Mobiltelefoner`) or **Vehicle types** (cars are the default), and **Places** (`København
   og omegn`, `Odense`, `Aarhus N`).
3. Narrow it with DBA's filters: price, seller (`Privat` or `Forhandler`), condition, ad type, brand, **Fiks færdig only**; on
   vehicles **Makes** and **Models**, model year, mileage in km, **Fuel**, **Gearbox**, **Body or type**, **Equipment**
   (`Anhængertræk` for a towbar), **Registration class** (`Varebil ex. moms` for vans) and the type's own filters. Or give **Dealer
   ids (vehicles)**, **Plates to look up (vehicles)**, **VINs to look up (vehicles)**, or paste DBA links into **Search links** and
   **Ad links or DBA ad ids**.
4. Turn on **Include the ad page (Ad details)** for the full ad, and on vehicles **Add similar vehicles (add-on)** or **Add a market
   valuation (add-on)** if you want them. Set **Maximum rows** and click **Start**. Download the rows as JSON, CSV or Excel, or read
   them through the Apify API.

The prefilled input reads 20 sofas (`sofa`) in København og omegn from the marketplace: 20 Listing events and 1 Results page,
$0.0458 at Gold and $0.0612 on the Free plan with the start fee (4 seconds on a test run of 2026-10-24). For a daily feed, schedule
the run in Apify (set **Posted within (hours)** to 24) and keep the ad ids you have seen in your own sheet or flow: this Actor keeps no
memory between runs.

### What you get

One row per ad (`type: "listing"`, `vertical: "marketplace"` or `"vehicles"`), one free coverage row per search with its price
summary (`type: "search"`), free status rows for anything that could not be delivered (`type: "status"`) and a run summary
(`type: "summary"`). Every price is in Danish kroner (`currency: "DKK"`). A field DBA does not show for an ad is `null`.

#### Fill rates measured

The share of delivered rows that carry each field, measured on the test actor's runs of 2026-10-24 (builds 0.1.2 and 0.1.3; run
files `platform-results/<run>.items.json`, each ad counted once per column, the run with **Include personal data** on left out).
Marketplace, search row: 2,526 rows from 14 runs (`dba-t5-worst-marketplace-1000` 981, `dba-t5-keyword-tail-left-out` 812,
`dba-t2-marketplace-300-rows` 600, 11 smaller runs 133). Marketplace, Ad details: 61 rows from 3 runs
(`dba-t6-worst-50-searches-one-row-details` 50, `dba-t1-marketplace-details-category` 9, `dba-t4-ad-links` 2). Vehicles, search row:
1,033 rows from 6 runs (`dba-t5-worst-cars-1000` 1,000 cars, 5 runs of the other types 33). Vehicles, Ad details: 113 rows from 9
runs (`dba-t5-worst-50-dealers-one-row` 50, `dba-t3-dealer-stock` 19, `dba-t4-private-sellers-off` 10, 6 smaller runs 34), 98 of
them cars and 73 of them dealers' ads, so the business fields there stand for dealers. A private seller's plate and VIN are counted
with personal data off, so they appear only on business rows here and on runs with **Include personal data** on. "n/a": not a
field of that row.

| Field | Marketplace, search row | Marketplace, Ad details | Vehicles, search row | Vehicles, Ad details |
|---|---|---|---|---|
| `price` | 100% | 100% | 100% | 100% |
| `region` | 100% | 100% | 100% | 100% |
| `location` | 100% | 100% | 100% | 100% |
| `latitude` | 99% | 100% | over 99% | 100% |
| `imageUrl` | over 99% | 98% | 97% | 96% |
| `sellerType` | 100% | 100% | 100% | 100% |
| `companyName` | 11% | 12% | 39% | 65% |
| `tradeType` | 100% | 100% | 0% | 4% |
| `brand` | 11% | 39% | n/a | n/a |
| `searchAttributes` | 12% | 41% | n/a | n/a |
| `shippingAvailable` | 100% | 100% | n/a | n/a |
| `description` | 0% | 100% | 0% | 96% |
| `condition` | 0% | 85% | 0% | 9% |
| `categoryPath` | 0% | 100% | n/a | n/a |
| `postalCode` | 0% | 100% | 0% | 100% |
| `make` | n/a | n/a | over 99% | 100% |
| `model` | n/a | n/a | 99% | 99% |
| `year` | n/a | n/a | 100% | 100% |
| `mileageKm` | n/a | n/a | 98% | 95% |
| `fuel` | n/a | n/a | 98% | 98% |
| `transmission` | n/a | n/a | 97% | 91% |
| `registrationClass` | n/a | n/a | 97% | 87% |
| `plate` | n/a | n/a | 27% | 54% |
| `vin` | n/a | n/a | 35% | 59% |
| `powerHp` | n/a | n/a | 0% | 94% |
| `equipment` | n/a | n/a | 0% | 69% |
| `firstRegistration` | n/a | n/a | 0% | 90% |
| `lastInspection` | n/a | n/a | 0% | 23% |
| `inspectionReportUrl` | n/a | n/a | 0% | 54% |
| `dealer` | n/a | n/a | 0% | 65% |
| `companyOrgNumber` | 0% | 12% | 0% | 64% |
| `companyPhone` | 0% | 8% | 0% | 64% |

#### On every row

| Field | What it is |
|---|---|
| `adId`, `url`, `title` | DBA's ad id (Annonce-ID), the ad's link, its title as served |
| `price`, `currency` | the asking price as a number, in DKK |
| `status`, `soldAt` | `active`, or `sold` when DBA marks the ad sold ("Solgt"), with the time when DBA gives one |
| `location`, `region`, `regionSource` | DBA's place (a town or a city district), the ad's DBA area (one of DBA's 12: `København og omegn`, `Fyn`, `Østjylland` ...), and whether the area was read from the town (`dbaTown`) or the city district (`dbaDistrict`) in DBA's own location tree |
| `latitude`, `longitude`, `coordinateAccuracy` | the ad's map point |
| `postalCode`, `postalName`, `streetAddress` | the postal code and town of the ad page, and a company's street |
| `publishedAt`, `editedAt` | when DBA published the ad, when it was last edited (ad page) |
| `sellerType`, `companyName`, `companyId`, `companyPageUrl` | `private` or `business`, the shop's or dealer's name, DBA id and page on DBA |
| `labels` | DBA's own labels on the search row ("Privat", "Forhandler", "Fiks færdig", "Køb nu", "Fri fragt") |
| `imageUrl`, `imageUrls`, `imageCount` | the main image, every image link, their count |
| `searchKey`, `searchLabel`, `position`, `source`, `detailsIncluded`, `scrapedAt` | the search the row came from, its place in the results, `search` or `link`, whether the ad page was read, the read time |
| `paidPlacement` | with **Mark paid placements** on: `true` when the row is the paid ad DBA shows above the search |

#### Marketplace rows

| Field | What it is |
|---|---|
| `tradeType`, `tradeTypeEnglish` | "Til salg" (for sale) or "Gives væk" (given away free), and in English |
| `brand`, `searchAttributes` | the brand DBA shows on the search row, the search row's own attributes (size, memory ...) |
| `shippingAvailable`, `buyNow`, `sellerPaysShipping` | DBA's flags: sent with DBA's own shipping service ("Fiks færdig"), "Køb nu", "Fri fragt" |
| `mainCategory`, `subCategory`, `category`, `categoryPath` | DBA's category path (ad page) |
| `condition`, `conditionEnglish` | DBA's condition label ("Brugt - men i god stand"), and in English (ad page) |
| `description`, `descriptionText`, `attributes`, `attributesById` | the seller's text as served and as plain text, the ad's key facts with DBA's Danish labels, and the same values under DBA's own attribute ids (`lego_theme`, `mobile_memory_size`, `depth` ...) (ad page) |
| `isWebshop`, `mapImageUrl` | DBA's webshop flag and DBA's map image of the ad's point (ad page) |
| `companyOrgNumber`, `companyPhone`, `companyWebsite`, `companyAddress`, `companyLogo` | a shop's profile: CVR number, phone, website, address, logo (ad page) |

#### Vehicle rows

| Field | What it is |
|---|---|
| `kind`, `vehicleKind`, `vehicleKindLabel` | the vehicle type you asked for (`car`, `mc`, `boat` ...), DBA's view type and its label ("Cars (Biler)") |
| `make`, `series`, `model`, `modelSpecification`, `year` | make, model series, model, model line, model year |
| `mileage`, `mileageUnit`, `mileageKm` | mileage as DBA serves it (`KILOMETER`) and in kilometres |
| `fuel`, `transmission`, `bodyType`, `wheelDrive`, `colour` | as DBA names them, each with an English twin (`fuelEnglish`, `transmissionEnglish` ...) |
| `registrationClass`, `dealerSegment`, `salesForm` | "Personbil", "Varebil ex. moms" or "Varebil inkl. moms"; "Privat" or "Forhandler"; "Brugtbil til salg" (the sales form with the ad page) |
| `plate`, `vin`, `inspectionReportUrl` | the registration number, the VIN (stelnummer) and the public inspection report link that carries the plate (a dealer's whenever DBA shows them; a private seller's only with **Include personal data** on) |
| `powerHp`, `engineVolume`, `doors`, `seats`, `weightKg`, `maxTrailerWeight`, `co2` | engine power, engine size, doors, seats, weight, towing weight, CO2 (ad page) |
| `batteryCapacity`, `drivingRangeKm`, `rangePerKwh` | battery, range and range per kWh of an electric car (ad page) |
| `firstRegistration`, `lastInspection`, `nextInspection`, `owners` | first registration, the last and next inspection (syn) dates, number of owners (ad page) |
| `equipment`, `sellerKnowledge`, `knownDamages`, `damagesDetails`, `majorRepairs`, `hasLiens` | equipment list, and a private seller's own answers on the car (DBA's "Sælgers kendskab til bilen"): damage, repairs, liens (ad page) |
| `boatClass`, `lengthFeet`, `widthCm`, `depthCm`, `material`, `motorType`, `motorSize`, `maxSpeedKnots`, `sleepers` | boat class, length, width, draught, hull, engine, top speed, berths |
| `redFlags` | warning signs as evidence: the seller's own damage, repair and lien answers, and mentions in the title or description of export only, damage or a fault, a lease takeover, a driving ban, deregistration or a sale for parts, each with the phrase and the sentence around it (a mention is only a mention: "ingen skader" mentions damage too) |
| `daysOnMarket`, `searchAdsOnDba` | days since publication, DBA's count of the search the row came from |
| `dealer` | the dealer card (below), with the ad page |

#### The dealer card and the shop profile

With the ad page, every dealer ad carries `dealer`: DBA's dealer id (`id`, the one **Dealer ids (vehicles)** takes), `name`, the
Danish CVR number (`orgNumber`) with its company register link (`registryUrl`, datacvr.virk.dk), `address`, `phone`, `email`,
`website`, `logo`, `description`, `openingHours`, `openingNow`, `sellingPoints`, `yearsOnDba` (DBA's own text, such as "5+ år på
DBA"), `adCount` (the dealer's ads on DBA), `pageUrl` and `adsUrl` (DBA's search of the dealer's ads). A marketplace shop's ad page
fills the row's company fields (name, address, phone, website, CVR number, logo) and `companyPageUrl`. A CVR number names a business,
so these are business data and always delivered.

#### Example row

One dealer car of a test run of 2026-10-24 (`dba-t2-cars-details-addons`, the test actor's build 0.1.2) with the ad page, similar
vehicles and the market valuation, trimmed to the main fields (the full row has 191 keys):

```json
{
  "type": "listing", "vertical": "vehicles", "kind": "car",
  "adId": "26117361", "url": "https://www.dba.dk/mobility/item/26117361", "title": "VW Passat",
  "make": "VW", "model": "Passat", "modelSpecification": "1,4 TSi 150 Comfortline DSG  4D", "year": 2016,
  "mileage": 170000, "mileageUnit": "KILOMETER", "mileageKm": 170000,
  "fuel": "Benzin", "fuelEnglish": "petrol", "transmission": "Automatisk", "transmissionEnglish": "automatic",
  "bodyType": "Sedan", "powerHp": 150, "weightKg": 1413, "registrationClass": "Personbil",
  "price": 109900, "currency": "DKK", "location": "Silkeborg", "postalCode": "8600",
  "region": "Østjylland", "regionSource": "dbaTown", "latitude": 56.2012998, "longitude": 9.581734,
  "publishedAt": "2026-10-24T10:47:33.000Z", "sellerType": "business", "dealerSegment": "Forhandler",
  "companyName": "Bilhuset Silkeborg", "companyId": "5781083", "companyOrgNumber": "37409391",
  "plate": "CR39953", "vin": "WVWZZZ3CZGE056988", "firstRegistration": "2015-10-15",
  "dealer": {
    "id": "5781083", "name": "Bilhuset Silkeborg", "orgNumber": "37409391",
    "registryUrl": "https://datacvr.virk.dk/enhed/virksomhed/37409391", "phone": "51 51 53 39",
    "website": "http://www.bilhusetsilkeborg.dk/", "address": "A.C.Illums Vej 9, 8600 Silkeborg",
    "adCount": 169, "yearsOnDba": "5+ år på DBA", "pageUrl": "https://www.dba.dk/mobility/dealer/5781083/bilhuset-silkeborg"
  },
  "similarVehiclesStatus": "delivered",
  "marketValuation": {
    "comparables": 47, "currency": "DKK", "medianPrice": 114900, "p25Price": 94900, "p75Price": 138700,
    "priceVsMedianPercent": -4.4, "priceVsMedianDkk": -5000, "confidence": "high", "adsInSearch": 55
  },
  "marketValuationStatus": "delivered"
}
```

#### The coverage row of each search, with its price summary (free)

Every search ends with one free row: DBA's count of ads (`adsOnDba`), the filters sent (`filtersSent`), DBA's order (`order`),
pages and rows read, distinct ads met (`distinctAdsMet`), ads delivered (`adsDelivered`), ads already delivered by an earlier
search of the run (`alreadyDelivered`), ads left out by a check (`filteredOut`, `filteredOutBy`), slices read past DBA's reach
(`slicesRead`), ads that stayed beyond reach (`adsBeyondReach`), whether the search was read to its end (`complete`) and why it
stopped (`stoppedBy`). With **Mark paid placements** on, `paidPlacement` names the paid ad DBA showed above the search and whether
it stood among the results.

Its `priceSummary` gives the count, lowest, quartiles (`p25`, `median`, `p75`), mean and highest asking price of the ads the search
met that passed every check on the row, the count of ads without a price (`withoutPrice`), and the same per DBA area (`byRegion`) and
per category (`byCategory`, marketplace) or per make (`byMake`, vehicles), each part with its count, median, lowest, highest and
mean, largest first. Each marketplace category you name is its own search, so asking for several categories gives you prices by
category and by area in one run. Turn it off with **Price summary per search**; it is free either way.

#### Add-on: Ad details (the ad page)

**Include the ad page (Ad details)** reads each ad's page and merges it into the row: the full description, every key fact and photo,
the category path, the postal code, the edit time, a shop's profile, and on vehicles the equipment, registration date, inspection
dates, owners, warranty, declared damages, the inspection report link and the dealer card. It is billed as one Ad details per row that
carries its ad page and takes about a second per row. The ad page is always read (and billed) on an ad link, on a plate or VIN
lookup, with the similar vehicles add-on and with a car weight range.

#### Add-on: Similar vehicles list

**Add similar vehicles (add-on)** adds `similarVehicles`: DBA's own list of vehicles like the ad (`adId`, `url`, `title`, the year
and mileage text as DBA shows it in `details`, the price as DBA shows it in `priceText` and as a number of kroner in `price`, `imageUrl`). It reads the ad page too.
`similarVehiclesStatus` says `delivered` or why the list is empty; only `delivered` is billed. Measured on a test run of 2026-10-24:
10 of 10 cars carried a list.

#### Add-on: Market valuation and the deal filter

**Add a market valuation (add-on)** reads, for each vehicle chosen for delivery, DBA's search of the same make and model one model
year either side, its newest 50 ads, and keeps only the other ads of exactly that make and model with a price. From those asking
prices `marketValuation` gives the count (`comparables`), `medianPrice`, `p25Price`, `p75Price`, `minPrice`, `maxPrice`,
`meanPrice`, a `confidence` (high with 20 or more comparable ads, medium with 10 to 19, low below), DBA's own count of that search
(`adsInSearch`), five comparable ads to check by hand (`comparableSample`), the `basis` in words, and how far this vehicle's price
stands from the median (`priceVsMedianPercent`, `priceVsMedianDkk`). It works on searches and on ad links alike. These are asking
prices, not sale prices. With fewer comparable ads than **Minimum comparable ads** (5 by default, up to 50), or a vehicle without
make, model or model year, there is no valuation and nothing is billed (`marketValuationStatus` says why).

The deal filter delivers only the vehicles you want to see: **Deal filter: at most this far from the median (%)** (`-10` for at least
10 percent under the market) or **(DKK)** (`-20000` for at least 20,000 kr. under). **Leave out red flagged vehicles** drops every
vehicle whose row carries a red flag. Vehicles left out, or without a valuation while a deal filter is set, are free. Measured on a
test run of 2026-10-24: 5 VW Golf at least 15 percent under their median delivered, 4 others left out free.

#### Plate and VIN lookups

**Plates to look up (vehicles)** and **VINs to look up (vehicles)** find the DBA ad of each vehicle you name. Danish plates such as
`DM69584`, `DM 69584` or `DM 69 584` are sent as DBA stores them and as its pages write them, 10 plates to one DBA search; a
personalised plate (2 to 7 letters and digits holding a digit) is sent as typed, and VINs 20 to one search, in each vehicle type you
pick (cars when **Vehicle types** is empty), at most 300 plates and 300 VINs a run. Every vehicle DBA answers has its ad page read,
and a row is delivered only when the ad page shows the plate or VIN asked. Each delivered row names the lookups it answers in
`matchedLookups` (list and position, never the plate or VIN). Each search's coverage row lists its lookups with `found` (`true`,
`false`, or `null` when the search could not be read in full), and the run summary repeats every result. A plate or VIN no ad carries
costs nothing. Measured on a test run of 2026-10-24: 4 plates and 1 VIN in one search, 3 plates and the VIN found, the made up plate
not found, 6 seconds; 50 plates no ad carries cost the start fee only.

A private seller's plate field stays empty with **Include personal data** off, even on the row its plate found.

#### Dealer stock

**Dealer ids (vehicles)** reads every vehicle of one dealer with DBA's own dealer filter, one search per dealer and vehicle type. It
takes DBA's dealer id (the `companyId` of a dealer row) or the dealer's page link on DBA
(`https://www.dba.dk/mobility/dealer/<id>/<name>`, the `companyPageUrl` of a dealer row). With the ad page on, every row carries the
dealer card. Measured on a test run of 2026-10-24: 20 cars of one dealer (the cap set, of 106 DBA counted) with their ad pages in 28
seconds.

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

You pay per event, with Apify's store discounts by plan. A marketplace ad and a vehicle cost the same; the ad page and the vehicle
add-ons are billed only when you turn them on and only on a row that carries them.

| Event | Free plan | Bronze | Silver | Gold |
|---|---|---|---|---|
| Listing (one marketplace ad row, primary) | $2.65 per 1,000 | $2.42 per 1,000 | $2.19 per 1,000 | $1.89 per 1,000 |
| Vehicle (one vehicle row, any type) | $2.65 per 1,000 | $2.42 per 1,000 | $2.19 per 1,000 | $1.89 per 1,000 |
| Ad details (one row that carries its ad page) | $0.84 per 1,000 | $0.77 per 1,000 | $0.70 per 1,000 | $0.60 per 1,000 |
| Results page (a search page that brings an ad new in the run and delivers one; up to 300 marketplace ads or 50 vehicles) | $0.70 per 1,000 pages | $0.64 per 1,000 pages | $0.58 per 1,000 pages | $0.50 per 1,000 pages |
| Similar vehicles list (add-on, one per row that carries a list) | $0.70 per 1,000 | $0.64 per 1,000 | $0.58 per 1,000 | $0.50 per 1,000 |
| Market valuation (add-on, one per row that carries a valuation) | $1.40 per 1,000 | $1.28 per 1,000 | $1.16 per 1,000 | $1.00 per 1,000 |
| Actor start (once per run at the default 256 MB) | $0.0075 | $0.0075 | $0.0075 | $0.0075 |

Platinum and Diamond plans pay the Gold price. The Actor start is a flat fee per run, with no plan discount.

The Store pricing card shows these same prices per 1,000 events: "$1.89 / 1,000" on the Listing row means one marketplace ad costs
$0.00189 at Gold, and "$1.40 / 1,000" on the Market valuation row means one valuation costs $0.0014 on the Free plan.

- **Listing** is charged once per marketplace ad delivered as a row, **Vehicle** once per vehicle ad, from a search, a dealer, a
  lookup or a link. An ad met twice in one run (two keywords, two slices) is delivered and billed once.
- **Results page** is charged once per DBA search page the run reads that brings at least one ad not met before in the run and from
  which an ad is delivered (up to 300 marketplace ads or 50 vehicles a page, so about $0.002 per 1,000 marketplace ads and $0.01 per
  1,000 vehicles at Gold). It pays for the searches that deliver only a few rows (a plate list, many dealers, many small searches),
  so the row price stays low. A page of repeats, a page whose ads are all left out by a filter, a page DBA did not apply, the first
  page of a split, an empty search, ad links and every page of a run's restarted attempt are free.
- **Ad details**, **Similar vehicles list** and **Market valuation** are charged only with their setting on (Ad details also on ad
  links, lookups, similar vehicles and a car weight range), and only on a row that carries them.
- Never billed: repeats in the run, ads left out by a filter (the keyword tail below included), a plate or VIN no ad carries, a
  removed or unknown ad link, a vehicle with too few comparable ads, a refused setting, a search that finds nothing, coverage rows,
  status rows and the summary.
- **Every run is charged the Actor start fee ($0.0075), also when it finds nothing** (an empty input, a filter no ad passes, a plate no
  ad carries, a refused setting): such a run costs $0.0075.

Worked examples, computed from the prices above with the start fee included. The rows marked "measured" billed exactly these events
on a test run of 2026-10-24; a real run can bill one or two more Results pages where a page brings only a few new ads.

| Run | Events | Free plan | Bronze | Silver | Gold |
|---|---|---|---|---|---|
| The prefill: 20 sofas in København og omegn (measured) | 20 Listing, 1 Results page | $0.0612 | $0.0565 | $0.0519 | $0.0458 |
| 1,000 marketplace ads, search rows only (measured) | 1,000 Listing, 4 Results pages | $2.6603 | $2.4301 | $2.1998 | $1.8995 |
| 1,000 marketplace ads with their ad pages | 1,000 Listing, 1,000 Ad details, 4 Results pages | $3.5003 | $3.2001 | $2.8998 | $2.4995 |
| 1,000 cars, search rows only (measured) | 1,000 Vehicle, 20 Results pages | $2.6715 | $2.4403 | $2.2091 | $1.9075 |
| 100 cars with their ad pages | 100 Vehicle, 100 Ad details, 2 Results pages | $0.3579 | $0.3278 | $0.2977 | $0.2575 |
| 200 cars with the market valuation | 200 Vehicle, 200 Market valuation, 4 Results pages | $0.8203 | $0.7501 | $0.6798 | $0.5875 |
| 200 cars with similar vehicles | 200 Vehicle, 200 Ad details, 200 Similar vehicles list, 4 Results pages | $0.8483 | $0.7761 | $0.7038 | $0.6075 |
| 50 keywords, one ad each (measured) | 50 Listing, 50 Results pages | $0.1750 | $0.1605 | $0.1460 | $0.1270 |
| A run that delivers nothing | none | $0.0075 | $0.0075 | $0.0075 | $0.0075 |

Set the run's maximum cost in Apify high enough for large runs: a row whose events do not all fit under it is withheld whole, never
delivered unbilled or billed without its data.

### Input

The Actor has 105 settings; every one is in the **Input** tab with its own help text. The main ones:

| Setting | What it does |
|---|---|
| `verticals` | `marketplace` (general goods) and `vehicles`, each its own search. Left empty: the marketplace, or vehicles when only vehicle settings are given. |
| `keywords` | Search words, each its own search (`sofa`, `iphone 15`, `vw golf`). DBA matches them in the ad texts. |
| `onlyKeywordMatches` | On by default: a marketplace keyword search delivers only ads whose title (or description, with the ad page) carries every word of the search; the rest of DBA's results are left out free (below). |
| `categories` | Marketplace categories, sub categories or product categories by DBA's Danish name (`Møbler og indretning`, `Sofaer og lænestole`, `Mobiltelefoner`) or value, each its own search. |
| `vehicleTypes` | The vehicle searches, each its own: `car` (Cars (Biler), the default), `mc` (Motorcycles (MC)), `scooter` (Mopeds and scooters), `atv` (ATVs), `boat` (Boats (Både)), `caravan` (Caravans (Campingvogne)), `mobileHome` (Motorhomes (Autocampere)), `truck` (Trucks (Lastbiler)), `bus` (Buses (Busser)), `construction` (Construction machinery), `tractor` (Tractors (Traktorer)), `agriTools` (Farm and garden machinery), `threshers` (Combine harvesters), or `b2bAll` (All business vehicles: trucks, buses, construction, farm). |
| `dealerIds` | Dealer ids or dealer page links, each a search of every vehicle of that dealer (per vehicle type). |
| `plates`, `vins` | Plate and VIN lookups (above). Not together with keywords or dealer ids. |
| `searchUrls` | DBA search links (`https://www.dba.dk/recommerce/forsale/search?...` or `https://www.dba.dk/mobility/search/<type>?...`), read with all their filters. |
| `adUrls` | Ad links (`/recommerce/forsale/item/<id>`, `/mobility/item/<id>`, `https://www.dba.dk/<id>`) or ad ids, up to 5,000, each read with its ad page. A removed or unknown ad is a free status row. |
| `locations` | DBA's 12 areas (`København og omegn`, `Fyn`, `Østjylland`), its towns (`Odense`, `Aarhus`, `Aalborg`) or city districts (`Odense C`, `Aarhus N`) by DBA's name or value, or a postal code (`8600` is Silkeborg, `5000` Odense C, `1620` København V; DBA files every town and district under its postal code). Several places are one search. A postal code DBA lists no place for (a post box code) is a free row, and the other places run. |
| `radiusAround`, `radiusKm` | DBA's own map radius (1 to 500 km) around a town, a city district or a postal code (`"radiusAround": "8600", "radiusKm": 20`), at the centre point DBA itself gives that place on its ads (read from DBA's rows on 2026-10-24 for 650 of its 769 places: every Danish place with ads; four small islands with no ads and 115 places of the Faroe Islands and Greenland have none, and naming one is a free row that asks for a point instead). |
| `latitude`, `longitude`, `radiusKm` | The same radius around a point in Denmark you give. |
| `minPrice`, `maxPrice`, `sellerType`, `postedToday` | Price in kroner, private sellers or companies and dealers only (DBA's "Privat" and "Forhandler"), DBA's "Nyt i dag". |
| `conditions`, `tradeTypes`, `brands`, `shippingOnly` | Marketplace: DBA's condition labels, ad type ("Til salg", "Gives væk", "Ønsker at købe"), brand (`HAY`, `IKEA`, `Stokke`), Fiks færdig only. |
| `makes`, `models`, `minYear`, `maxYear`, `minMileage`, `maxMileage`, `minPowerHp`, `maxPowerHp`, `fuelTypes`, `transmissions`, `bodyTypes`, `wheelDrives`, `colours`, `salesForms` | DBA's vehicle filters by DBA's Danish names (`VW`, `Golf`, `El`, `Automatisk`, `Stationcar`). Mileage in km, as DBA counts it. |
| `equipment`, `wheelSets`, `warrantyTypes`, `conditionDocuments`, `registrationClasses`, `minTrailerWeightKg`, `maxTrailerWeightKg` | Cars: equipment (`Anhængertræk`, `Apple CarPlay`, `Bakkamera` ...), wheel sets, DBA's warranty filter (`Garanti`), service history (`Service`), registration class (`Personbil`, `Varebil ex. moms`, `Varebil inkl. moms`), towing weight. |
| `minEngineCc`, `maxEngineCc`, `vehicleConditions` | MC, mopeds and ATVs: engine size in cc; new or used (MC, caravans, motorhomes). |
| `minLengthFeet`, `maxLengthFeet`, `minWidthCm`, `maxWidthCm`, `minBoatEngineHp`, `maxBoatEngineHp`, `minTopSpeedKnots`, `maxTopSpeedKnots`, `boatMaterials`, `boatEngineTypes`, `boatEngineIncluded`, `berths`, `seatGroups`, `vehicleLocations` | Boats: length, width, engine power, top speed, material, engine type, engine included, berths, seats, where the boat stands (`Danmark` or `Udlandet`). |
| `minLengthCm`, `maxLengthCm`, `minWeightKg`, `maxWeightKg` | Caravans and motorhomes: length; caravans, motorhomes and trucks: weight, sent to DBA. Cars: the weight is read from each car's ad page (DBA's car search has no weight filter), so every car of the search has its ad page read and billed as Ad details when delivered; a car whose page shows no weight is left out, free. The pages of cars left out are unpaid work: when the newest cars of the search fail the range, the run stops on its allowance (about 20 car pages) with a free status row, so narrow the search (a make, a body type) for a range few cars meet (measured 2026-10-25: 1,500 kg and up delivered 5 of 5 on one run and stopped after 21 lighter cars on another). |
| `attributeFilters` | Any other filter of the search's own DBA filter list, by name or Danish label: `{"truck_segment": ["Kassevogn"], "construction_segment": ["Minigraver"]}`. |
| `postedAfter`, `postedWithinHours`, `postedBefore`, `includeKeywords`, `requireAllKeywords`, `excludeKeywords`, `titleOnly`, `excludeAdIds` | Filters checked on every row; an ad left out is free. **Posted before** reads the newer ads in front and leaves them out free, so a day far back can stop the run on its allowance for unpaid reads. |
| `maxItems`, `maxItemsPerSearch`, `maxPagesPerSearch`, `maxRowsPerSearch`, `startPage` | Paid rows per run (default 100), per search, pages per search, rows read per search; **Start page** reads every search from that page of DBA's own results (53 marketplace ads or 50 vehicles a page) to go on where an earlier run stopped (such a search is not split and its coverage row says it is not complete; not with plates or VINs). |
| `includeDetails`, `includeSimilarVehicles`, `includeMarketValuation`, `minComparables`, `maxPriceVsMarketPercent`, `maxPriceVsMarketDkk`, `excludeRedFlagged` | The add-ons and the deal filter (above). |
| `includePersonalData`, `markPaidPlacements` | The personal data switch (below); the paid ad flag (one free extra read per search). |
| `priceSummary`, `includeRawData`, `descriptionFormat`, `descriptionMaxLength`, `outputFields`, `compactOutput`, `excludeEmptyFields`, `extractContacts`, `phoneExtractionMode` | The price summary per search (on by default); DBA's search row; description `asServed`, `text` or `markdown` and a length cut; your own field list or the most used fields only; empty fields left out; e-mails, phones, websites and social profiles written in the texts (companies' ads always, private ads with personal data on). |
| `failIfIncomplete`, `completenessTolerancePercent`, `completenessToleranceAbsolute`, `maxFailedRequestsPercent`, `proxyConfiguration`, `requestsPerSecond`, `maxConcurrency`, `maxRequestRetries` | Fail the run when a search is incomplete or too many reads failed; your own bar for a complete search; your own proxy links (Apify's datacenter proxy by default, which every DBA door answers); the pace (0.2 to 2 requests a second, default 1), requests in flight (1 to 4), retries (0 to 5). |

A run reads at most 300 searches. A monitor or alert setting refuses the run with a free row that says this Actor keeps no monitor,
and an empty input is refused with a free row (only the run's start fee is charged).

#### Example inputs

Sofas and armchairs in København og omegn and Nordsjælland, with their ad pages:

```json
{ "verticals": ["marketplace"], "categories": ["Sofaer og lænestole"], "locations": ["København og omegn", "Nordsjælland"], "includeDetails": true, "maxItems": 200 }
```

Used VW Golf in Østjylland under 100,000 kr., with a market valuation, only those at least 10 percent under the median:

```json
{ "verticals": ["vehicles"], "makes": ["VW"], "models": ["Golf"], "maxPrice": 100000, "locations": ["Østjylland"], "includeMarketValuation": true, "maxPriceVsMarketPercent": -10, "maxItems": 100 }
```

Which of these cars are for sale on DBA, and at what price:

```json
{ "plates": ["DA47162", "DX 24 542"], "vins": ["VSSZZZ1PZ7R114474"] }
```

Every vehicle of one dealer, with the dealer card:

```json
{ "dealerIds": ["https://www.dba.dk/mobility/dealer/5781083/bilhuset-silkeborg"], "includeDetails": true, "maxItems": 500 }
```

#### DBA's keyword search and its tail

DBA's marketplace search ranks a keyword's results by relevance and ends them with ads that do not carry the word (related goods,
and a few unrelated ads even for a made up word). With **Only ads that carry the search words** on (the default), a marketplace row
of a keyword search is delivered only when its title (or its description, with the ad page read) holds every word of the search;
the others are left out, free, and counted on the coverage row (`filteredOutBy.onlyKeywordMatches`). Words match as parts of words
("sofa" matches "hjørnesofa"), and "a OR b" means either. Measured on a test run of 2026-10-24: "kajak" met all 1,449 ads DBA counted
and delivered 813, 636 left out free, in 7 seconds. Turn it off to get every ad DBA's search returns.

#### Every filter is checked

Every named filter is resolved against the search's own DBA filter list. A value the list does not offer (a make, a place, a
category) is a free row that lists the values it does offer, and the search delivers nothing: an unknown value never widens a search.
A filter a vehicle type does not have (engine size on cars) refuses that search with a free row naming the filters it has. DBA's
vehicle search drops a value it does not know without a word and answers its whole stock; every page DBA answers must echo back the
filters sent, so a page where DBA dropped one becomes a free row and nothing from it is delivered or billed.

#### Past DBA's 15,000 and 2,500 ad reach

DBA serves at most 50 pages of one search: 15,000 marketplace ads at 300 a page, and 2,500 vehicles at 50 a page. Past page 50 the
marketplace answers an error and the vehicle search answers page 1 again; the walk stops at the lower of page 50 and DBA's own last
page, and a page that is not the page asked for is never delivered or billed. The marketplace counted 3,394,428 ads and cars 21,887 on
2026-10-24. When DBA counts more ads than one search can reach and you want more, the search is split into slices by DBA's own
counts: marketplace searches by category, sub category and product category, then by area; vehicle searches by make and model, make,
boat class and area; then by price bands. Each slice is read in DBA's own order, an ad met in an earlier slice is skipped free, and
the coverage row says how many slices were read and how many ads stayed beyond reach (`adsBeyondReach`). A search is `complete` when
its slices met about every ad DBA counted (at least 98 percent less 2 ads on a split search, 99 percent less 2 on one search, or your
own bar set with `completenessTolerancePercent` and `completenessToleranceAbsolute`). DBA counts a few ads on a category and in none of its parts (`adsNoSliceHolds` on the coverage row): no slice can reach them, and
the coverage row then says not complete and how many. Measured on 2026-10-25: every boat, 3,524 of 3,524 in 2 slices, complete; a
sub category of 16,548 ads ("Erhvervskøkken og restaurant"), 16,501 delivered in 2 slices, 47 held only on the sub category itself.

#### Restarts

If Apify restarts a run on another server, the run reads its own dataset back: the rows already delivered are neither delivered nor
charged again, and the pages of the restarted attempt are free. Nothing is billed twice.

#### Personal data

A private seller is an ad DBA marks as private ("Privat"). With **Include personal data** off (the default), these fields are null on
a private seller's row: the plate and VIN (`plate`, `vin`, and their entries in the key facts `attributes`), the inspection report
link that carries the plate (`inspectionReportUrl`), the seller's DBA user id (`sellerId`), street (`streetAddress`), the seller's
own links and ad references, the contacts found in the texts (**Extract contacts from texts**) and the raw search row; a private
seller's map point is rounded to 2 decimals (about 1 km) when DBA gives it to the address. On every ad, a contact person's name, phone
and e-mail (`contacts`) are null with the switch off. Turning the switch on adds all of these. A company's or dealer's name, id, CVR
number, address, phone, website and dealer card are business data and always delivered. Titles, descriptions, equipment texts and
the seller's own answers are delivered exactly as DBA serves them, so an ad's own text can name a person or give a phone number. DBA
shows no private seller's name to visitors who are not logged in, so this Actor never has it. Plate and VIN lookups work with the
switch on or off. You are responsible for a lawful use of personal data, GDPR included.

### FAQ

#### Does DBA have a public API?

This Actor works as one: it reads DBA's public search and ad pages, logged out, and gives you the rows through the Apify API as
JSON, CSV or Excel, with a free coverage row per search that gives DBA's own count of ads (`adsOnDba`).

#### How do I scrape dba.dk listings and prices?

Open the **Input** tab, pick the marketplace or vehicles, add keywords, categories or places (or paste DBA search links), set
**Maximum rows** and click **Start**: each ad is one row with its price in kroner, place, DBA area and seller, and each search ends with
a free price summary by area and by category or make. The prefilled input (20 sofas in København og omegn) costs $0.0458 at Gold.

#### Is it legal to scrape DBA?

This Actor reads only the public search and ad pages any visitor sees without logging in, never sends the sort parameter or opens the
profile, contact and map pages DBA's robots.txt disallows, and withholds a private seller's personal data unless you turn **Include
personal data** on. DBA's terms and its page footer forbid systematic collection of its content without DBA's written permission, so
check DBA's terms, Danish law and the GDPR for your own use; you are responsible for a lawful use.

#### How do I get notified when a new ad appears on DBA?

This Actor sends no notifications and keeps no memory between runs. Schedule the run in Apify with **Posted within (hours)** set to 24,
or **New today** on: each run delivers the ads DBA published in that window, and you keep the ad ids you have already seen in your
own sheet or flow.

#### What do things sell for on DBA?

DBA shows asking prices, not sale prices. Each search's free coverage row gives the count, lowest, quartiles, median, mean and highest
asking price of the ads it met, and the same per DBA area and per category (marketplace) or make (vehicles); for vehicles, **Add a
market valuation (add-on)** sets each vehicle's price against the median of the same make and model one model year either side.

#### Why does this Actor run with limited permissions?

It needs nothing outside its own run: it reads DBA and writes only to its own run's dataset and key-value store, and it opens no
named storage. Limited permissions keep the rest of your Apify account out of its reach.

### What this Actor does NOT do

- **No other sites.** This listing reads DBA only; Blocket and FINN.no have their own listings (below), and one run never mixes
  sites, so every row is a DBA row.
- **No sort order.** DBA's robots.txt asks robots not to send its sort parameter, so every search is read in DBA's own default order
  (newest first on vehicles and, by DBA's default, on marketplace searches without words; relevance with words); a pasted link's sort
  is dropped with a free note.
- **No monitor and no alerts.** It keeps no memory between runs: no "new only" rows, no price change, sold or removal tracking across
  runs, no Telegram, Slack, Discord, WhatsApp or webhook alerts; a run that asks for one is refused with a free row (only the run's start
  fee is charged, as on every run) and reads nothing. Schedule the run in Apify
  (**Posted within (hours)** set to 24) and compare the rows in your own sheet or flow by `adId`. Within one run, a removed ad link is a
  free status row.
- **No private seller name, no messages.** DBA's ad pages name no private seller to visitors who are not logged in; this Actor never
  logs in and never contacts a seller. A shop's name and phone and a dealer's name, phone and e-mail are on the ad page and delivered.
- **No login only data.** Saved searches, favourites, messages, a seller's profile pages (`/profile`, disallowed by DBA's robots.txt)
  and anything behind a DBA account are not read.
- **No homes and no jobs.** DBA has no housing or job search today; this listing reads its marketplace and its vehicles.
- **No sale prices.** Prices, price summaries and market valuations are asking prices of ads on DBA.
- **No other currencies.** DBA prices in DKK only; rows carry DKK and `currency`.
- **No view counts.** DBA's pages carry no view count.
- **No paid ad rows outside the results.** The paid ad DBA shows above a search is never delivered as a row of its own; with **Mark
  paid placements** on, a delivered row that is that paid ad says `paidPlacement: true`.
- **No photo downloads.** Photo links only.
- **No guessed spellings and no empty input sample.** A value is used as you send it (after trimming and case) or refused with a free
  row listing DBA's own values; an input with nothing to search is refused with a free row, and the Console prefill is the example.
- **No unpaid crawling.** A run stops with a status row when its unpaid work (pages whose ads were all filtered out or already
  delivered, removed ads, the reads that check a search's filters) passes a small allowance (USD 0.0004 plus a share of every billed
  event): narrow the search or loosen the filters checked on each row. Each add-on likewise may spend USD 0.003 (USD 0.0005 with a
  deal or red flag filter) on reads that bill nothing, plus a share of its delivered events.

### API and integrations

Run it from the Apify API, the Apify client for JavaScript or Python, Make, Zapier, n8n or any HTTP client. Example with the API (put
your own token in place of `<YOUR_TOKEN>`):

```bash
curl -X POST "https://api.apify.com/v2/acts/automation_craft~dba-scraper/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"verticals": ["marketplace"], "keywords": ["sofa"], "locations": ["København og omegn"], "maxItems": 20}'
```

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_TOKEN>' });
const run = await client.actor('automation_craft/dba-scraper').call({ verticals: ['vehicles'], makes: ['VW'], includeMarketValuation: true, maxItems: 50 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

```python
from apify_client import ApifyClient
client = ApifyClient("<YOUR_TOKEN>")
run = client.actor("automation_craft/dba-scraper").call(run_input={"verticals": ["marketplace"], "categories": ["Mobiltelefoner"], "maxItems": 100})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

Every row carries `type`; keep `type == "listing"` for the ads, and read the coverage rows (`type == "search"`) for the price
summaries and to see whether each search was read in full. The run report (`REPORT` in the run's key-value store) sums up the run.

#### Use it from an AI agent (MCP)

AI agents can run this Actor as a tool through Apify's MCP server: connect your MCP client to `https://mcp.apify.com` and add
`automation_craft/dba-scraper` to its tools. The agent sends the input as JSON (for example `{"verticals": ["vehicles"], "makes": ["VW"], "locations": ["Fyn"], "maxItems": 20}`) and reads the run's dataset back: the ad rows (`type: "listing"`), the coverage row
of each search with its price summary (`type: "search"`), status rows and the summary. For agents, set `compactOutput` (the most used
fields only, `region` and `mileageKm` included) or `outputFields`, and `excludeEmptyFields`, keep `maxItems` small, and read the
coverage row to see whether a search was read to its end and how many ads DBA counts.

### Changelog

See the Changelog tab (0.1, the launch).

### More data tools by Automation Craft

- [Blocket Scraper: Ads, Prices, Cars and Counties](https://apify.com/automation_craft/blocket-scraper)
- [FINN.no Scraper: Torget, Cars, Homes and Jobs](https://apify.com/automation_craft/finn-scraper)
- [FINN Motor Scraper: Norway Cars, MC and Boats](https://apify.com/automation_craft/finn-motor-scraper)
- [FINN Eiendom Scraper: Norway Homes and Rentals](https://apify.com/automation_craft/finn-eiendom-scraper)
- [FINN Jobs Scraper: Norway Job Ads, Employers](https://apify.com/automation_craft/finn-jobs-scraper)
- [Marktplaats Scraper: Ads, Cars, Sellers & Alerts](https://apify.com/automation_craft/marktplaats-scraper)
- [willhaben Scraper: Immobilien, Cars, Jobs & Ads](https://apify.com/automation_craft/willhaben-scraper)
- [Kleinanzeigen Scraper & API: Ads, Prices, Places](https://apify.com/automation_craft/kleinanzeigen-scraper)
- [Gumtree Scraper: UK, Australia, South Africa Ads](https://apify.com/automation_craft/gumtree-scraper)
- [Mobile.de Scraper: Cars, Prices, Dealers & Ratings](https://apify.com/automation_craft/mobile-de-scraper)
- [AutoScout24 Scraper: EU Car Listings & Prices](https://apify.com/automation_craft/autoscout24-scraper)

# Changelog

This Actor's version history is a separate document: https://apify.com/automation_craft/dba-scraper/changelog.md

# Actor input Schema

## `verticals` (type: `array`):

DBA's marketplace (general goods: furniture, electronics, clothes and every other category) and its vehicles (cars, motorcycles, boats, caravans and more), each its own search. Left empty: the marketplace, or vehicles when only vehicle settings are given.

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

Search words, each one its own search ("sofa", "iphone 15", "vw golf", "barnevogn", "spisebord"). DBA matches them in the ad texts. Left empty, each search reads without words, newest first.

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

Marketplace only: DBA categories, sub categories or product categories by DBA's Danish name ("Møbler og indretning", "Sofaer", "Mobiltelefoner") or DBA's value ("0.78"). Each category is its own search, with its own price summary.

## `vehicleTypes` (type: `array`):

Vehicles only: which DBA vehicle searches to read, each its own search. Left empty: cars.

## `dealerIds` (type: `array`):

Every vehicle of one dealer: DBA's dealer ids (the companyId of a dealer row) or a dealer's page link on DBA (https://www.dba.dk/mobility/dealer/<id>/<name>, the companyPageUrl of a dealer row), each its own search per vehicle type (DBA's own dealer filter). Not together with plates or vins.

## `plates` (type: `array`):

Danish plates such as "DM69584", "DM 69584" or "DM 69 584", or a personalised plate of 2 to 7 letters and digits holding a digit: each looks for the DBA ad of that vehicle in each vehicle type (cars when vehicleTypes is empty), sent as DBA stores it and as its pages write it, up to 10 plates to one DBA search. A row is delivered only when the vehicle's own plate on its ad page is the plate asked; each plate's result (found, not found) is on its search's free coverage row. At most 300 a run; not together with keywords or dealerIds.

## `vins` (type: `array`):

Vehicle identification numbers (stelnummer, 11 to 17 letters and digits holding both): each looks for the DBA ad of that vehicle, as plates do, 20 VINs to one DBA search. A VIN no ad carries is free (its search's coverage row says not found).

## `locations` (type: `array`):

DBA's areas ("København og omegn", "Fyn", "Østjylland"), towns ("Odense", "Aarhus", "Aalborg") or city districts ("Odense C", "Aarhus N") by DBA's name, or DBA's value ("0.200009"), or a postal code ("8600", "2100"; DBA's place of that code). Several places are one search (any of them).

## `latitude` (type: `number`):

With longitude and radiusKm: search around a point in Denmark (DBA's own map radius).

## `longitude` (type: `number`):

With latitude and radiusKm.

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

With latitude and longitude, or with radiusAround: the distance in kilometres.

## `radiusAround` (type: `string`):

With radiusKm: search around a DBA town or city district ("Silkeborg", "Aarhus C") or a postal code ("8600"), at the centre point DBA gives that place. Instead of latitude and longitude.

## `minPrice` (type: `integer`):

The lowest price in Danish kroner, sent to DBA.

## `maxPrice` (type: `integer`):

The highest price in Danish kroner, sent to DBA.

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

Private sellers only, or companies and dealers only (DBA's own seller filter, "Privat" or "Forhandler").

## `postedToday` (type: `boolean`):

Only ads DBA marks as new today ("Nyt i dag").

## `conditions` (type: `array`):

DBA's condition labels: "Helt ny - uåbnet/med prismærke", "Som ny - ingen synlige brugsspor", "Brugt - men i god stand", "Brugt - med synlige brugsspor", "Skal repareres".

## `tradeTypes` (type: `array`):

"Til salg" (for sale), "Gives væk" (given away free) or "Ønsker at købe" (wanted).

## `brands` (type: `array`):

Brands as DBA lists them for the search ("HAY", "IKEA", "Apple", "Stokke" and about 1,700 more).

## `shippingOnly` (type: `boolean`):

Only ads sent with DBA's own shipping service ("Fiks færdig").

## `makes` (type: `array`):

"VW", "Toyota", "Tesla", "Yamaha", "Adria" and the other makes DBA lists for the vehicle type.

## `models` (type: `array`):

Cars only, with makes: models by DBA's name ("Golf", "Polo", "Model Y").

## `minYear` (type: `integer`):

Every vehicle type with a model year.

## `maxYear` (type: `integer`):

Every vehicle type with a model year.

## `minMileage` (type: `integer`):

In kilometres, as DBA counts it: cars, MC, mopeds, ATVs and motorhomes.

## `maxMileage` (type: `integer`):

In kilometres.

## `minPowerHp` (type: `integer`):

Cars, MC, mopeds, ATVs, motorhomes, trucks, buses, construction machinery, tractors and combine harvesters.

## `maxPowerHp` (type: `integer`):

As minPowerHp.

## `fuelTypes` (type: `array`):

"Benzin", "Diesel", "El", "Hybrid benzin", "Plug-in Benzin", "Gas (CNG)" and the other names DBA lists (cars, MC, mopeds, boats).

## `transmissions` (type: `array`):

Cars and motorhomes: "Automatisk" or "Manuelt".

## `bodyTypes` (type: `array`):

The body or type DBA lists for the vehicle type: "Stationcar", "SUV", "Sedan", "Hatchback 5-dørs", "CUV", "Kassevogn" (cars); "Adventure", "Touring" (MC); "Daycruiser", "RIB", "Sejlbåd/Motorsejler" (boat classes); "Campingvogn", "Teltvogn" (caravans); "Alkove", "Camper", "Helintegreret" (motorhomes); truck, bus, machine and farm tool types.

## `wheelDrives` (type: `array`):

Cars and motorhomes: "Firehjulstræk", "Forhjulstræk", "Baghjulstræk".

## `colours` (type: `array`):

Cars only: "Sort", "Hvid", "Grå", "Blå", "Sølv" and the other names DBA lists.

## `salesForms` (type: `array`):

Boats: "Brugt båd", "Ny båd" or "Til salg"; caravans and motorhomes: "Til salg".

## `equipment` (type: `array`):

Cars only: "Anhængertræk" (towbar), "Apple CarPlay", "Bakkamera", "Bluetooth", "Fartpilot", "AC/Klimaanlæg", "Coupé-opvarmer", "Motorvarmer", "Parkeringssensor, bag", "Læder- og semilæderinteriør", "Soltag/glastag". Several values: any of them.

## `wheelSets` (type: `array`):

Cars only: "Én hjulsæt" or "To eller flere hjulsæt".

## `warrantyTypes` (type: `array`):

Cars only: "Garanti" (DBA's warranty and insurance filter).

## `conditionDocuments` (type: `array`):

Cars only: "Service" (DBA's car condition filter: the car comes with its service history).

## `registrationClasses` (type: `array`):

Cars only: "Personbil", "Varebil ex. moms" (van, price without VAT) or "Varebil inkl. moms" (van, price with VAT).

## `vehicleConditions` (type: `array`):

MC: "Ny MC" or "Brugt MC"; caravans and motorhomes: "Ny" or "Brugt".

## `minEngineCc` (type: `integer`):

MC, mopeds and ATVs: DBA's engine size in cubic centimetres.

## `maxEngineCc` (type: `integer`):

As minEngineCc.

## `minLengthFeet` (type: `integer`):

Boats: DBA's length in feet.

## `maxLengthFeet` (type: `integer`):

Boats.

## `minLengthCm` (type: `integer`):

Caravans and motorhomes: DBA's length in centimetres.

## `maxLengthCm` (type: `integer`):

Caravans and motorhomes.

## `minWidthCm` (type: `integer`):

Boats and caravans: DBA's width in centimetres.

## `maxWidthCm` (type: `integer`):

Boats and caravans.

## `minWeightKg` (type: `integer`):

Caravans, motorhomes and trucks: DBA's weight filter in kilograms. Cars: DBA's car search has no weight filter, so every car's ad page is read and its weight judged there (each delivered car is billed Ad details too; a car whose page shows no weight is left out, free).

## `maxWeightKg` (type: `integer`):

Caravans, motorhomes and trucks; cars read from each ad page (billed Ad details), as Minimum weight.

## `minTrailerWeightKg` (type: `integer`):

Cars only: the largest trailer weight in kilograms.

## `maxTrailerWeightKg` (type: `integer`):

Cars only.

## `minBoatEngineHp` (type: `integer`):

Boats: the power of the boat's engine.

## `maxBoatEngineHp` (type: `integer`):

Boats.

## `minTopSpeedKnots` (type: `integer`):

Boats.

## `maxTopSpeedKnots` (type: `integer`):

Boats.

## `berths` (type: `array`):

Boats, caravans and motorhomes: DBA's groups of berths, such as "3 - 4".

## `seatGroups` (type: `array`):

Boats and motorhomes: DBA's seat groups, such as "4 - 6" (boats) or "4 - 5" (motorhomes).

## `boatEngineTypes` (type: `array`):

Boats: "Indenbords" (inboard), "Udenbords" (outboard) or "Andet".

## `boatEngineIncluded` (type: `array`):

Boats: DBA's engine included filter, by its labels ("Indenbords", "Nej").

## `boatMaterials` (type: `array`):

Boats: "Glasfiber", "Aluminium", "Plastik", "Træ", "Andet".

## `vehicleLocations` (type: `array`):

Boats and motorhomes: "Danmark" or "Udlandet" (abroad); caravans: "Danmark".

## `attributeFilters` (type: `object`):

Any other filter of the search's own DBA filter list, by DBA's name or Danish label, with values by label or value, or {"min": n, "max": n} for a range. For example {"truck_segment": \["Kassevogn"], "construction_segment": \["Minigraver"]}. A filter the search does not offer is refused with the filters it does offer.

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

Only ads published on or after this day in Denmark (YYYY-MM-DD), checked on every row.

## `postedWithinHours` (type: `integer`):

Only ads published within this many hours of the run's start, checked on every row.

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

Only ads published before this day in Denmark (YYYY-MM-DD), checked on every row. DBA lists newest first, so the newer ads in front are read and left out free; a day far back can stop the run on its allowance for unpaid reads.

## `includeKeywords` (type: `array`):

Words an ad must contain (its title, and its description when the ad page is read). Any one of them, or all with requireAllKeywords.

## `requireAllKeywords` (type: `boolean`):

With includeKeywords: every word must be in the ad.

## `excludeKeywords` (type: `array`):

Ads holding any of these words are left out, free.

## `titleOnly` (type: `boolean`):

includeKeywords and excludeKeywords look at the title only.

## `onlyKeywordMatches` (type: `boolean`):

Marketplace searches made from keywords (and pasted search links with words): deliver only the ads whose title carries every word of the search, or, when the ad page is read, its title or description. DBA's own search ends a keyword's results with ads that carry none of the words (on the last pages of a search most titles lack them, and a made up word still returns a few unrelated ads); those are left out, free, and counted on the coverage row. Words are matched as parts of words ("sofa" matches "hjørnesofa"); "a OR b" means either. Off: every ad DBA's search returns.

## `excludeAdIds` (type: `array`):

DBA ad ids (Annonce-ID) or ad links never to deliver.

## `searchUrls` (type: `array`):

Search pages copied from DBA's marketplace (https://www.dba.dk/recommerce/forsale/search?...) or its vehicles (https://www.dba.dk/mobility/search/<type>?...), read with all their filters. DBA's sort order in a link is not sent (DBA asks robots not to); the link is read in DBA's default order.

## `adUrls` (type: `array`):

DBA ad links (https://www.dba.dk/recommerce/forsale/item/<id>, https://www.dba.dk/mobility/item/<id> or https://www.dba.dk/<id>) or DBA ad ids (Annonce-ID): each read with its ad page and billed as one Listing or Vehicle plus one Ad details. A removed or unknown ad is a free row.

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

The most paid rows (marketplace ads and vehicles) the run delivers, across all searches and links.

## `maxItemsPerSearch` (type: `integer`):

The most paid rows from one search or search link.

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

The most result pages read for one search.

## `maxRowsPerSearch` (type: `integer`):

How many rows of each search are read at most, the rows left out by a filter included (no limit by default).

## `startPage` (type: `integer`):

Read every search from this page of DBA's own results (53 marketplace ads or 50 vehicles a page) instead of the first: to go on from where an earlier run stopped. Such a search is not split past DBA's 50 page reach and its coverage row says it is not complete. Given, even as 1, every search is read in DBA's own pages from that page, so runs of startPage 1, 2, 3 never overlap. Not with plates or vins.

## `includeDetails` (type: `boolean`):

Read each ad's page: the full description, every key fact and all images, the category path, the postal code, the edited time, a shop's profile (name, address, phone, CVR number, website), and on vehicles the equipment, registration date, inspection dates, owners, warranty, declared damages, the inspection report link and the dealer card (CVR number, address, phone, e-mail, website, opening hours, brands). Billed as one Ad details per row that carries its ad page; about a second per row.

## `includeSimilarVehicles` (type: `boolean`):

Vehicles: DBA's own list of similar vehicles for each ad (id, link, title, year and mileage text, price, image). Reads the ad page too (billed as Ad details). Billed as one Similar vehicles list per row that carries one; an ad DBA lists none for is empty and free.

## `includeMarketValuation` (type: `boolean`):

Vehicles: the asking prices of the same make and model on DBA today, one model year either side (count, median, quartiles, lowest and highest), and how far this vehicle's price stands from the median, in percent and kroner. One extra DBA search per vehicle; billed as one Market valuation per row that carries one. Fewer than 5 comparable ads, or a vehicle without make, model or model year: no valuation, free. Asking prices, not sale prices.

## `maxPriceVsMarketPercent` (type: `integer`):

With includeMarketValuation: deliver only vehicles whose asking price is at most this many percent above (positive) or below (negative) the median of their market valuation, such as -10 for at least 10 percent under the market. Vehicles left out, or with no valuation, are free; their valuation reads are the add-on's unpaid work.

## `maxPriceVsMarketDkk` (type: `integer`):

With includeMarketValuation: deliver only vehicles whose asking price is at most this many kroner above (positive) or below (negative) the median of their market valuation, such as -20000 for at least 20,000 kr. under the market. Vehicles left out, or with no valuation, are free.

## `minComparables` (type: `integer`):

With includeMarketValuation: the fewest comparable ads a valuation needs (5 to 50, 5 by default); a vehicle with fewer gets no valuation, free. Each valuation says its confidence too: high with 20 or more, medium with 10 to 19, low below.

## `excludeRedFlagged` (type: `boolean`):

Vehicles: leave out, free, every vehicle whose row carries a red flag (the seller's own answer of known damage, major repairs or a lien, or a mention in the title or description of export only, damage or a fault, a lease takeover, a driving ban, deregistration or a sale for parts). A mention is only a mention ("ingen skader" mentions damage too): read redFlags first.

## `includePersonalData` (type: `boolean`):

Deliver the fields that name or reach a private person: a private seller's plate and VIN (in their fields and in the key facts) and the inspection report link that carries the plate, DBA user id, street and exact map point (off: the point is rounded to 2 decimals, about 1 km, when DBA gives it to the address), the seller's own links and ad references, contact persons' names, phones and e-mails on any ad, and the contacts found in the texts of private ads. Off: those fields are empty; a company's or dealer's name, id, CVR number, address, phone, website and dealer card are business data and always delivered. Plate and VIN lookups work either way. You are responsible for a lawful use, GDPR included.

## `markPaidPlacements` (type: `boolean`):

Read the paid ad DBA shows above each marketplace and vehicle search's results (one small extra read per search, free) and flag each delivered row that is one (paidPlacement true or false); the search's coverage row names the paid ads and whether they stood among its results. A paid ad that is not among the results is not delivered (its own row cannot prove the search's filters). Ad links, plate or VIN lookups and dealer stocks say null.

## `priceSummary` (type: `boolean`):

Each search's coverage row carries the count, lowest, quartiles, median, mean and highest asking price of the ads it met, and the same per DBA area (region) and per category (marketplace) or make (vehicles). Free.

## `includeRawData` (type: `boolean`):

Add DBA's search row as served (a private seller's only with personal data on).

## `descriptionFormat` (type: `string`):

How the ad description is delivered.

## `descriptionMaxLength` (type: `integer`):

Cut descriptions to this many characters (descriptionCut marks the row).

## `outputFields` (type: `array`):

Keep only these row fields, by the names the rows carry ("adId", "url", "region", "make", "model", "mileageKm", "marketValuation"); the row's identity, title, price, place, status and image count, and the fields of every add-on that is billed, always stay. Not together with compactOutput.

## `compactOutput` (type: `boolean`):

Deliver only the most used fields (handy for AI agents).

## `excludeEmptyFields` (type: `boolean`):

Drop fields that are empty on a row.

## `extractContacts` (type: `boolean`):

Add the e-mail addresses, phone numbers, websites and social profiles written in the title and description (companies' ads always; private ads with includePersonalData on).

## `phoneExtractionMode` (type: `string`):

With extractContacts.

## `failIfIncomplete` (type: `boolean`):

End the run as failed when a search or link could not be read in full (the rows delivered stay).

## `maxFailedRequestsPercent` (type: `integer`):

End the run as failed when more of its reads failed.

## `completenessTolerancePercent` (type: `number`):

Your own bar for a complete search: a search counts as complete when it met at least DBA's count of ads less this percent (and less the number of ads below). Empty: the fixed rule (98 percent of DBA's count less 2 ads on a split search, 99 percent less 2 on one search).

## `completenessToleranceAbsolute` (type: `integer`):

Your own bar for a complete search, in ads: DBA's count less this many ads (and less the percent above). Empty: the fixed rule.

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

Leave as is: DBA is read through Apify's datacenter proxy, which every DBA door answers. Your own proxy links replace it.

## `requestsPerSecond` (type: `number`):

The pace of the run's one exit (0.2 to 2).

## `maxConcurrency` (type: `integer`):

At most this many requests in flight, inside the pace (DBA is never asked more than requestsPerSecond requests a second): ad pages and add-on pages are read on this many lanes.

## `maxRequestRetries` (type: `integer`):

Tries of a failed read after the first.

## Actor input object example

```json
{
  "verticals": [
    "marketplace"
  ],
  "keywords": [
    "sofa"
  ],
  "locations": [
    "København og omegn"
  ],
  "sellerType": "any",
  "postedToday": false,
  "shippingOnly": false,
  "requireAllKeywords": false,
  "titleOnly": false,
  "onlyKeywordMatches": true,
  "maxItems": 20,
  "includeDetails": false,
  "includeSimilarVehicles": false,
  "includeMarketValuation": false,
  "excludeRedFlagged": false,
  "includePersonalData": false,
  "markPaidPlacements": false,
  "priceSummary": true,
  "includeRawData": false,
  "descriptionFormat": "asServed",
  "compactOutput": false,
  "excludeEmptyFields": false,
  "extractContacts": false,
  "failIfIncomplete": false,
  "requestsPerSecond": 1,
  "maxConcurrency": 4,
  "maxRequestRetries": 2
}
```

# Actor output Schema

## `items` (type: `string`):

No description

## `report` (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 = {
    "verticals": [
        "marketplace"
    ],
    "keywords": [
        "sofa"
    ],
    "locations": [
        "København og omegn"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_craft/dba-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 = {
    "verticals": ["marketplace"],
    "keywords": ["sofa"],
    "locations": ["København og omegn"],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation_craft/dba-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 '{
  "verticals": [
    "marketplace"
  ],
  "keywords": [
    "sofa"
  ],
  "locations": [
    "København og omegn"
  ],
  "maxItems": 20
}' |
apify call automation_craft/dba-scraper --silent --output-dataset

```

## MCP server setup

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