Finn.no $0.8πŸ’° URL | Keyword |  Deep Search Scraper avatar

Finn.no $0.8πŸ’° URL | Keyword | Deep Search Scraper

Pricing

from $0.80 / 1,000 results

Go to Apify Store
Finn.no $0.8πŸ’° URL | Keyword |  Deep Search Scraper

Finn.no $0.8πŸ’° URL | Keyword | Deep Search Scraper

From $0.8/1K. Scrape active Finn.no ads via search builder or URL. Returns 30+ fields per ad, including full HTML description, employer details, deadline, contacts, languages, sector, industries, keywords, and apply URL.

Pricing

from $0.80 / 1,000 results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

0

Monthly active users

16 days ago

Last modified

Share

Finn.no Jobs Scraper

Scrape every active job ad on Finn.no, Norway's largest classifieds portal, in two clicks. Two input modes (Search builder, URL paste), 30+ structured fields per ad including the full HTML description, employer details, deadline, contact persons, working languages, sector, industries, keywords, and the apply URL. Works on every Apify plan with no extra setup.

Why This Scraper?

  • 30+ fields per ad, not just the SERP card: sector, industries, contact persons, keywords, apply URL, and the full rendered description.
  • Two input modes that both work for individual ads or full searches: build by keyword, location, employment type, industry, occupation, sector, working language, and posted-since; or paste any finn.no/job URL (including a single /job/ad/
  • Works on every plan, including Free. Apify Proxy is recommended for reliability; for higher volume or Norway-pinned routing set groups: ["RESIDENTIAL"], country: "NO".
  • Per-search budget cap so multi-keyword runs return a fair share from each search; client-side de-duplication across pages and searches via finnkode.
  • ~50 ads per SERP page, 2 to 5 ads per second sustained, low memory (256 MB default).
  • Skip sponsored placements ("Betalt plassering") with a single checkbox if you only want organic results.
  • Daily/recurring change monitoring: turn on Incremental mode to get only NEW, UPDATED, and REAPPEARED listings on every scheduled run, or resume one specific interrupted crawl with resumeFromRunId.

Data You Get

Sample shape: values are illustrative placeholders, not from a live ad.

FieldExample
id"460000000"
idInt460000000
url"https://www.finn.no/job/ad/460000000"
title"Sample Job Title"
subtitle"Sample Subtitle Headline"
employer"Sample Employer AS"
employerUrl"http://www.example.com/"
employerHomepage"http://www.example.com/"
employerLogo"https://images.finncdn.no/dynamic/default/0000/0/0/000000_0000000000.png"
streetAddress"Sample Street 1"
postalCode"0000"
city"Oslo"
addressCountry"NO"
locationDisplay"Oslo"
locationLink"https://www.finn.no/job/search?location=1.20001.20061"
latitude59.9000
longitude10.7000
datePosted"2026-01-01"
datePostedEpochMs1735689600000
relativePosted"2 dager siden"
applicationDeadline"2026-02-01"
applicationDeadlineEpochMs1738368000000
applicationDeadlineRaw"01.02.2026"
lastModified"2026-01-01T09:00:00.000Z"
lastModifiedEpochMs1735722000000
employmentForm"Fast"
employmentType["FULL_TIME"]
employmentTypeRequested"fulltime"
sector"Privat"
industries["Sample Industry A", "Sample Industry B"]
jobFunction"Sample Function"
internalJobTitle"Sample Internal Title"
workingLanguages["Norsk", "Engelsk"]
contactPersons[{ "name": "Jane Doe", "phones": ["+4700000000"], "emails": ["jane@example.com"] }]
keywords["sample", "keyword", "tags"]
applyUrl"https://example.com/apply/000"
descriptionHtml"<p>Full HTML ad description goes here.</p>"
descriptionText"Full ad description as plain text goes here."
breadcrumb["FINN", "Jobb", "SΓΈk", "Oslo"]
sponsoredfalse
scrapedAt"2026-01-01T00:00:00.000Z"
changeType"NEW" (incremental mode only β€” see "Resume & recurring updates" below)
changedFields["title"] (incremental mode, UPDATED rows only)
firstSeenAt"2026-01-01T00:00:00.000Z" (incremental mode only)
lastSeenAt"2026-01-02T00:00:00.000Z" (incremental mode only)

How to Use

1) Search by keyword + location

{
"mode": "search",
"queries": ["developer"],
"location": "1.20001.20061",
"employmentType": "fulltime",
"maxPages": 5,
"maxListings": 200,
"fetchDetails": true
}

2) Search multiple keywords with industry filter

{
"mode": "search",
"queries": ["sykepleier", "lege", "fysioterapeut"],
"employmentType": "fulltime",
"industry": "9",
"publishedSince": "7",
"sortBy": "published_desc",
"maxPages": 3,
"maxListings": 150
}

