Sign inTry it

Search FINN Torget for second-hand items.

Searches FINN Torget, Norway's largest marketplace, like its search page: title, price in NOK, place, when it was published (UTC), private or business seller, shipping and FINN '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
FINN, Norway
Version
v1
Runs, last 7 days
No reports yet
sha256
987a787d6b15…

Run it with your agent

after installing Wield

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

“Search FINN Torget for second-hand items.”

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

{
  "tool": "run",
  "arguments": {
    "recipe_id": "finn.no/search-marketplace",
    "params": {
      "max_price": 2000,
      "query": "sykkel",
      "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_typeFINN'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_pricenumberNOK
min_pricenumberNOK
pageinteger = 1
querystringrequiredWhat to look for, e.g. 'sykkel', 'sofa', '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.finn.no

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.finn.no/recommerce/forsale/item/')]) == length(output.listings)
  • output.listings[*].published_at == reverse(sort(output.listings[*].published_at))
  • length(output.listings[?currency == 'NOK']) == length(output.listings)

Raw recipe

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

Check it yourself
curl -s https://wield.run/api/v1/recipes/finn.no/search-marketplace | shasum -a 256
# 987a787d6b156a1fb9c1d9475bff8050821991d15fa72abdeb107f6e93c043ed
finn.no/search-marketplace.json, v1
{
  "description": "Searches FINN Torget, Norway's largest marketplace, like its search page: title, price in NOK, place, when it was published (UTC), private or business seller, shipping and FINN '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": "finn.no/search-marketplace",
  "keywords": [
    "finn",
    "finn torget",
    "brukt",
    "til salgs",
    "gis bort",
    "sykkel",
    "møbler",
    "kjøpe",
    "selge",
    "second hand",
    "used",
    "marketplace",
    "norway",
    "classifieds"
  ],
  "output": {
    "schema": {
      "properties": {
        "last_page": {
          "type": [
            "integer",
            "null"
          ]
        },
        "listings": {
          "items": {
            "properties": {
              "buy_now": {
                "description": "Can be bought directly on FINN",
                "type": "boolean"
              },
              "currency": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "image": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "latitude": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "location": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "longitude": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "price": {
                "description": "NOK",
                "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": "NOK",
        "minimum": 0,
        "type": "number"
      },
      "min_price": {
        "description": "NOK",
        "minimum": 0,
        "type": "number"
      },
      "page": {
        "default": 1,
        "maximum": 50,
        "minimum": 1,
        "type": "integer"
      },
      "query": {
        "description": "What to look for, e.g. 'sykkel', 'sofa', '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.finn.no/recommerce/forsale/search?q=… is server-rendered from a base64 react-query state; its props name apiUrl https://www.finn.no/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). Images are links to images.finncdn.no (never called).",
    "recorded_at": "2026-11-07T21:53:00+01:00",
    "recorded_by": "C4"
  },
  "requires_login": false,
  "schema": "https://wield.run/schema/recipe/v1.json",
  "site": {
    "country": "NO",
    "id": "finn.no",
    "language": "nb",
    "name": "FINN",
    "origin": "https://www.finn.no",
    "origins": [
      "https://www.finn.no"
    ]
  },
  "steps": [
    {
      "description": "FINN'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 FINN Torget 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.finn.no/recommerce/forsale/item/')]) == length(output.listings)",
      "output.listings[*].published_at == reverse(sort(output.listings[*].published_at))",
      "length(output.listings[?currency == 'NOK']) == length(output.listings)"
    ],
    "example_params": {
      "max_price": 2000,
      "query": "sykkel",
      "sort": "newest"
    },
    "max_ms": 3000
  },
  "version": 1
}