# DBA Denmark Marketplace Listings Scraper (`automation-lab/dba-denmark-marketplace-listings-scraper`) Actor

Search public DBA.dk listings and export IDs, titles, prices, locations, seller context when exposed, images, and canonical URLs for inventory monitoring.

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

## Pricing

from $1.32 / 1,000 item extracteds

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 Denmark Marketplace Listings Scraper

Export public **DBA listings** from Denmark's classified marketplace as clean, structured records.
Search by keyword, pass a current DBA.dk search or category URL, or collect one public listing page.
The Actor saves stable listing IDs, titles, asking prices, locations, posting age, category and seller context when exposed, images, and canonical URLs.

Use it for recurring resale inventory checks, price research, sourcing, and spreadsheet or data-pipeline exports.
No DBA account, login cookie, or private API key is required.

### What does this DBA scraper do?

The Actor turns public DBA.dk result pages into one dataset row per listing.
It supports:

- keyword searches such as `iphone`, `sofa`, or `ladcykel`;
- public DBA.dk search and category URLs, including URLs carrying filters;
- individual public listing URLs;
- bounded pagination up to your `maxItems` limit;
- optional detail-page enrichment;
- stable-ID deduplication across several inputs;
- Apify schedules, webhooks, API clients, and dataset exports.

Search pages already provide the most useful monitoring fields.
Keep `includeDetails` disabled for the fastest and least expensive inventory collection.
Enable it when descriptions or additional detail-page fields matter to your workflow.

### Who is this Actor for?

#### Resale market analysts

Build repeatable snapshots of active Danish classified inventory and compare asking-price distributions.

#### Second-hand retailers and sourcing teams

Track a narrow product query, identify listing URLs, and review promising inventory in your downstream system.

#### Researchers and journalists

Export public listings into CSV, JSON, Excel, or a notebook without maintaining a DBA page parser.

#### Automation and data teams

Schedule a consistent query, use `listingId` as the business key, and compare successive datasets for new, changed, or missing listings.

### Why use this DBA listings extractor?

- **Typed output:** prices are available as both source text and numeric values.
- **Canonical identity:** every result includes the DBA listing ID and canonical URL.
- **Monitoring context:** each row carries its input source and observation timestamp.
- **Useful without detail crawling:** result cards expose titles, prices, locations, age, brands, and images.
- **Controlled collection:** page, item, timeout, and retry bounds prevent accidental open-ended runs.
- **Honest nulls:** fields that DBA does not expose are returned as `null`, not guessed.
- **Integration ready:** the default dataset works with Apify exports, webhooks, API clients, and MCP.

The Actor does not bypass login controls and does not collect private account data.

### What data can I extract from DBA.dk?

| Field | Type | Meaning |
| --- | --- | --- |
| `listingId` | string | Stable numeric DBA listing identifier |
| `title` | string | Public listing title |
| `price` | string or null | Asking price formatted as shown by DBA |
| `priceValue` | number or null | Numeric asking price for analysis |
| `currency` | string or null | Currency, normally `DKK` |
| `category` | string or null | Category when structured data exposes it |
| `location` | string or null | Public location shown on the result card |
| `postedAgo` | string or null | Source-provided relative posting age |
| `condition` | string or null | Structured product condition when exposed |
| `brand` | string or null | Brand or leading result attribute |
| `description` | string or null | Public structured summary or detail description |
| `sellerName` | string or null | Public seller name when exposed |
| `sellerType` | string or null | Public seller type when exposed |
| `imageUrl` | string or null | Primary image URL |
| `imageUrls` | string\[] | Public image URLs found for the listing |
| `isSponsored` | boolean | Whether DBA marked the card as paid placement |
| `url` | string | Canonical public listing URL |
| `sourceUrl` | string | Search, category, or listing input that produced the row |
| `scrapedAt` | string | ISO 8601 observation timestamp |

Seller and category fields are nullable because DBA does not expose them on every public page.

### How to scrape DBA listings