3) Search English-language management roles

{
"mode": "search",
"queries": ["product manager"],
"employmentType": "management",
"workLanguage": "english",
"sector": "private",
"skipSponsored": true,
"maxPages": 2
}

4) URL mode (paste any Finn.no URL, including a single ad)

{
"mode": "url",
"urls": [
"https://www.finn.no/job/search?q=developer&extent=3947&location=1.20001.20061",
"https://www.finn.no/job/search?extent=3942&location=0.22030",
"https://www.finn.no/job/ad/460000000"
],
"skipSponsored": true,
"maxPages": 5,
"maxListings": 250,
"fetchDetails": true
}

The search-builder fields (queries, location, employmentType, industry, occupation, sector, workLanguage, publishedSince, sortBy) are ignored in URL mode, because the pasted URL already carries its own filters. skipSponsored is not: it is applied after fetch, so it drops "Betalt plassering" cards from a pasted URL's results too.

5) Daily monitoring: only what changed since yesterday

{
"mode": "search",
"queries": ["developer"],
"location": "1.20001.20061",
"incrementalMode": true
}

First scheduled run returns everything as NEW. Every later run returns only NEW, UPDATED, and REAPPEARED listings β€” see "Resume & recurring updates" below.

Input Parameters

ParameterTypeDefaultDescription
modeenumsearchsearch (use builder fields) or url (paste URLs).
queriesarray of strings["developer"]Search mode only, ignored in URL mode. One search per keyword. Empty = browse without keyword filter.
locationstringemptySearch mode only, ignored in URL mode. Finn.no hierarchical location code (e.g. 1.20001.20061 for Oslo, 1.20001.20015 for Vestland). Pick a filter on finn.no/job and copy from ?location=.
employmentTypeenumfulltimeSearch mode only. In URL mode the employment type is read back out of the pasted URL instead. any / fulltime (Heltid, extent=3947) / parttime (Deltid, extent=3942) / management (Lederstillinger, manager_role=6702).
industrystringemptySearch mode only, ignored in URL mode. Finn.no industry code from ?industry=.
occupationstringemptySearch mode only, ignored in URL mode. Finn.no occupation/job-function code from ?occupation=.
sectorenumanySearch mode only, ignored in URL mode. any / private / public.
workLanguageenumanySearch mode only, ignored in URL mode. any / norwegian / english / swedish / danish / other.
publishedSinceenumanySearch mode only, ignored in URL mode. any / 1 / 3 / 7 / 14 / 30 (days).
sortByenumdefaultSearch mode only. A pasted URL keeps whatever ?sort= it already carries. default (relevance), published_desc (newest), deadline_asc (closest deadline).
skipSponsoredboolfalseApplies in both search mode and URL mode. Drop "Betalt plassering" cards (paid placements) after fetch, including from the results of a pasted finn.no/job URL.
urlsarray of stringsexample URLURL mode only. Each URL is paged forward independently. The search-builder fields above are ignored in this mode; skipSponsored still applies.
maxPagesint(empty)Max SERP pages per search (or per pasted URL). Leave empty (or 0) to walk every result page until Finn.no has no more.
maxListingsint20Cap across all searches. 0 = unlimited (still bounded by maxPages).
fetchDetailsbooltrueFetch full ad details: description, deadline, sector, industries, contact persons, keywords, apply URL.
resumeFromRunIdstring(empty)A previous run ID or dataset ID to continue a full-catalogue walk across separate runs. Listings already collected there (matched by id) are skipped, so this run only saves the new ones. For recurring daily monitoring of the same search, use incrementalMode instead β€” see "Resume & recurring updates" below.
incrementalModeboolfalseDaily/recurring monitoring of this same search. First run returns everything as NEW; later runs return only NEW/UPDATED/REAPPEARED by default. See "Resume & recurring updates" below.
stateKeystring(empty)Optional name for a monitoring campaign, so its incremental state stays stable or is deliberately shared. Auto-derived from your search/URL and fetchDetails settings when left empty.
emitUnchangedboolfalseIncremental mode only. Also return listings unchanged since the last run, marked UNCHANGED. Adds and bills extra rows you already have.
emitExpiredboolfalseIncremental mode only. Also return listings from a previous run no longer found, marked EXPIRED, once a run has fully scanned the tracked search (not capped, not a resume). Adds and bills extra synthetic rows.
proxyobjectApify ProxyWorks on every plan, including Free. For higher volume or Norway-pinned routing, set groups: ["RESIDENTIAL"], country: "NO".

Resume & recurring updates

There are two different things here β€” pick the one that matches what you're doing:

NeedUse
A crawl stopped and should continueresumeFromRunId / automatic checkpoint recovery
Run the same search every day and receive only changesincrementalMode
Keep separate daily campaigns for similar searchesdistinct stateKey values
Run a normal full snapshotleave both off

