# Bilbasen Scraper — Denmark's Car Marketplace (`blackfalcondata/bilbasen-scraper`) Actor

Scrape bilbasen.dk — Denmark's largest car marketplace with full vehicle specs · seller contacts · gallery images · price-direction monitoring. Filter by make & model. Incremental mode tracks new and changed listings across scheduled runs.

- **URL**: https://apify.com/blackfalcondata/bilbasen-scraper.md
- **Developed by:** [Black Falcon Data](https://apify.com/blackfalcondata) (community)
- **Categories:** E-commerce, Lead generation, Automation
- **Features:** Limited permissions
- **Stats:** 62 total users, 12 monthly users, 98.2% runs succeeded, 4 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $2.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

### What does Bilbasen Scraper do?

Bilbasen Scraper extracts structured listing data from [bilbasen.dk](https://bilbasen.dk) — including contact details, full descriptions, prices, and location data. It supports controllable result limits, so you can run the same query consistently over time. The actor also offers detail enrichment (full descriptions and contact information) where the source provides them.

**New to Apify?** [Sign up free](https://console.apify.com/sign-up?fpr=1h3gvi) and use the included $5 monthly platform credit to test this actor.

### Key features

- **🔔 Notifications:** telegram / Slack / Discord / WhatsApp / webhook alerts on each run. Combine with incremental to ping only when prices or inventory actually move.
- **🔗 Paste-mode:** paste any bilbasen.dk URL — single-listing pages, search-results, or category SEO URLs. Build the filter you want in the browser, copy, paste; the actor parses every query param.
- **💵 Structured pricing:** listing price parsed into a numeric `price` field plus filter inputs (`priceFrom` / `priceTo`) so you can target a budget band. Use `priceType` (where supported) to exclude leasing or wholesale listings.
- **♻️ Incremental mode:** daily runs emit only listings that are new or whose price/condition changed since last run. Perfect for inventory-diff dashboards and competitive pricing alerts. Saves 80–95% on recurring monitoring.
- **📋 Detail enrichment:** two-stage scraping — search-card data first, then a per-listing detail page fetch with full description, gallery images, equipment list, and seller contact info. Toggle with `includeDetailPages`.
- **🧠 Danish NLP enrichment:** `enrichFromDescription: true` parses free-text Danish descriptions for service history, damage flags + severity, warranty status + expiry, registration number, and coarse region. Adds `serviceStatus`, `damageFlag`, `damageSeverity`, `warrantyStatus`, `warrantyExpiry`, `registrationNumber`, and `coarseRegion` fields.
- **🖼️ Image-output control:** `imagesMode: "first3" | "all"` controls how many image URLs are embedded per listing. Always reports `imagesCount` regardless of mode — pick `first3` for fast previews, `all` for complete galleries.
- **📦 Compact mode:** light payload with core fields only — comparable rows across listings without HTML or metadata overhead. Perfect for pricing dashboards.
- **✂️ Description truncation:** cap description length with `descriptionMaxLength` to control LLM prompt cost and dataset size — set 0 for full descriptions, or any char-limit to trim.
- **🔌 MCP connectors:** export your results into Notion via Apify's MCP connectors — a clean run-summary page, no glue code. Opt-in via the App connector field; deterministic field-mapping, no AI. Built on Apify's connector framework, so more destinations open up as their catalog grows.

### What data can you extract from bilbasen.dk?

Each result includes Core listing fields (`url`, `portalUrl`, `title`, `price`, `priceAmount`, `priceText`, `priceType`, and `priceBeforeReduction`, and more), detail fields when enrichment is enabled (`description`, `descriptionHtml`, `descriptionMarkdown`, `priceDescription`, and `dealerDescription`), and contact information (`sellerPhone`, `contactEmail`, and `sellerHasEmail`). In standard mode, all fields are always present — unavailable data points are returned as `null`, never omitted. In compact mode, only core fields are returned.

Enable detail enrichment in the input to get richer fields such as full descriptions and contact information where the source provides them.

### Input

The main inputs are a result limit. Additional filters and options are available in the input schema.

Key parameters:

- **`startUrls`** — Bilbasen URLs to scrape. Supports both search pages (/brugt/bil/audi/a4) and single listings (/brugt/bil/vw/golf/variant/123456). Leave empty to use the filter params below.
- **`make`** — Car make to search for (e.g. "Audi", "BMW", "Toyota"). Used to build search URL when no startUrls provided.
- **`model`** — Car model to search for (e.g. "A4", "3-serien", "Yaris"). Family names such as "Golf", "C-Klasse" or "Transit" are also accepted and matched to all model lines. Requires make to be set.
- **`yearFrom`** — Minimum model year (e.g. 2018)
- **`yearTo`** — Maximum model year (e.g. 2024)
- **`priceFrom`** — Minimum price in DKK (e.g. 50000)
- **`priceTo`** — Maximum price in DKK (e.g. 300000)
- **`priceType`** — Filter by listing price type. Leave empty to include all types (Retail, engros, leasing). Set to "Retail" to show only standard retail listings.
- **`mileageFrom`** — Minimum odometer reading in km.
- **`mileageTo`** — Maximum odometer reading in km.
- **`fuelType`** — Fuel/drivetrain filter. Leave empty to include all.
- **`gearType`** — Transmission filter.
- ...and 38 more parameters

### Input examples

**Basic search** — Fetch vehicles from the provided start URL.

→ Full payload per result — all standard fields populated where the source provides them.

```json
{
  "startUrls": [
    {
      "url": "https://www.bilbasen.dk/brugt/bil"
    }
  ],
  "maxResults": 50
}
```

**Incremental tracking** — Only emit vehicles that changed since the previous run with this `stateKey`.

→ First run builds the baseline state. Subsequent runs emit only records that are new or whose tracked content changed. Set `emitUnchanged: true` to include unchanged records as well.

```json
{
  "startUrls": [
    {
      "url": "https://www.bilbasen.dk/brugt/bil"
    }
  ],
  "maxResults": 200,
  "incrementalMode": true,
  "stateKey": "bilbasen-tracker"
}
```

**Compact output for AI agents** — Return only core fields for AI-agent and MCP workflows.

→ Small payload with the most important fields — ideal for piping into LLMs without token overhead.

```json
{
  "startUrls": [
    {
      "url": "https://www.bilbasen.dk/brugt/bil"
    }
  ],
  "maxResults": 50,
  "compact": true
}
```

### Output

Each run produces a dataset of structured listing records. Results can be downloaded as JSON, CSV, or Excel from the Dataset tab in Apify Console.

### Example listing record

```json
{
  "url": "https://www.bilbasen.dk/brugt/bil/audi/e-tron/55-black-edition-s-line-quattro-5d/6286479",
  "portalUrl": "https://www.bilbasen.dk/brugt/bil/audi/e-tron/55-black-edition-s-line-quattro-5d/6286479",
  "title": "Audi e-tron 55 Black Edition S-line quattro 5d",
  "price": 439900,
  "priceAmount": 439900,
  "priceText": "439.900 kr.",
  "priceType": "Retail",
  "priceBeforeReduction": 449900,
  "make": "Audi",
  "model": "e-tron",
  "variant": "55 Black Edition S-line quattro 5d",
  "year": 2022,
  "mileage": 33000,
  "fuelType": "El",
  "color": "Sortmetal",
  "doors": 5,
  "bodyType": "SUV",
  "horsepower": "408 hk/664 nm",
  "horsepowerHp": 408,
  "torqueNm": 664,
  "yearlyTax": "920 kr. / år",
  "firstRegistrationDate": "2022-06",
  "registrationDate": "2022-06",
  "description": "Audi E-tron 55 - Black Edition !!, \n\nEkstra:\n✅ 21\" Fælge Audi Sport 5-V-eget stjernedesign, \n✅ B&O Premium Sound System med 3D lyd,\n✅ S line interiør,\n✅ Dekorindlæg Carbon struktur,\n✅ Head-up display,...",
  "descriptionMarkdown": "Audi E-tron 55 - Black Edition !!, \n\nEkstra:\n✅ 21\" Fælge Audi Sport 5-V-eget stjernedesign, \n✅ B&O Premium Sound System med 3D lyd,\n✅ S line interiør,\n✅ Dekorindlæg Carbon struktur,\n✅ Head-up display,...",
  "contentHash": "3d70eeed57879110",
  "features": [
    "21\" Fælge Audi Sport 5-V-eget stjernedesign,",
    "B&O Premium Sound System med 3D lyd,",
    "S line interiør,",
    "Dekorindlæg Carbon struktur,",
    "Head-up display,",
    "... 35 more items"
  ],
  "location": "6800 Varde",
  "locationCity": "Varde",
  "locationZipCode": 6800,
  "dealer": "Michaels Automobiler ApS",
  "sellerName": "Michaels Automobiler ApS",
  "sellerType": "Dealer",
  "sellerAddress": "Jeppe Skovgaards Vej 2, 6800 Varde",
  "sellerCity": "Varde",
  "sellerZipCode": 6800,
  "sellerPhone": "76950059",
  "externalId": "6286479",
  "images": [
    "https://billeder.bilbasen.dk/bilinfo/1df35dd4-f0d1-4bb2-a4c4-889ba66c77bc.jpeg?class=S300X300",
    "https://billeder.bilbasen.dk/bilinfo/061cddb2-88eb-467d-98da-3dfd4d5e2cde.jpeg?class=S300X300",
    "https://billeder.bilbasen.dk/bilinfo/b2b623d7-f66a-43bd-bca3-85397044fc00.jpeg?class=S300X300"
  ],
  "imagesCount": 22,
  "scrapedAt": "2026-06-20T20:18:09.589Z",
  "dataCompleteness": "detail",
  "drivingRangeKm": 405,
  "batteryCapacityKwh": 86.5,
  "energyConsumption": "240 Wh/km",
  "accelerationSec": 5.7,
  "topSpeedKmh": 200,
  "towWeight": "1.800 kg",
  "vehicleCategory": "Personbil",
  "vehicleTypeClass": "SUV",
  "cargoLiters": 660,
  "weightKg": 2565,
  "widthCm": 194,
  "lengthCm": 490,
  "heightCm": 163,
  "payloadKg": 565,
  "maxTowWeightBrakedKg": 1800,
  "drivetrain": "Firehjulstræk",
  "hasAbs": true,
  "hasEsp": true,
  "airbagsNote": "6",
  "ratingAverage": 4.644153225806451,
  "ratingCount": 231,
  "subRatings": [
    {
      "name": "Køreegenskaber",
      "rating": 4.866935483870968
    },
    {
      "name": "Driftsomkostninger",
      "rating": 4.278225806451613
    },
    {
      "name": "Sikkerhed",
      "rating": 4.911290322580645
    },
    {
      "name": "Værdi for pengene",
      "rating": 4.520161290322581
    }
  ],
  "syiId": "0015ec32-307a-4b20-9325-714f03e00cf1",
  "tenant": "bilinfo",
  "dealerId": 5477,
  "dealerWebsite": "https://www.michaels-automobiler.dk/?utm_source=bilbasen&utm_medium=referral",
  "dealerCvr": "26988136",
  "dealerInventoryCount": 139,
  "dealerInventoryUrl": "https://www.bilbasen.dk/find-en-forhandler/bilforhandler--id5477",
  "dealerOpeningHours": [
    {
      "day": "Mandag - Fredag",
      "hours": "9:00 - 17:00"
    },
    {
      "day": "Lørdag",
      "hours": "Efter aftale"
    },
    {
      "day": "Søndag",
      "hours": "11:00 - 15:00"
    }
  ],
  "dealerSellingPoints": [
    "FRAGUS Gosafe",
    "Lade løsninger",
    "Finansiering",
    "Flexleasing "
  ],
  "dealerDescription": "Michaels Automobiler er et firma, der handler med nyere biler i topkvalitet i alle størrelser og med speciale i VW, Skoda, Audi og Mercedes. Mere end 25års erfaring og altid mere end 200 biler på lage...",
  "sellerHasEmail": true,
  "financingMonthlyPrice": 4683,
  "financingProvider": "AL Finans Lån",
  "financingDownPayment": 88420,
  "financingApr": 6.43,
  "financingPeriodMonths": 96,
  "financingTotalCost": 537902
}
```

### Incremental fields

When `incrementalMode: true`, each record also carries:

- `changeType` — one of `NEW`, `UPDATED`, `UNCHANGED` (deprecated skeleton mode, see below), or `EXPIRED`.

#### Sold-detection via EXPIRED rows (opt-in)

Set `emitExpired: true` and a tracked listing that has been missing from **2 consecutive fully-covered runs** is exported once as a minimal `changeType: "EXPIRED"` row (`url`, `portalUrl`, `externalId`, `contentHash`, `scrapedAt`; other fields null) — your signal that the car is sold or delisted. EXPIRED rows are billed as standard results, which is why this is off by default.

Expiry only fires when the run's scope provably covers the full search: clean make/model searches or browse-all. Filtered searches (year, price, mileage, etc.), multi-search runs, and partial crawls never expire listings — a listing absent because your filter excluded it will not be falsely reported as sold.

#### Unchanged skeletons (deprecated)

`pushUnchangedSkeletons: true` additionally pushes a minimal `changeType: "UNCHANGED"` skeleton row for every listing that hasn't changed since the previous run. This mode is **deprecated** — prefer EXPIRED-based sold-detection above, which achieves the same goal without re-exporting the full inventory every run. Note that every exported dataset row is billed as a result, including unchanged skeleton rows, so on stable inventories skeleton runs cost nearly as much per row as regular runs.

### How to scrape bilbasen.dk

1. Go to [Bilbasen Scraper](https://apify.com/blackfalcondata/bilbasen-scraper?fpr=1h3gvi) in Apify Console.
2. Configure the input.
3. Set `maxResults` to control how many results you need.
4. Enable `includeDetails` if you need full descriptions, contact info, equipment and emissions data.
5. Click **Start** and wait for the run to finish.
6. Export the dataset as JSON, CSV, or Excel.

### Use cases

- Extract listing data from bilbasen.dk for market research and competitive analysis.
- Track pricing trends across regions and categories over time.
- Monitor new and changed vehicles on scheduled runs without processing the full dataset every time.
- Use structured location data for regional analysis, mapping, and geo-targeting.
- Feed structured data into AI agents, MCP tools, and automated pipelines using compact mode.
- Export clean, structured data to dashboards, spreadsheets, or data warehouses.
- Benchmark seller / dealer reputation using rating fields.

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

Bilbasen Scraper uses [pay-per-event](https://docs.apify.com/platform/actors/paid-actors/pay-per-event) pricing. You pay a small fee when the run starts and then for each result that is actually produced.

- **Run start:** $0.01 per run
- **Per result:** $0.002 per listing record

Example costs:

- 10 results: **$0.03**
- 25 results: **$0.06**
- 100 results: **$0.21**
- 200 results: **$0.41**
- 500 results: **$1.01**

#### Example: recurring monitoring savings

These examples compare full re-scrapes with incremental runs at different churn rates. Churn is the share of vehicles that are new or whose tracked content changed since the previous run. Actual churn depends on your query breadth, source activity, and polling frequency — the scenarios below are examples, not predictions.

Example setup: 250 vehicles per run, daily polling (30 runs/month). Costs scale linearly with the number of vehicles.

| Churn rate | Full re-scrape run cost | Incremental run cost | Savings vs full re-scrape | Monthly cost after baseline |
|---|---:|---:|---:|---:|
| 5% — stable niche query | $0.51 | $0.04 | $0.47 (93%) | $1.05 |
| 15% — moderate broad query | $0.51 | $0.08 | $0.43 (83%) | $2.55 |
| 30% — high-volume aggregator | $0.51 | $0.16 | $0.35 (69%) | $4.80 |

Full re-scrape monthly cost at the same cadence: $15.30. First month with incremental costs $1.53 / $2.97 / $5.15 for the 5% / 15% / 30% scenarios because the first run builds baseline state at full cost before incremental savings apply.

Platform usage is included in the per-result fee shown above.

### FAQ

#### How many results can I get from bilbasen.dk?

The number of results depends on the search query and available vehicles on bilbasen.dk. Use the `maxResults` parameter to control how many results are returned per run.

#### Does Bilbasen Scraper support recurring monitoring?

Yes. Enable incremental mode to only receive new or changed vehicles on subsequent runs. This is ideal for scheduled monitoring where you want to track changes over time without re-processing the full dataset.

#### Can I integrate Bilbasen Scraper with other apps?

Yes. Bilbasen Scraper works with Apify's [integrations](https://apify.com/integrations?fpr=1h3gvi) to connect with tools like Zapier, Make, Google Sheets, Slack, and more. You can also use webhooks to trigger actions when a run completes.

#### Can I use Bilbasen Scraper with the Apify API?

Yes. You can start runs, manage inputs, and retrieve results programmatically through the [Apify API](https://docs.apify.com/api/v2). Client libraries are available for JavaScript, Python, and other languages.

#### Can I use Bilbasen Scraper through an MCP Server?

Yes. Apify provides an [MCP Server](https://apify.com/apify/actors-mcp-server?fpr=1h3gvi) that lets AI assistants and agents call this actor directly. Use compact mode, `descriptionMaxLength`, a single `descriptionFormat`, and `excludeEmptyFields` to keep payloads manageable for LLM context windows.

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

This actor extracts publicly available data from bilbasen.dk. Web scraping of public information is generally considered legal, but you should always review the target site's terms of service and ensure your use case complies with applicable laws and regulations, including GDPR where relevant.

#### Your feedback

If you have questions, need a feature, or found a bug, please [open an issue](https://apify.com/blackfalcondata/bilbasen-scraper/issues?fpr=1h3gvi) on the actor's page in Apify Console. Your feedback helps us improve.

### You might also like

- [🚗 mobile.de \[$0.59/1K💰\] Fast Scraper · Finance · Dealer GPS](https://apify.com/blackfalcondata/mobile-de-scraper?fpr=1h3gvi) — Scrape mobile.de — Germany's largest car marketplace (1.4M+ listings) at $0.6 / 1,000 results. Get.
- [AutoScout24 Scraper \[Just 💰$0.49\] — 930K Cars, 9 Countries](https://apify.com/blackfalcondata/autoscout24-scraper?fpr=1h3gvi) — 💰 $0.49 per 1,000 cars, platform usage included. Scrape autoscout24.com — Europe's largest.
- [Autotrader AU \[$0.9💰\] Car & Caravan Scraper 🇦🇺](https://apify.com/blackfalcondata/autotrader-au-scraper?fpr=1h3gvi) — Scrape autotrader.com.au car & caravan listings — advertised + previous price with a computed.
- [AutoTrader Canada — used car listings](https://apify.com/blackfalcondata/autotrader-ca-scraper?fpr=1h3gvi) — Scrape autotrader.ca — filter by make model year & price · full vehicle specs with listing photos ·.
- [Autotrader UK \[$0.75💰/1K\] - Car Scraper, Full Detail](https://apify.com/blackfalcondata/autotrader-uk-scraper?fpr=1h3gvi) — Scrape UK car listings from Auto Trader by make, model, price, year, mileage, fuel, and body type..
- [Blocket Scraper — Sweden's Largest Marketplace](https://apify.com/blackfalcondata/blocket-scraper?fpr=1h3gvi) — 💰 $2 per 1,000 listings. Scrape blocket.se — Sweden's largest classifieds and car marketplace..
- [Coches.net Scraper \[Just 💰$3\] — Used Cars in Spain](https://apify.com/blackfalcondata/coches-scraper?fpr=1h3gvi) — 💰 $3 per 1,000 listings. Scrape coches.net — Spain's largest vehicle marketplace for cars · vans ·.
- [DBA \[Just 💰$2\] — Denmark's Largest Marketplace](https://apify.com/blackfalcondata/dba-listings-scraper?fpr=1h3gvi) — 💰 $2 per 1,000 listings. Scrape dba.dk — Denmark's largest classifieds platform covering.

### Getting started with Apify

New to Apify? [Create a free account with $5 credit](https://console.apify.com/sign-up?fpr=1h3gvi) — no credit card required.

1. Sign up — $5 platform credit included
2. Open this actor and configure your input
3. Click **Start** — export results as JSON, CSV, or Excel

Need more later? [See Apify pricing](https://apify.com/pricing?fpr=1h3gvi).

### Disclaimer

This actor accesses only publicly available data on bilbasen.dk. You are responsible for how you use the extracted data — in particular any personal information such as names, phone numbers, or email addresses — and for complying with Bilbasen's terms of use, applicable data-protection law (including the GDPR where it applies), and the anti-spam rules of your jurisdiction.

This actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Bilbasen or any of its subsidiaries. All trademarks mentioned are the property of their respective owners.

### Search keywords

bilbasen scraper, bilbasen api, apify bilbasen, bilbasen data extraction, bilbasen.dk scraper, bilbasen.dk data, bilbasen.dk api, car listings scraper, vehicle data extraction, used car data, denmark cars scraper, bilbasen.dk listings, danish car marketplace, used cars denmark, biler til salg, car listings denmark.

# Changelog

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

# Actor input Schema

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

Bilbasen URLs to scrape. Supports both search pages (/brugt/bil/audi/a4) and single listings (/brugt/bil/vw/golf/variant/123456). Leave empty to use the filter params below.

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

Car make to search for (e.g. "Audi", "BMW", "Toyota"). Used to build search URL when no startUrls provided.

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

Car model to search for (e.g. "A4", "3-serien", "Yaris"). Family names such as "Golf", "C-Klasse" or "Transit" are also accepted and matched to all model lines. Requires make to be set.

## `yearFrom` (type: `integer`):

Minimum model year (e.g. 2018)

## `yearTo` (type: `integer`):

Maximum model year (e.g. 2024)

## `priceFrom` (type: `integer`):

Minimum price in DKK (e.g. 50000)

## `priceTo` (type: `integer`):

Maximum price in DKK (e.g. 300000)

## `priceType` (type: `string`):

Filter by listing price type. Leave empty to include all types (Retail, engros, leasing). Set to "Retail" to show only standard retail listings.

## `mileageFrom` (type: `integer`):

Minimum odometer reading in km.

## `mileageTo` (type: `integer`):

Maximum odometer reading in km.

## `fuelType` (type: `string`):

Fuel/drivetrain filter. Leave empty to include all.

## `gearType` (type: `string`):

Transmission filter.

## `bodyType` (type: `string`):

Body style filter (Sedan, SUV, Hatchback, Stationcar, MPV, Coupé, Cabriolet).

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

Dealer vs. private seller filter.

## `zipCode` (type: `integer`):

Danish postal code for geo-limited search (used with radiusKm). Results are filtered to listings within the given radius of this zip code area.

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

Search radius in km around zipCode. Listings are filtered to those within this distance (by postal-code area centroid).

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

Sort order for search results.

## `includeEngrosCvr` (type: `boolean`):

Include wholesale listings from CVR-registered dealers. Note for incremental users: toggling this between runs on the same incremental state changes the visible listing pool, which can cause wholesale-only listings to be reported as EXPIRED — use a separate stateKey per setting.

## `strictModelFilter` (type: `boolean`):

When searching for a specific model (e.g. Tesla Model S), filter out listings for other models that Bilbasen may include in results. Enabled by default.

## `maxResults` (type: `integer`):

Maximum number of results to scrape (0 = unlimited). This is the primary cost control — Apify charges per emitted record. Set this conservatively on your first run.

## `includeDetailPages` (type: `boolean`):

Fetch full detail for each listing (description, seller info, all specs). Disable for faster list-only scraping. Note: detail fetch may still run for listings where core fields (make, model) are missing from the search-result data, so the output remains usable.

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

Truncate description text to this many characters. Useful for reducing output size. Leave empty for full description.

## `compact` (type: `boolean`):

Return only 10 core fields (url, title, make, model, year, price, mileage, fuelType, sellerName, scrapedAt). Ideal for AI agents and MCP workflows.

## `enrichFromDescription` (type: `boolean`):

Parse seller description for service history, damage flags, warranty status, and registration number. Adds serviceStatus, damageFlag, damageSeverity, warrantyStatus, warrantyExpiry, registrationNumber, and coarseRegion fields.

## `imagesMode` (type: `string`):

How many image URLs to include: "first3" returns only the first 3, "all" returns every available image URL. imagesCount always shows the total.

## `incrementalMode` (type: `boolean`):

Only output new or changed listings since the last run. Uses content hashing stored in the actor's key-value store. First run outputs everything.

## `pushUnchangedSkeletons` (type: `boolean`):

DEPRECATED — prefer EXPIRED-based sold-detection instead: just leave Emit Expired Listings enabled (the default) and watch for changeType:"EXPIRED" rows. When Incremental Mode is on, this flag also pushes minimal skeleton items (url + externalId + contentHash + changeType:"UNCHANGED") for listings that haven't changed. Note: every exported dataset row is billed as a result — including unchanged skeleton rows — so on stable inventories skeleton runs cost nearly as much per row as regular runs.

## `emitExpired` (type: `boolean`):

When Incremental Mode is on, emit a one-time result row with changeType:"EXPIRED" for any tracked listing that has been missing from 2 consecutive fully-covered runs (sold-detection). EXPIRED rows are billed as standard results, so this is off by default — enable it if you want sold/delisted signals. Only applies to runs whose scope provably covers the full search — clean make/model searches or browse-all; filtered searches (year, price, mileage, etc.), multi-search runs, and partial crawls never expire listings.

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

Proxy configuration. Strongly recommended for reliable delivery.

## `maxPages` (type: `integer`):

Maximum number of search result pages to paginate through. Defensive safety bound — `maxResults` is the primary record cap.

## `minDelayMs` (type: `integer`):

Minimum deterministic delay between requests (0 = no delay)

## `maxDelayMs` (type: `integer`):

Maximum deterministic delay between requests (0 = no delay)

## `telegramToken` (type: `string`):

Telegram bot token from @BotFather. Required for Telegram notifications.

## `telegramChatId` (type: `string`):

Telegram chat or channel ID where alerts are sent (e.g. "-100123456789" for a private group, or "@yourchannel").

## `discordWebhookUrl` (type: `string`):

Discord incoming webhook URL. Get one from Server Settings → Integrations → Webhooks.

## `slackWebhookUrl` (type: `string`):

Slack incoming webhook URL. Create at api.slack.com/messaging/webhooks.

## `whatsappPhoneNumberId` (type: `string`):

WhatsApp Business phone number ID from Meta Business Manager (NOT the phone number itself — the numeric ID shown next to your business number). Free service-conversation messages within 24 hours of last user-initiated contact.

## `whatsappAccessToken` (type: `string`):

Meta Cloud API access token with `whatsapp_business_messaging` scope. Get a permanent token from a system user in Meta Business Manager.

## `whatsappTo` (type: `string`):

Recipient phone in E.164 format (e.g. +4512345678). Recipient must have messaged your business number within the last 24 hours — outside that window, free-form text is rejected by Meta.

## `webhookUrl` (type: `string`):

Generic webhook URL that receives a JSON POST with the full listing payload + run metadata. Universal escape hatch for n8n / Make / Zapier / your own backend.

## `webhookHeaders` (type: `object`):

Optional headers (e.g. {"Authorization": "Bearer xyz"}) sent with the webhook POST.

## `notificationLimit` (type: `integer`):

Maximum number of listings included in each notification message (1–20). Excess listings are still in the dataset; notifications get a summary line.

## `notifyOnlyChanges` (type: `boolean`):

When Incremental Mode is on, only send notifications for new or changed listings. Has no effect outside incremental mode.

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

Pick a single description representation. `all` keeps every variant; `text` / `html` / `markdown` drop the others.

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

Drop null, empty-string, and empty-array fields from each record before push. Smaller payloads for AI agents and dashboards.

## `appConnector` (type: `string`):

Optional. Pick a connected app under Settings → API & Integrations to receive your results. Notion is supported today (a run-summary page); other MCP connectors are best-effort as Apify expands its catalog.

## `mcpIssueTeam` (type: `string`):

Only when the connected app is an issue tracker: the team (name or ID) the summary issue is created under, if that app requires one.

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

Fetch the detail page for each listing to retrieve the full description text and contact information. Increases run time and cost. Leave off for a fast, low-cost run.

## `stateKey` (type: `string`):

Optional stable identifier for the tracked search. Leave empty to auto-derive from your search inputs — different filter combinations get isolated state.

## `emitUnchanged` (type: `boolean`):

When incremental mode is on, also emit listings whose content has not changed since the last run.

## `cityName` (type: `string`):

Danish city as the centre for a distance search — e.g. "Aarhus", "København", "Odense". Pair with Search Radius to keep only cars within that many km of the city. Leave Zip Code empty to use this (Zip Code takes precedence when both are set).

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.bilbasen.dk/brugt/bil"
    }
  ],
  "includeEngrosCvr": false,
  "strictModelFilter": true,
  "maxResults": 100,
  "includeDetailPages": true,
  "compact": false,
  "enrichFromDescription": false,
  "imagesMode": "first3",
  "incrementalMode": false,
  "pushUnchangedSkeletons": false,
  "emitExpired": false,
  "maxPages": 200,
  "minDelayMs": 0,
  "maxDelayMs": 0,
  "notificationLimit": 5,
  "notifyOnlyChanges": false,
  "descriptionFormat": "all",
  "excludeEmptyFields": false,
  "includeDetails": false,
  "emitUnchanged": false
}
```

# Actor output Schema

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

Dataset containing all scraped car listings. Each item is a normalized OutputItem record.

## `listingsCsv` (type: `string`):

Same listings in CSV format for spreadsheet import.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        {
            "url": "https://www.bilbasen.dk/brugt/bil"
        }
    ],
    "maxResults": 100,
    "descriptionFormat": "all",
    "excludeEmptyFields": false,
    "includeDetails": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("blackfalcondata/bilbasen-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": [{ "url": "https://www.bilbasen.dk/brugt/bil" }],
    "maxResults": 100,
    "descriptionFormat": "all",
    "excludeEmptyFields": False,
    "includeDetails": False,
}

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

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

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

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://www.bilbasen.dk/brugt/bil"
    }
  ],
  "maxResults": 100,
  "descriptionFormat": "all",
  "excludeEmptyFields": false,
  "includeDetails": false
}' |
apify call blackfalcondata/bilbasen-scraper --silent --output-dataset

```

## MCP server setup

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