Sign inTry it

Search Blocket for second-hand items.

Searches Blocket, Sweden's largest marketplace, like its search page: title, price in SEK, place, when it was published (UTC), private or business seller, shipping and Blocket 'buy now' flags, map position, image and link. Filters: price range, condition, seller type, for sale / giveaway / wanted; sort by relevance, date or price. 53 listings per page.

No reports yetRead-only, no login
Site
Blocket, Sweden
Version
v1
Runs, last 7 days
No reports yet
sha256
2d26759da30d…

Run it with your agent

after installing Wield

Ask in plain words. Your agent finds this recipe and calls it:

“Search Blocket for second-hand items.”

Read-only: it changes nothing on the site. No login needed.

{
  "tool": "run",
  "arguments": {
    "recipe_id": "blocket.se/search-marketplace",
    "params": {
      "max_price": 2000,
      "query": "cykel",
      "sort": "newest"
    }
  }
}

Requests

sent from your browser, in order
  1. 1GET/recommerce/forsale/search/api/search/SEARCH_ID_BAP_COMMON?condition&dealer_segment&page&price_from&price_to&q&sort&trade_typeBlocket's own search API (/recommerce/forsale/search/api, the apiUrl in the search page's props; the page calls it when the search changes). The one-item foreach maps the params to its filter codes.repeats, max 1

Parameters

from your agent
conditionenumnew (unopened), like_new, good, used (visibly used), needs_repair "new" | "like_new" | "good" | "used" | "needs_repair"
max_pricenumberSEK
min_pricenumberSEK
pageinteger = 1
querystringrequiredWhat to look for, e.g. 'cykel', 'soffa', 'iphone 13'
sellerenum "any" | "private" | "business" = "any"
sortenum "relevance" | "newest" | "oldest" | "price_low" | "price_high" = "relevance"
typeenumfor_sale, giveaway (free) or wanted (people looking to buy) "for_sale" | "giveaway" | "wanted" = "for_sale"

Returns

to your agent
last_pageinteger
listingsobject[]buy_now, currency, image, latitude, location, longitude, price, published_at, seller, shipping, title, url
pageinteger
querystring
totalinteger

Where it can send

  • www.blocket.se

Anything else is blocked by the extension.

Reads from your session

Nothing. Your browser attaches the site's cookies by itself.

Used only in requests to the addresses on the left. Never sent to wield.run or your agent.

Checks

a run passes when
  • length(output.listings) > `40`
  • output.total > `1000`
  • length(output.listings[?price > `2000`]) == `0`
  • length(output.listings[?starts_with(url, 'https://www.blocket.se/recommerce/forsale/item/')]) == length(output.listings)
  • output.listings[*].published_at == reverse(sort(output.listings[*].published_at))
  • length(output.listings[?currency == 'SEK']) == length(output.listings)

Raw recipe

Served as canonical JSON from /api/v1/recipes/blocket.se/search-marketplace, so its sha256 matches the ETag and the index.

