# Blocket.se Car Listings Extractor (`steeriq/blocket-se-extract`) Actor

- **URL**: https://apify.com/steeriq/blocket-se-extract.md
- **Developed by:** [steeriq](https://apify.com/steeriq) (community)
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## 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

## Blocket.se Car Listings Extractor

Extracts car listings from [blocket.se](https://www.blocket.se), the Swedish
marketplace. You paste search, dealer or listing URLs, and it returns every
matching listing as clean, structured JSON: price, make, model, year, mileage,
fuel, gearbox, body, power, battery and range, location, seller, photos, VIN
and more.

The output uses one normalised shape that is shared with our other car
marketplace extractors, so you can combine data from several countries without
writing a mapping layer.

### What it covers

- Passenger cars, SUVs and family vans
- Light commercial vehicles listed among cars: vans and pick-ups

Other categories are skipped, including motorcycles, A-tractors, trucks,
caravans, boats and everything outside vehicles.

### How to use it

1. Open [blocket.se](https://www.blocket.se/mobility/search/car) and build a
   car search with the site's own filters: make, model, price, year, fuel,
   region, and so on.
2. Copy the URL from your browser's address bar.
3. Paste it into **Start URLs** and run the actor.

Every result of that search is returned. A single listing URL returns just that
listing. You can mix as many URLs as you like; the results are de-duplicated.

The actor accepts:

| URL | Example |
| --- | --- |
| Search results | `https://www.blocket.se/mobility/search/car?variant=1.749.2132` |
| A make or model page | `https://www.blocket.se/mobility/discover/cars/bmw/3-serie` |
| A dealer's stock | `https://www.blocket.se/mobility/dealer/547773/bilhuset-i-kalmar-ab` |
| One listing | `https://www.blocket.se/mobility/item/27268814` |

A make or model page returns the same results as the search it links to. A
dealer URL returns the dealer's cars.

Old Blocket URLs (`/bilar/…`, `/annonser/…`, `/annons/…`) are rejected: the
site now redirects them to far broader searches than the ones they named, so
build the search again on the current site.

### Input

| Field | Default | What it does |
| --- | --- | --- |
| `startUrls` | (required) | Search, make or model, dealer and listing URLs. |
| `detailLevel` | `full` | `full` opens every listing page for the complete record. `compact` returns only what the search results show, about 50 listings per request. |
| `maxItems` | no limit | Stop after this many listings. |
| `includeEquipment` | `false` | Add the equipment list, in Swedish, as published. |
| `includeRawParameters` | `false` | Add every other parameter from the listing page, as the site published it. |
| `skipSeenListings` | `false` | Skip listings that an earlier run already returned. |
| `seenStoreName` | `blocket-se-seen-listings` | The named key-value store that remembers seen listings. |
| `maxConcurrency` | `10` | Most requests in flight at once. |
| `maxRequestRetries` | `3` | Retries per request. |
| `proxyConfiguration` | none | Leave it empty and the actor uses a proxy only if the site blocks it. |

Example input:

```json
{
  "startUrls": ["https://www.blocket.se/mobility/search/car?variant=1.749.2132"],
  "maxItems": 100
}
```

#### Tracking new listings

To collect only new listings on a schedule, turn on `skipSeenListings` and run
the same searches daily. Listings that an earlier run returned are skipped
before they are requested, so you don't pay for them again. Use a different
`seenStoreName` for each independent feed.

### Output

Each dataset item is one listing. Here is an example at `full` detail, with
the photo list and description shortened:

```json
{
  "marketplace": "blocket-se",
  "id": "27268814",
  "url": "https://www.blocket.se/mobility/item/27268814",
  "title": "BMW 330e",
  "variant": "Touring Steptronic M-Sport *El-Drag *Kamera *ACC",
  "make": "bmw",
  "model": "330e",
  "price": 259900,
  "priceDerived": false,
  "priceExVat": null,
  "currency": "SEK",
  "year": 2021,
  "firstRegistration": "2020-10-01",
  "mileageKm": 160500,
  "fuelType": "plugin_hybrid_petrol",
  "bodyType": "wagon",
  "gearbox": "automatic",
  "drivetrain": "rear_wheel",
  "doors": 5,
  "seats": 5,
  "weightKg": 1905,
  "towingCapacityKg": 1500,
  "engineCapacityCc": 1990,
  "powerKw": 215,
  "batteryCapacityKwh": 12,
  "electricRangeKm": 56,
  "color": "grey",
  "condition": "used",
  "vin": "WBA6N3103MFK12581",
  "co2Gkm": 36,
  "euroStandard": null,
  "consumption": {
    "fuelL100km": null,
    "electricKwh100km": { "city": null, "highway": null, "combined": 16.2 }
  },
  "technicalInspectionUntil": "2026-10-31",
  "hasServiceHistory": null,
  "location": {
    "raw": "Trångsundsvägen 4, 39239 Kalmar",
    "city": "Kalmar",
    "region": null,
    "postalCode": "39239",
    "countryCode": "SE",
    "latitude": null,
    "longitude": null
  },
  "seller": {
    "type": "business",
    "typeInferred": false,
    "name": "Bilhuset i Kalmar AB",
    "memberSince": null,
    "activeListingCount": 150,
    "profileUrl": "https://www.blocket.se/mobility/dealer/547773/bilhuset-i-kalmar-ab",
    "websiteUrl": "http://www.bilhusetkalmar.se",
    "address": {
      "raw": "Trångsundsvägen 4, 392 39 KALMAR",
      "city": "KALMAR",
      "region": null,
      "postalCode": "39239",
      "countryCode": "SE",
      "latitude": null,
      "longitude": null
    }
  },
  "imageUrls": ["https://images.blocketcdn.se/dynamic/default/item/27268814/…"],
  "imageCount": 17,
  "status": "active",
  "description": "BMW 330e Touring Steptronic, M-Sport, 292hk, 2021…",
  "publishTime": null,
  "extractionTime": "2026-10-09T15:20:11.482Z",
  "startUrl": "https://www.blocket.se/mobility/search/car?variant=1.749.2132"
}
```

At `compact` detail you get the fields from `id` to `status`: the ones the
search results show. They show no body type, engine, power or battery, so
those are `null` there, and a range only for electric and plug-in hybrid cars.
The seller there has only its type and, for a dealer, its name.

#### How to read the fields

- **Normalised values.** Make, fuel, body, gearbox, drivetrain, colour and
  condition use fixed lowercase values (`diesel`, `suv`, `automatic`), whatever
  label the site used. If the site publishes a value outside that list, the
  field is `"unidentified"` and the original label is kept under `unmapped`,
  for example `{ "fuelType": "…" }`.
- **`null`** means the site did not publish that value.
- **`price`** is the full purchase price in Swedish kronor, including VAT.
  `priceExVat` is the price before VAT, when a company seller publishes one.
- **Leasing.** A monthly payment is never given as `price`:
  - A leasing offer has `price: null` and `priceExVat: null`, and `condition`
    `null`: its amount is a monthly payment, not a purchase price.
  - So does a price under 20 000 kr whose title or specification speaks of
    leasing (`Privatleasing`, `BUSINESS LEASE`, `kr/mån`, `:-/Mån`): sellers
    list leases under other sales forms too.
  - A car sold outright that also advertises leasing keeps its price.
  - A lease taken over and priced monthly, with no such words, can still come
    through with its monthly figure as `price`.
- **`mileageKm`** is converted from the Swedish mil the site publishes: one mil
  is 10 km.
- **`engineCapacityCc`** is converted from the litres the site publishes, to
  two decimals: `1,99 L` is 1990 cm³.
- **`powerKw`** is converted from metric horsepower (`hk`).
- **`vin`** is the full 17 characters, when the seller publishes it.
- **`publishTime`** is always `null`: the site shows only when a listing was
  last updated.
- **`seller.type`** is `business` for a dealer, named with its page on the
  site, and `private` for a private seller, who is never named.
- **`extractionTime`** is when the page was read. Price, mileage and status are
  as of that moment.
- **Removed listings.** A listing URL whose ad was removed, sold or withdrawn
  returns an item with `"status": "removed"`, so you can tell it apart from a
  failed request. The site does not say which of the three it was.

The registration number is never collected.

#### Run summary

Each run also saves a `RUN_SUMMARY` record in its key-value store. It shows the
outcome of every start URL (`ok`, `truncated`, `rejected` or `failed`), and any
requests that failed. The same summary appears as the run's status message.

`truncated` means the search had more results than the site lets anyone page
through: at most 2,500 per search, 50 pages of 50. To get all of them, split
the search into narrower ones, for example by model, year or price range.

### Cost and speed

Searches are read from the site's own search data, about 50 listings per
request, and listing pages as plain HTML. The actor uses no browser and, by
default, no proxy, so runs are fast and cheap. A proxy is added automatically,
first datacenter and then residential, only if the site starts blocking
requests.

To keep costs down:

- Use `compact` when the search result fields are enough.
- Set `maxItems` while you are testing.
- Use `skipSeenListings` for scheduled runs.

### Limits

- Only public listings are extracted. Nothing that requires a login.
- Seller phone numbers are not collected.
- Descriptions and equipment are returned as the seller wrote them, usually in
  Swedish.

# Actor input Schema

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

Search and listing URLs, mixed freely. Build a search with the site’s own filters and paste its URL: every result comes back. A listing URL returns that one listing. Results are merged and de-duplicated.

## `detailLevel` (type: `string`):

Full visits every listing page for the complete record. Compact returns only what the search result cards show, at about a twentieth of the requests.

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

Stop after this many results. Leave empty for every result.

## `includeEquipment` (type: `boolean`):

Add the equipment list to each full listing. It runs to about 80 entries on some sites.

## `includeRawParameters` (type: `boolean`):

Add every parameter the site published, as it published it, to each full listing.

## `skipSeenListings` (type: `boolean`):

Skip listings a previous run with the same store name already returned, without requesting them.

## `seenStoreName` (type: `string`):

The named key-value store holding the ids of listings already returned.

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

Most requests in flight at once.

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

Retries per request. With the default proxy tiers, a retry is likely to go out on a costlier proxy for that site.

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

Leave empty, or on “no proxy”, to start without a proxy and step up to Apify datacenter, then residential, only where the site blocks. An Apify Proxy group or your own proxies chosen here are used as they are, without stepping up.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.blocket.se/mobility/search/car?variant=1.749.2132"
  ],
  "detailLevel": "full",
  "maxItems": 3,
  "includeEquipment": false,
  "includeRawParameters": false,
  "skipSeenListings": false,
  "seenStoreName": "blocket-se-seen-listings",
  "maxConcurrency": 10,
  "maxRequestRetries": 3
}
```

# Actor output Schema

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

Every observation this run emitted, with every field, as JSON.

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

The same observations, trimmed to the overview columns.

## `runSummary` (type: `string`):

The outcome of every start URL, the requests that failed, and the route each start URL finished on.

# 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": [
        "https://www.blocket.se/mobility/search/car?variant=1.749.2132"
    ],
    "maxItems": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("steeriq/blocket-se-extract").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": ["https://www.blocket.se/mobility/search/car?variant=1.749.2132"],
    "maxItems": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("steeriq/blocket-se-extract").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": [
    "https://www.blocket.se/mobility/search/car?variant=1.749.2132"
  ],
  "maxItems": 3
}' |
apify call steeriq/blocket-se-extract --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steeriq/blocket-se-extract"
        }
    }
}
```

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/PEgfGbl9JDRFkiE2I/builds/g8Iw57OwEV3ipJboH/openapi.json