1. Open the Actor in Apify Console.
2. Add one or more terms under **Search queries**.
3. Alternatively, paste current public DBA.dk URLs under **DBA.dk URLs**.
4. Set **Maximum listings** to the number of unique rows you need.
5. Keep detail enrichment off for ordinary inventory and price monitoring.
6. Click **Start**.
7. Open the **Dataset** tab to inspect or export the results.
8. Save the input as a Task if you want to schedule the same search repeatedly.

A useful first input is:

```json
{
  "queries": ["iphone"],
  "maxItems": 20,
  "maxPagesPerSource": 2,
  "includeDetails": false
}
```

### Input parameters

#### `queries`

Array of text searches to run on public DBA.dk marketplace listings.
Whitespace-only entries are ignored.
Examples: `iphone`, `sofa`, `kamera`, and `ladcykel`.

#### `startUrls`

Array of public DBA.dk search, category, or listing URLs.
Use this route when you already configured filters on the DBA website.
URLs on other hosts are rejected instead of fetched.

#### `maxItems`

Maximum unique rows saved across all sources.
Allowed range: 1 to 10,000.
The Actor stops scheduling pages after reaching this limit.

#### `includeDetails`

When `true`, opens each accepted listing page for additional public fields.
A failed detail request does not erase valid search-card data.
Expect longer runs because this adds up to one request per result.

#### `maxPagesPerSource`

Maximum pages visited for each search or category input.
Allowed range: 1 to 100.
This is a safety bound; `maxItems` can stop collection earlier.

#### `requestTimeoutSecs`

Per-request timeout from 10 to 120 seconds.
Transient network failures receive at most two retries with backoff.

If both `queries` and `startUrls` are empty, the Actor runs the prefilled `iphone` search.

### Output example

The default dataset contains objects like this real search result:

```json
{
  "listingId": "24983944",
  "title": "Apple iPhone 8 64 GB guld",
  "price": "300 kr.",
  "priceValue": 300,
  "currency": "DKK",
  "category": null,
  "location": "Tølløse",
  "postedAgo": "37 min.",
  "condition": "Used",
  "brand": "Apple",
  "description": "Apple iPhone 8 64 GB guld",
  "sellerName": null,
  "sellerType": null,
  "imageUrl": "https://images.dbastatic.dk/dynamic/default/item/24983944/1b0f47c7-9af4-4e31-acd2-fa50987537fc",
  "imageUrls": [
    "https://images.dbastatic.dk/dynamic/default/item/24983944/1b0f47c7-9af4-4e31-acd2-fa50987537fc"
  ],
  "isSponsored": false,
  "url": "https://www.dba.dk/recommerce/forsale/item/24983944",
  "sourceUrl": "https://www.dba.dk/recommerce/forsale/search?q=iphone",
  "scrapedAt": "2026-09-16T20:08:33.756Z"
}
```

Values change as sellers create, edit, promote, and remove listings.
Treat the example as a schema illustration, not current inventory.

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

The Actor uses pay-per-event pricing:

- one **Start** event per run;
- one **Listing** event for each useful dataset row.

You are not charged an item event for malformed, duplicate, empty, or failed records.
The start fee is **$0.005 per run**. Listing prices use these spend tiers:

| Apify tier | Price per listing |
| --- | ---: |
| FREE | $0.00253 |
| BRONZE | $0.00220 |
| SILVER | $0.001716 |
| GOLD | $0.00132 |
| PLATINUM | $0.00132 |
| DIAMOND | $0.00132 |

For a FREE-tier user, a 10-listing run costs about **$0.0303**, a 100-listing run about **$0.258**, and a 1,000-listing run about **$2.535**, including one start event.
Higher Apify spend tiers reduce the per-listing price automatically.
These are event-price estimates; Apify billing can also reflect refunds, fraud, disputes, taxes, corrections, or clawbacks.

Use a small `maxItems` value while validating a new query.
For recurring monitoring, one focused scheduled Task is usually easier to compare than many overlapping queries.

### Monitoring new and changed DBA inventory

The Actor produces observations, not a permanent historical database.
To monitor changes:

1. Save a Task with a stable query or filtered URL.
2. Run it on an Apify schedule.
3. Export or deliver each dataset through a webhook.
4. Key records by `listingId`.
5. Compare `priceValue`, title, location, and presence with the previous snapshot.
6. Use `scrapedAt` as the observation time.

