Domain skill
bilbasen
Markdown synced from browser-harness domain skills.
- Host
- bilbasen
- Files
- 1
Agent prompt
Use this skill
Copy this prompt into your coding agent to make it enable browser-harness domain skills and read this exact domain folder before automating.
Set up https://github.com/browser-use/browser-harness for me if it is not already installed. If setup is needed, read `install.md` first to install and connect it to my real browser. Then read `SKILL.md` for normal usage and always read `helpers.py` because that is where the browser-harness functions are. Enable domain skills if they are not already enabled by setting `BH_DOMAIN_SKILLS=1` for browser-harness. Use the `bilbasen` domain skill from `agent-workspace/domain-skills/bilbasen/`. Read every markdown file for this domain before inventing an approach: - agent-workspace/domain-skills/bilbasen/search.md Use those domain-skill notes to complete my task for `bilbasen` in my real browser. When you open a setup, verification, or task tab, activate it so I can see the active browser tab.
Skill contents
What the agent will read
Used-car search data extraction
search.md
- Field-tested against www.bilbasen.dk on 2026-09-21 from a logged-out, real Chrome session (CDP). Bilbasen is Denmark's largest used-car marketplace.
- Plain HTTP is blocked. httpget / curl with a full Chrome UA returns HTTP 202 with an empty body (JS bot challenge). Use the user's real browser.
- Search result pages embed every listing on the page as JSON in <script id="NEXTDATA"> (Next.js SSR). No need to scrape cards or scroll.
- Search URL pattern: https://www.bilbasen.dk/brugt/bil/<make>/<model>?pricefrom=<int>&priceto=<int>. Make/model slugs are lowercase (vw, id.4). The site 302s to an internal model id (/brugt/bil/vw/id2314) and appends...
Show full markdown
Field-tested against www.bilbasen.dk on 2026-09-21 from a logged-out, real Chrome session (CDP). Bilbasen is Denmark's largest used-car marketplace.
Quick summary
- Plain HTTP is blocked.
http_get/curlwith a full Chrome UA returns HTTP 202 with an empty body (JS bot challenge). Use the user's real browser. - Search result pages embed every listing on the page as JSON in
<script id="__NEXT_DATA__">(Next.js SSR). No need to scrape cards or scroll. - Search URL pattern:
https://www.bilbasen.dk/brugt/bil/<make>/<model>?pricefrom=<int>&priceto=<int>. Make/model slugs are lowercase (vw,id.4). The site 302s to an internal model id (/brugt/bil/vw/id2314) and appendsincludeengroscvr=true&includeleasing=false; both URLs work. - 30 listings per page; total hits in
hits. - This example reads one page. When
hitsexceeds the listing count, use the visible next-page control. - Wait for listing IDs to change before reading the next page. Remove duplicates by
externalId. - Verify the final unique count against
hits; report any shortfall instead of claiming complete results.
Extracting listings
python
import json
new_tab("https://www.bilbasen.dk/brugt/bil/vw/id.4?pricefrom=150000&priceto=195000")
wait_for_load()
raw = js("document.getElementById('__NEXT_DATA__').textContent")
queries = json.loads(raw)["props"]["pageProps"]["dehydratedState"]["queries"]
data = next((q.get("state", {}).get("data") for q in queries
if isinstance(q.get("state", {}).get("data"), dict)
and "listings" in q["state"]["data"]), None)
if data is None:
raise RuntimeError("The page has no listings query")
print(data["hits"], len(data["listings"])) # e.g. 48, 30
Top-level keys in data: listings, filterOptions, sortOptions, searchRequest, pagination, breadcrumbs, canonicalUrl, hits, totalAbundance.
Fields in each listing
| Field | Example | Notes |
|---|---|---|
externalId | 6999185 | listing id, also last path segment of uri |
uri | https://www.bilbasen.dk/brugt/bil/vw/id4/52-pure-5d/6999185 | detail page |
price.price | 169900 | int DKK, use for math; price.displayPrice is formatted |
price.priceType | "Retail" | |
make, model | "VW", "ID.4" | |
variant | "77 1ST Pro Performance 5d" | trim string; use the battery field for capacity |
description | Danish prose, 800–2900 chars | dealer boilerplate mixed with equipment highlights |
sellerType | "Forhandler" / "Privat" | dealer vs private |
saleType | ||
location | object | seller location |
media[] | {mediaType: "Picture", url} | images, ?class=S640X640 |
properties.firstregistrationdate | {displayTextShort: "10/2022"} | month/year of first registration |
properties.mileage | "76.500 km" | Danish thousands separator, parse in code |
properties.hk | "148 hk" | horsepower |
properties.moth | "920 kr/år" | annual ownership tax (ejerafgift) |
properties.trailer | "1.000 kg" | tow rating |
properties.kmt | "10,9 sek" | 0–100 acceleration |
properties.electricmotorrange | "343 km" | WLTP range |
properties.batterycapacity | "52 kWh batteri" (displayTextLong) | |
properties.geartype | transmission text | gearbox type |
properties.fueltype | "El" | fuel type |
features | [] | empty on search pages; equipment list is not in the search JSON |
Each properties.* entry has both displayTextLong and displayTextShort. All numeric values are formatted strings; parse them in code.
Traps
- 202 empty body from
http_getis the bot wall, not a transient error. Do not retry with headers; go through the browser. featuresis always empty in search results. Equipment lists must come from the detail page.- Seller descriptions are not spec sheets. Descriptions were seen quoting DC charging speeds that did not match the variant's model year. Verify technical specs against the exact variant and model year. Use
properties.batterycapacityfor the listed battery capacity. - Danish number formats:
76.500 kmis 76,500;10,9 sekis 10.9.