Check it yourself
curl -s https://wield.run/api/v1/recipes/blocket.se/search-marketplace | shasum -a 256
# 2d26759da30d9383465ad0234cafa09bcf4110636883ad3d34f8b329416a5eb5
blocket.se/search-marketplace.json, v1
{
  "description": "Searches Blocket, Sweden's largest marketplace, like its search page: title, price in SEK, place, when it was published (UTC), private or business seller, shipping and Blocket 'buy now' flags, map position, image and link. Filters: price range, condition, seller type, for sale / giveaway / wanted; sort by relevance, date or price. 53 listings per page.",
  "effect": "read",
  "id": "blocket.se/search-marketplace",
  "keywords": [
    "blocket",
    "begagnat",
    "säljes",
    "bortskänkes",
    "köpes",
    "cykel",
    "möbler",
    "köpa",
    "sälja",
    "second hand",
    "used",
    "marketplace",
    "sweden",
    "classifieds"
  ],
  "output": {
    "schema": {
      "properties": {
        "last_page": {
          "type": [
            "integer",
            "null"
          ]
        },
        "listings": {
          "items": {
            "properties": {
              "buy_now": {
                "description": "Can be bought directly on Blocket",
                "type": "boolean"
              },
              "currency": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "image": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "latitude": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "location": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "longitude": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "price": {
                "description": "SEK",
                "type": [
                  "number",
                  "null"
                ]
              },
              "published_at": {
                "description": "ISO 8601, UTC",
                "type": [
                  "string",
                  "null"
                ]
              },
              "seller": {
                "description": "private or business",
                "type": "string"
              },
              "shipping": {
                "description": "Can be shipped",
                "type": "boolean"
              },
              "title": {
                "type": "string"
              },
              "url": {
                "type": "string"
              }
            },
            "type": "object"
          },
          "type": "array"
        },
        "page": {
          "type": "integer"
        },
        "query": {
          "type": "string"
        },
        "total": {
          "type": [
            "integer",
            "null"
          ]
        }
      },
      "required": [
        "query",
        "listings"
      ],
      "type": "object"
    },
    "value": "let $s = steps.search[0] in {query: params.query, total: $s.total || `0`, page: params.page || `1`, last_page: $s.last_page || `null`, listings: map(&(let $x = @ in {title: $x.title, price: $x.price || `null`, currency: $x.currency || `null`, location: $x.location || `null`, published_at: ($x.ts && let $t = $x.ts // `1000` in let $z = $t // `86400` + `719468` in let $era = $z // `146097` in let $doe = $z - $era * `146097` in let $yoe = ($doe - $doe // `1460` + $doe // `36524` - $doe // `146096`) // `365` in let $doy = $doe - (`365` * $yoe + $yoe // `4` - $yoe // `100`) in let $mp = (`5` * $doy + `2`) // `153` in let $mon = ($mp < `10` && $mp + `3`) || $mp - `9`, $day = $doy - (`153` * $mp + `2`) // `5` + `1`, $sec = $t % `86400` in join('', [to_string($yoe + $era * `400` + (($mon <= `2` && `1`) || `0`)), '-', pad_left(to_string($mon), `2`, '0'), '-', pad_left(to_string($day), `2`, '0'), 'T', pad_left(to_string($sec // `3600`), `2`, '0'), ':', pad_left(to_string(($sec % `3600`) // `60`), `2`, '0'), ':', pad_left(to_string($sec % `60`), `2`, '0'), 'Z'])) || `null`, seller: (contains($x.flags || `[]`, 'retailer') && 'business') || 'private', shipping: contains($x.flags || `[]`, 'shipping_exists'), buy_now: contains($x.flags || `[]`, 'buy_now'), latitude: $x.lat || `null`, longitude: $x.lon || `null`, image: $x.image || `null`, url: $x.url}), $s.docs || `[]`)}"
  },
  "params": {
    "additionalProperties": false,
    "properties": {
      "condition": {
        "description": "new (unopened), like_new, good, used (visibly used), needs_repair",
        "enum": [
          "new",
          "like_new",
          "good",
          "used",
          "needs_repair"
        ],
        "type": "string"
      },
      "max_price": {
        "description": "SEK",
        "minimum": 0,
        "type": "number"
      },
      "min_price": {
        "description": "SEK",
        "minimum": 0,
        "type": "number"
      },
      "page": {
        "default": 1,
        "maximum": 50,
        "minimum": 1,
        "type": "integer"
      },
      "query": {
        "description": "What to look for, e.g. 'cykel', 'soffa', 'iphone 13'",
        "maxLength": 100,
        "minLength": 2,
        "type": "string"
      },
      "seller": {
        "default": "any",
        "enum": [
          "any",
          "private",
          "business"
        ],
        "type": "string"
      },
      "sort": {
        "default": "relevance",
        "enum": [
          "relevance",
          "newest",
          "oldest",
          "price_low",
          "price_high"
        ],
        "type": "string"
      },
      "type": {
        "default": "for_sale",
        "description": "for_sale, giveaway (free) or wanted (people looking to buy)",
        "enum": [
          "for_sale",
          "giveaway",
          "wanted"
        ],
        "type": "string"
      }
    },
    "required": [
      "query"
    ],
    "type": "object"
  },
  "provenance": {
    "method": "browser-inspect",
    "notes": "The search page https://www.blocket.se/recommerce/forsale/search?q=… is server-rendered from a base64 react-query state; its props name apiUrl https://www.blocket.se/recommerce/forsale/search/api, and the page calls /search/SEARCH_ID_BAP_COMMON with the same URL parameters as the page (q, price_from, price_to, condition 1–5, dealer_segment 1 private / 3 business, trade_type 1 sale / 2 giveaway / 3 wanted, sort RELEVANCE / PUBLISHED_DESC / PUBLISHED_ASC / PRICE_ASC / PRICE_DESC, page). Answer: docs [{type 'bap', heading, location, price.amount/currency_code, timestamp (ms), flags private/retailer/shipping_exists/buy_now, coordinates, image.url, canonical_url}], metadata.result_size.match_count, metadata.paging.last. Display ads are a separate advertising slot, not docs; the recipe keeps type 'bap' only. published_at is the epoch converted in JMESPath (civil-from-days). blocket.se's old search URLs redirect to /recommerce/forsale/search; the platform is the same as FINN's. Images are links to images.blocketcdn.se (never called).",
    "recorded_at": "2026-11-07T21:54:00+01:00",
    "recorded_by": "C4"
  },
  "requires_login": false,
  "schema": "https://wield.run/schema/recipe/v1.json",
  "site": {
    "country": "SE",
    "id": "blocket.se",
    "language": "sv",
    "name": "Blocket",
    "origin": "https://www.blocket.se",
    "origins": [
      "https://www.blocket.se"
    ]
  },
  "steps": [
    {
      "description": "Blocket's own search API (/recommerce/forsale/search/api, the apiUrl in the search page's props; the page calls it when the search changes). The one-item foreach maps the params to its filter codes.",
      "expect": {
        "assert": "body.docs != `null`",
        "content_type": "json",
        "status": [
          200
        ]
      },
      "extract": {
        "json": {
          "docs": "docs[?type == 'bap'].{title: heading, price: price.amount, currency: price.currency_code, location: location, ts: timestamp, flags: flags, lat: coordinates.lat, lon: coordinates.lon, image: image.url, url: canonical_url}",
          "last_page": "metadata.paging.last",
          "total": "metadata.result_size.match_count"
        }
      },
      "foreach": {
        "as": "f",
        "in": "let $sort = params.sort || 'relevance', $cond = params.condition || `null`, $seller = params.seller || 'any', $type = params.type || 'for_sale' in [{sort: ($sort != 'relevance' && (`[[\"relevance\",\"RELEVANCE\"],[\"newest\",\"PUBLISHED_DESC\"],[\"oldest\",\"PUBLISHED_ASC\"],[\"price_low\",\"PRICE_ASC\"],[\"price_high\",\"PRICE_DESC\"]]`[?@[0] == $sort] | [0][1])) || `null`, condition: (`[[\"new\",\"1\"],[\"like_new\",\"2\"],[\"good\",\"3\"],[\"used\",\"4\"],[\"needs_repair\",\"5\"]]`[?@[0] == $cond] | [0][1]) || `null`, dealer: (`[[\"private\",\"1\"],[\"business\",\"3\"]]`[?@[0] == $seller] | [0][1]) || `null`, trade: (`[[\"for_sale\",\"1\"],[\"giveaway\",\"2\"],[\"wanted\",\"3\"]]`[?@[0] == $type] | [0][1]) || '1'}]",
        "max": 1
      },
      "id": "search",
      "request": {
        "headers": {
          "Accept": "application/json"
        },
        "method": "GET",
        "query": {
          "condition": "{{f.condition}}",
          "dealer_segment": "{{f.dealer}}",
          "page": "{{params.page}}",
          "price_from": "{{params.min_price}}",
          "price_to": "{{params.max_price}}",
          "q": "{{params.query}}",
          "sort": "{{f.sort}}",
          "trade_type": "{{f.trade}}"
        },
        "url": "/recommerce/forsale/search/api/search/SEARCH_ID_BAP_COMMON"
      }
    }
  ],
  "task": "Search Blocket for second-hand items",
  "tos": {
    "notes": "One request per call, the same search the page makes. robots.txt allows the search and its API but disallows URLs with sort= for bots; sort= is sent only when the user asks for another order than relevance. No messages, offers or favourites.",
    "reviewed": false
  },
  "verify": {
    "checks": [
      "length(output.listings) > `40`",
      "output.total > `1000`",
      "length(output.listings[?price > `2000`]) == `0`",
      "length(output.listings[?starts_with(url, 'https://www.blocket.se/recommerce/forsale/item/')]) == length(output.listings)",
      "output.listings[*].published_at == reverse(sort(output.listings[*].published_at))",
      "length(output.listings[?currency == 'SEK']) == length(output.listings)"
    ],
    "example_params": {
      "max_price": 2000,
      "query": "cykel",
      "sort": "newest"
    },
    "max_ms": 3000
  },
  "version": 1
}