A new ID means a newly observed listing.
A known ID with a changed price indicates an updated asking price.
An absent ID can mean sale, removal, expiration, or movement beyond your page/item limits.

### Export DBA listings to spreadsheets and data pipelines

Every run writes to the default Apify dataset.
From the Dataset tab you can export JSON, CSV, Excel, XML, or RSS.

Common workflows include:

- send a CSV to a pricing analyst;
- append rows to Google Sheets through an automation platform;
- load JSON into BigQuery, Snowflake, or a warehouse;
- trigger a webhook after each scheduled run;
- join listing IDs with your own product taxonomy;
- create a dashboard of asking-price ranges by location.

Do not use `title` alone as a key.
Use `listingId`, and keep `sourceUrl` when combining several query runs.

### Run through the Apify API

Replace `APIFY_TOKEN` with your token.
Never expose a production token in client-side code or public repositories.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~dba-denmark-marketplace-listings-scraper/runs?token=APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"queries":["sofa"],"maxItems":25,"maxPagesPerSource":2}'
```

To wait and retrieve dataset items:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~dba-denmark-marketplace-listings-scraper/run-sync-get-dataset-items?token=APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"queries":["ladcykel"],"maxItems":15}'
```

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/dba-denmark-marketplace-listings-scraper').call({
    queries: ['kamera'],
    maxItems: 50,
    maxPagesPerSource: 3,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient
import os

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/dba-denmark-marketplace-listings-scraper').call(
    run_input={
        'queries': ['iphone'],
        'maxItems': 20,
        'maxPagesPerSource': 2,
    }
)
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use with MCP and AI agents

Add this Actor to Claude Code through Apify MCP:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/dba-denmark-marketplace-listings-scraper"
```

#### Claude Desktop, Cursor, and VS Code

Claude Desktop, Cursor, and VS Code clients can use this MCP server configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/dba-denmark-marketplace-listings-scraper"
    }
  }
}
```

Example prompts:

- “Search public DBA listings for `ladcykel` and return 20 rows sorted by numeric asking price.”
- “Collect this DBA search URL and summarize inventory counts by location.”
- “Run my saved DBA monitoring Task and identify IDs whose asking price changed from yesterday's dataset.”

An AI-generated comparison is only as complete as the configured item and page limits.

### Reliability, retries, and limitations

DBA.dk can change its HTML, structured data, result order, and public field availability.
The Actor validates that responses are recognizable HTML and fails clearly when the first page contains no recognizable listings.

Important limits:

- it collects public pages only;
- it does not log in or access favorites, messages, or private seller data;
- search order can include sponsored placements;
- relative posting age is source text, not an inferred absolute date;
- seller, category, and condition fields can be `null`;
- detail enrichment is slower than search-card mode;
- a listing disappearing from one bounded snapshot is not proof that it sold;
- the Actor does not provide alerts or snapshot comparison by itself.

The direct HTTP route avoids unnecessary browser overhead and does not silently activate paid residential proxy traffic.

### Troubleshooting

#### The run reports no recognizable listings

Open the input URL in a browser and confirm it is a current public DBA.dk search, category, or listing page.
Try a broader keyword, remove stale filters, and ensure the URL host is `dba.dk`.

#### I received fewer rows than expected

Increase `maxItems` and, when relevant, `maxPagesPerSource`.
DBA can return duplicates across sponsored and organic positions; the Actor saves each listing ID once.

#### Some seller or category values are null

DBA does not expose every field on every result or detail page.
Enable `includeDetails` for best-effort enrichment, but do not expect fields that are absent from the public page.

#### A detail request failed but the run succeeded

This is intentional graceful degradation.
The Actor retains valid search-card fields rather than discarding the listing.
Review logs if detail-only fields are essential to your workflow.

#### Can I pass a non-DBA URL?

No.
The Actor rejects other domains to prevent accidental or misleading collection.

### Responsible use and legality

