{"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}