Resume (resumeFromRunId) continues one specific interrupted or previous large crawl: paste a run ID or dataset ID and this run skips listings already collected there, returning only the remaining new ones. A checkpoint is also saved automatically as the run progresses β€” if the run is interrupted by an Apify platform migration or you click Resurrect on a failed run, it picks back up from where it left off in the same run, without re-saving already-collected listings. No input is needed for this; it's automatic.

Incremental mode (incrementalMode) is for a schedule (for example, daily): the actor remembers the previous run of the same search by itself, so you never paste a run ID. The first run returns everything as NEW. Later runs return only NEW, UPDATED, and REAPPEARED listings by default β€” duplicates and unchanged listings are suppressed (and not billed). Turn on emitUnchanged or emitExpired only when you also want those rows returned (and billed for). State is isolated per search/URL setup and per fetchDetails setting β€” turning fetchDetails on or off starts a fresh baseline rather than diffing detail fields against a card-only snapshot. Set stateKey to name or deliberately share a monitoring campaign.

Some fields are excluded from change detection because they always drift on their own and would otherwise mark every listing UPDATED on every run: scrapedAt (the run timestamp) and relativePosted (a relative "X days ago" string that changes with the clock, not the listing). Both fields are still returned on every row as usual β€” they are simply ignored when deciding NEW/UPDATED/UNCHANGED.

Scheduled-run example β€” same search, run daily:

Day 1 (first run ever for this search):

{ "mode": "search", "queries": ["developer"], "location": "1.20001.20061", "incrementalMode": true }

β†’ every listing comes back with "changeType": "NEW".

Day 2 (the schedule fires again, identical input):

{ "mode": "search", "queries": ["developer"], "location": "1.20001.20061", "incrementalMode": true }

β†’ listings that vanished and reappeared come back as "changeType": "REAPPEARED", listings whose title/deadline/etc. changed come back as "changeType": "UPDATED" with changedFields listing what changed, brand-new postings come back as "changeType": "NEW" β€” and listings that are still there, unchanged, are not returned at all (suppressed, not billed) unless emitUnchanged is on.

Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape β€” the Apify dataset is never changed.

What gets written to the connector: a condensed, human-readable summary of each record β€” not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

  1. Authorize a connector once under Apify β†’ Settings β†’ Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
  3. For Notion, also set notionParentPageUrl to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

Output Example

Sample shape: values are illustrative placeholders, not from a live ad.

{
"id": "460000000",
"idInt": 460000000,
"url": "https://www.finn.no/job/ad/460000000",
"title": "Sample Job Title",
"subtitle": "Sample Subtitle Headline",
"employer": "Sample Employer AS",
"employerUrl": "http://www.example.com/",
"employerHomepage": "http://www.example.com/",
"employerLogo": "https://images.finncdn.no/dynamic/default/0000/0/0/000000_0000000000.png",
"streetAddress": "Sample Street 1",
"postalCode": "0000",
"city": "Oslo",
"addressCountry": "NO",
"locationDisplay": "Oslo",
"locationLink": "https://www.finn.no/job/search?location=1.20001.20061",
"latitude": 59.9,
"longitude": 10.7,
"datePosted": "2026-01-01",
"datePostedEpochMs": 1735689600000,
"relativePosted": "2 dager siden",
"applicationDeadline": "2026-02-01",
"applicationDeadlineEpochMs": 1738368000000,
"applicationDeadlineRaw": "01.02.2026",
"lastModified": "2026-01-01T09:00:00.000Z",
"lastModifiedEpochMs": 1735722000000,
"employmentForm": "Fast",
"employmentType": ["FULL_TIME"],
"employmentTypeRequested": "fulltime",
"sector": "Privat",
"industries": ["Sample Industry A", "Sample Industry B"],
"jobFunction": "Sample Function",
"internalJobTitle": "Sample Internal Title",
"workingLanguages": ["Norsk", "Engelsk"],
"contactPersons": [
{ "name": "Jane Doe", "phones": ["+4700000000"], "emails": ["jane@example.com"] }
],
"keywords": ["sample", "keyword", "tags"],
"applyUrl": "https://example.com/apply/000",
"descriptionHtml": "<p>Full HTML ad description goes here.</p>",
"descriptionText": "Full ad description as plain text goes here.",
"breadcrumb": ["FINN", "Jobb", "SΓΈk", "Oslo"],
"sponsored": false,
"scrapedAt": "2026-01-01T00:00:00.000Z"
}

Plan Requirement

This scraper works on every Apify plan, including Free, with the default useApifyProxy: true config. For larger runs, or if you see throttling, switch the proxy field to { useApifyProxy: true, apifyProxyGroups: ["RESIDENTIAL"], apifyProxyCountry: "NO" } (Apify Starter or higher). You can also paste your own proxy URLs in the proxy field.