Use this Actor only for lawful purposes and public information you are entitled to process.
Review DBA.dk's terms, robots guidance, database rights, applicable privacy law, and your own legal basis before collecting or redistributing data.

Minimize the amount and frequency of collection.
Do not use public seller context for harassment, discrimination, spam, or identity enrichment.
Do not attempt to contact sellers automatically unless your use complies with platform rules and applicable law.

You are responsible for retention, access controls, downstream decisions, and deletion obligations.
This documentation is product guidance, not legal advice.
DBA.dk is a third-party source; this Actor is not affiliated with, endorsed by, or operated by DBA.dk.

### FAQ

#### Does it require a DBA account?

No. It processes public marketplace pages without login credentials.

#### Does it support search terms and URLs?

Yes. Use `queries` for keyword discovery or `startUrls` for current public search, category, and listing URLs.

#### Can it monitor price changes?

It produces stable IDs, numeric prices, source URLs, and observation timestamps suitable for comparison.
Store and compare successive run datasets in your own workflow.

#### Does it scrape cars?

General public DBA marketplace results may include items returned by your input, but this Actor does not promise a specialized vehicle schema.
Use search URLs and inspect the resulting fields for your exact category.

#### Are images downloaded?

No. Output contains public image URLs, which avoids unnecessary media transfer.

#### How are duplicates handled?

Rows are deduplicated by stable DBA listing ID across pages and all supplied inputs in one run.

### Related Actors

Explore other public marketplace and classified-data Actors from `automation-lab` when your project genuinely needs another source.
Each source has its own schema and usage rules, so do not combine records without source-specific normalization.

For this Actor, the canonical listing URL and `sourceUrl` preserve DBA provenance in downstream datasets.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/dba-denmark-marketplace-listings-scraper/changelog.md

# Actor input Schema

## `queries` (type: `array`):

Danish marketplace keywords to search on DBA.dk, such as iPhone, sofa, cykel, or kamera.

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

Optional public dba.dk search, category, or individual listing URLs. URLs on other domains are rejected.

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

Maximum unique listing records saved across all queries, URLs, and pages.

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

Visit each listing to enrich fields when DBA exposes them. Search-card data is retained if one detail request fails. This mode is slower.

## `maxPagesPerSource` (type: `integer`):

Safety limit for pagination of each search or category URL. Collection also stops as soon as maxItems is reached.

## `requestTimeoutSecs` (type: `integer`):

Timeout for each DBA.dk page request. Transient failures receive up to two bounded retries.

## Actor input object example

```json
{
  "queries": [
    "iphone"
  ],
  "startUrls": [
    {
      "url": "https://www.dba.dk/recommerce/forsale/search?q=iphone"
    }
  ],
  "maxItems": 20,
  "includeDetails": false,
  "maxPagesPerSource": 5,
  "requestTimeoutSecs": 20
}
```

# Actor output Schema

## `overview` (type: `string`):

Open the default dataset using the listing overview view.

# 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 = {
    "queries": [
        "iphone"
    ],
    "startUrls": [
        {
            "url": "https://www.dba.dk/recommerce/forsale/search?q=iphone"
        }
    ],
    "maxItems": 20,
    "includeDetails": false,
    "maxPagesPerSource": 5,
    "requestTimeoutSecs": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/dba-denmark-marketplace-listings-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 = {
    "queries": ["iphone"],
    "startUrls": [{ "url": "https://www.dba.dk/recommerce/forsale/search?q=iphone" }],
    "maxItems": 20,
    "includeDetails": False,
    "maxPagesPerSource": 5,
    "requestTimeoutSecs": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/dba-denmark-marketplace-listings-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 '{
  "queries": [
    "iphone"
  ],
  "startUrls": [
    {
      "url": "https://www.dba.dk/recommerce/forsale/search?q=iphone"
    }
  ],
  "maxItems": 20,
  "includeDetails": false,
  "maxPagesPerSource": 5,
  "requestTimeoutSecs": 20
}' |
apify call automation-lab/dba-denmark-marketplace-listings-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/dba-denmark-marketplace-listings-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/X0oZ3VKlMItwMMP7e/builds/RdF1wI3UdHMHCYzCl/openapi.json
