FINN.no Jobs Scraper - Listings, Employers & Contacts
Pricing
from $0.80 / 1,000 results
FINN.no Jobs Scraper - Listings, Employers & Contacts
Scrape active FINN.no job listings by search filters or URL. Extract 30+ fields including full descriptions, employer details, deadlines, contacts, languages, sectors, industries, keywords and apply URLs.
Pricing
from $0.80 / 1,000 results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
4
Total users
0
Monthly active users
7 days ago
Last modified
Categories
Share
Finn.no Scraper: Job Ads, Employers, Deadlines and Contacts
Finn.no Scraper turns Finn.no, Norway's largest classifieds portal, into a structured feed of job ads. Search by keyword, location, employment type, industry, occupation, sector, working language and posting date, or paste any finn.no/job URL, including a single ad, and get the full ad back: employer, address, deadline, contact persons, working languages, sector, industries, keywords, the apply URL and the complete description. Export to JSON, CSV or Excel, or pull results into your app through the API.
Why This Scraper?
- 30+ fields per ad, not just the search card. Full HTML and plain-text description, employer address and homepage, deadline, contact persons, working languages, sector, industries and the apply URL.
- Two ways to scrape. Build a search from keyword, location, employment type, industry, occupation, sector, working language and posted-since filters, or paste any finn.no/job URL, including a single
/job/ad/<id>link, and every result page is collected automatically. - Post-filter for sponsored cards. Drop "Betalt plassering" placements with one checkbox, applied to both a built search and a pasted URL's results.
- Per-search budget. A multi-keyword run splits the item cap across every keyword instead of exhausting it on the first one.
- Daily change monitoring. Turn on Incremental mode to get only the listings that are new or changed on each scheduled run, with unchanged and expired tracking available as opt-ins.
- Resume an interrupted crawl. Paste a previous run or dataset ID to continue a large walk without re-collecting what's already saved, or let the actor recover automatically after a platform migration.
- Pipe results into your apps. Send a summary of every ad straight into Notion, Linear or Airtable through MCP connectors, on top of the full dataset.
Use Cases
- Recruiters and staffing agencies: track competing job ads for a role, and compare deadlines, sectors, employment forms and ad requirements across employers.
- Job boards and aggregators: mirror Finn.no job listings into your own search index, newsletter or alert feed.
- Market and labor researchers: measure which sectors, industries and locations are hiring, and how demand shifts week to week.
- Norwegian-language NLP teams: build labeled datasets of real job ad text for classification, extraction or search-ranking models.
- HR and compliance analytics teams: monitor a defined set of employers' own postings for consistency and changes over time.
Data You Get
Sample shape: values are illustrative placeholders, not from a live ad.
| Field | Example |
|---|---|
id | "471234567" |
idInt | 471234567 |
url | "https://www.finn.no/job/ad/471234567" |
title | "Backend-utvikler" |
employer | "Nordlys Data AS" |
employerHomepage | "https://www.example-employer.no/" |
city | "Oslo" |
postalCode | "0150" |
locationDisplay | "Oslo" |
latitude / longitude | 59.9139 / 10.7522 |
datePosted | "2026-02-10" |
applicationDeadline | "2026-03-10" |
employmentForm | "Fast" |
employmentType | ["FULL_TIME"] |
sector | "Privat" |
industries | ["IT", "Telekommunikasjon"] |
workingLanguages | ["Norsk", "Engelsk"] |
contactPersons | [{ "name": "Kari Fjeldstad", "phones": ["+4791234567"], "emails": ["kari.fjeldstad@example-employer.no"] }] |
keywords | ["backend", "kotlin", "cloud"] |
applyUrl | "https://www.example-employer.no/careers/471234567" |
descriptionText | "Full ad description as plain text goes here." |
sponsored | false |
scrapedAt | "2026-02-10T08:00:00.000Z" |
Each ad also carries the employer's own website URL and logo, address country, a location filter link, epoch-millisecond timestamps alongside every date field, the raw Norwegian deadline string, a last-modified time, the employment type you requested, the job function and internal job title, the full HTML description, and a breadcrumb trail. When Incremental mode is on, every row also carries changeType (NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED), changedFields, firstSeenAt and lastSeenAt; EXPIRED only appears on a run that has "Emit expired" turned on and itself completes a full, uncapped, non-resumed scan of that same search; REAPPEARED only appears for a listing that an earlier such run marked no longer present, so neither shows up on a plain incremental run.
How to Use
- Pick a Search mode:
search(build from keyword, location and filters) orurl(paste finn.no/job links). - Fill in the fields for that mode. In
urlmode the search-builder fields are ignored, because the pasted link already carries its own filters. - Set Max listings and, if you want a hard page ceiling, Max pages to control run size and cost.
- Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.
Search by keyword and location:
{"mode": "search","queries": ["prosjektleder"],"location": "1.20001.20061","employmentType": "fulltime","maxListings": 100,"fetchDetails": true}
Multiple keywords with an industry filter, newest first:
{"mode": "search","queries": ["sykepleier", "fysioterapeut"],"industry": "9","publishedSince": "7","sortBy": "published_desc","maxPages": 3,"maxListings": 150}
URL mode: a search link plus one single ad:
{"mode": "url","urls": ["https://www.finn.no/job/search?q=developer&extent=3947&location=1.20001.20061","https://www.finn.no/job/ad/471234567"],"skipSponsored": true,"maxListings": 200}
Daily monitoring: only what changed since yesterday (uncapped so a complete scan is possible):
{"mode": "search","queries": ["developer"],"location": "1.20001.20061","incrementalMode": true,"maxListings": 0}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/finn-no-jobs-scraper").call(run_input={"mode": "search","queries": ["developer"],"location": "1.20001.20061",})for listing in client.dataset(run["defaultDatasetId"]).iterate_items():print(listing["title"], listing["employer"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/finn-no-jobs-scraper').call({mode: 'search',queries: ['developer'],location: '1.20001.20061',});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
Caps: Max listings and Max pages
Max listings stops the whole run once that many records have been collected, split fairly across every keyword in a multi-keyword search; it defaults to 20 when left empty, only an explicit 0 means unlimited. Max pages limits how many search-result pages are walked per keyword (or per pasted URL); each page holds up to about 50 ads. Leave Max pages empty or at 0 for no page limit, and set Max listings to 0 for no item limit, to walk every result page Finn.no has for that search.
Resume and recurring updates
There are two different things here, pick the one that matches what you're doing:
| Need | Use |
|---|---|
| A crawl stopped and should continue | resumeFromRunId, plus automatic checkpoint recovery |
| Run the same search every day and receive only changes | incrementalMode |
| Keep separate daily campaigns for similar searches | distinct stateKey values |
| A normal full snapshot | leave 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. This also works for a full re-walk of the same search, not only for a pasted list of single-ad URLs: a leading page whose listings were already collected by the earlier run is walked through rather than stopping the search immediately. If new ads have shifted into those same early pages since the earlier run, the walk can still end once it hits a page with no new listings at all, so resume soon after the interruption for the most complete result. 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 that; 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 and UPDATED (with changedFields listing what changed); unchanged listings are suppressed and not billed unless emitUnchanged is on. REAPPEARED and EXPIRED are opt-in and cannot happen by default: turning on emitExpired marks a listing EXPIRED only once a run has completed a full, uncapped scan of the tracked search with no resumeFromRunId involved; only a listing that a complete emitExpired scan marked no longer present can later come back as REAPPEARED on a subsequent run that finds it again. If emitExpired has never been turned on, or a run never completes a full scan, no listing is ever marked EXPIRED, and REAPPEARED never occurs either. State is isolated per search/URL setup and per fetchDetails setting, so toggling detail fetching starts a fresh baseline instead of diffing detail fields against a card-only snapshot. Set stateKey to name or deliberately share a monitoring campaign.
Scheduled-run example, same search run daily:
Day 1 (first run ever for this search): every listing comes back as "changeType": "NEW".
Day 2 (the schedule fires again, identical input): brand-new postings come back as "changeType": "NEW", listings whose title, deadline or other fields changed come back as "changeType": "UPDATED" with changedFields naming what changed, and listings still there and unchanged are not returned at all unless emitUnchanged is on. Nothing is marked REAPPEARED or EXPIRED in this example, because emitExpired was never turned 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.
- Authorize a connector once under Apify, then Settings, then Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto 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.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search (use the builder fields below) or url (paste finn.no/job URLs). |
queries | array | prefill: ["developer"] | Search mode only, ignored in URL mode. Free-text search terms; one search per keyword. Empty runs a browse with no keyword filter. |
location | string | (empty) | Search mode only, ignored in URL mode. Finn.no hierarchical location code from ?location= on finn.no/job, for example 1.20001.20061 for Oslo. |
employmentType | string | fulltime | Search mode only; a pasted URL's own extent/manager_role parameter is read instead. any, fulltime (Heltid), parttime (Deltid) or management (Lederstillinger). |
industry | string | (empty) | Search mode only, ignored in URL mode. Finn.no industry code from ?industry=. |
occupation | string | (empty) | Search mode only, ignored in URL mode. Finn.no occupation/job-function code from ?occupation=. |
sector | string | any | Search mode only, ignored in URL mode. any, private or public. |
workLanguage | string | any | Search mode only, ignored in URL mode. Workplace working language filter. |
publishedSince | string | any | Search mode only, ignored in URL mode. Limit to ads posted within the last N days. |
sortBy | string | default | Search mode only; a pasted URL keeps whatever ?sort= it already carries. default (relevance), published_desc (newest) or deadline_asc (closest deadline). |
urls | array | prefill: one example URL | URL mode only, ignored in search mode. One or more finn.no/job URLs; each is paged forward independently. The search-builder fields above are ignored in this mode. |
skipSponsored | boolean | false | Applies in both modes. Drop "Betalt plassering" cards after fetch, including from a pasted URL's results. |
maxPages | integer | (empty) | Max search-result pages per keyword (or per pasted URL). Leave empty, or 0, to walk every page Finn.no has. |
maxListings | integer | 20 | Stop after this many listings across all searches. 0 means unlimited, still bounded by maxPages. |
fetchDetails | boolean | true | Fetch full ad details: description, deadline, employer details, sector, industries, working languages, contact persons, keywords and apply URL. |
resumeFromRunId | string | (empty) | A previous run ID or dataset ID to continue a full-catalogue walk. Listings already collected there (matched by id) are skipped. |
incrementalMode | boolean | false | Recurring monitoring of this same search. First run returns everything as NEW; later runs return only NEW/UPDATED by default. |
stateKey | string | (empty) | Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. |
emitUnchanged | boolean | false | Incremental mode only. Also return (and bill) listings unchanged since the last run, marked UNCHANGED. |
emitExpired | boolean | false | Incremental mode only. Also return (and bill) listings no longer found, marked EXPIRED, once a run has fully scanned the tracked search. |
proxy | object | prefill: useApifyProxy: true | Connection settings. For higher volume or Norway-pinned routing, add apifyProxyGroups: ["RESIDENTIAL"], apifyProxyCountry: "NO". |
mcpConnectors | array | (empty) | Optional: send a summary of each record to apps you authorized under Integrations. |
notionParentPageUrl | string | (empty) | Notion connector only: page under which item pages are created. |
maxNotifyListings | integer | 50 | Cap on items written to each connector per run. Does not affect the dataset. |
Output Example
Sample shape: values are illustrative placeholders, not from a live ad.
{"id": "471234567","idInt": 471234567,"url": "https://www.finn.no/job/ad/471234567","title": "Backend-utvikler","subtitle": "Bygg skyplattformer for norske kunder","employer": "Nordlys Data AS","employerUrl": "https://www.example-employer.no/","employerHomepage": "https://www.example-employer.no/","employerLogo": "https://images.finncdn.no/dynamic/default/0000/0/0/000000_0000000000.png","streetAddress": "Storgata 12","postalCode": "0150","city": "Oslo","addressCountry": "NO","locationDisplay": "Oslo","locationLink": "https://www.finn.no/job/search?location=1.20001.20061","latitude": 59.9139,"longitude": 10.7522,"datePosted": "2026-02-08","datePostedEpochMs": 1770508800000,"relativePosted": "2 dager siden","applicationDeadline": "2026-03-10","applicationDeadlineEpochMs": 1773100800000,"applicationDeadlineRaw": "10.03.2026","lastModified": "2026-02-09T14:00:00.000+02:00","lastModifiedEpochMs": 1770638400000,"employmentForm": "Fast","employmentType": ["FULL_TIME"],"employmentTypeRequested": "fulltime","sector": "Privat","industries": ["IT", "Telekommunikasjon"],"jobFunction": "Systemutvikling","internalJobTitle": "Backend Engineer II","workingLanguages": ["Norsk", "Engelsk"],"contactPersons": [{ "name": "Kari Fjeldstad", "phones": ["+4791234567"], "emails": ["kari.fjeldstad@example-employer.no"] }],"keywords": ["backend", "kotlin", "cloud"],"applyUrl": "https://www.example-employer.no/careers/471234567","descriptionHtml": "<p>Full HTML ad description goes here.</p>","descriptionText": "Full ad description as plain text goes here.","breadcrumb": ["FINN", "Jobb", "Sok", "Oslo"],"sponsored": false,"scrapedAt": "2026-02-10T08:00:00.000Z"}
Plan Requirement
The default proxy setting works out of the box, and the run automatically retries with a different connection when one is refused. For larger or more frequent runs, set the proxy field to apifyProxyGroups: ["RESIDENTIAL"], apifyProxyCountry: "NO" for steadier Norway-pinned routing. You can also paste your own proxy URLs in the proxy field.
FAQ
How much does it cost?
You pay for the Apify run itself and per record returned; turning "Fetch detail pages" on or off does not change the per-record price. The Pricing tab shows current rates. Use Max listings (and Max pages) to cap the cost of any run.
Is it legal to scrape Finn.no?
This actor collects only publicly available job listing data. You are responsible for how you use it: follow Finn.no's terms and the laws that apply to you, and get legal advice if you plan to store or redistribute employer and contact details commercially.
Can I get only new or changed listings on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new and updated listings, and unchanged ones are suppressed and not billed unless you turn on "Emit unchanged".
Why did my run return an empty dataset instead of failing?
If Finn.no's pages could not be read on every attempt, the run still finishes normally with an empty dataset rather than failing outright, but its status message says so explicitly, distinguishing that from a genuinely empty search (zero matches for your filters) or a page layout change. Check the status message, retry, or switch the proxy input to the residential group with Norway as the exit. The run does still fail outright for a few input problems unrelated to blocking: an unreadable resumeFromRunId, combining it with incrementalMode on a search that already has saved state, or the actor's connection setup itself failing at startup.
Does Resume work for a full search, or only for pasted single-ad URLs?
Both. Pasting a previous run or dataset ID into resumeFromRunId skips every listing already collected there, whether you're resuming a list of single ads or re-walking the same keyword search: an already-collected leading page is walked through rather than stopping the search immediately. If new ads have shifted into those same early pages since the earlier run, the walk can still end once it hits a page with no new listings at all, so resume soon after the interruption for the most complete result.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push a summary of results into Notion, Linear or Airtable.
๐ Want more classifieds data?
Pair this actor with these related scrapers from the same team:
| ๐ท๏ธ Leboncoin FR Pull public leboncoin.fr listings across cars, property, jobs, electronics, furniture... | ๐ท๏ธ Subito.it Scrape Subito.it listings across cars, real estate, marketplace, jobs, and more. Search... |
| ๐ท๏ธ Craigslist Scraper Scrape Craigslist postings in any of 700+ cities worldwide: price, title, posting text... | ๐ท๏ธ 2dehands & 2ememain Scrape classifieds from 2dehands.be and 2ememain.be by keyword, filters, or URLs. Returns... |
| ๐ท๏ธ Kijiji.ca Scraper Scrape Kijiji.ca listings across property, vehicles, jobs, electronics, furniture... | ๐ท๏ธ OLX Global From $1/1K. Fast OLX scraper across 9 countries, including Poland, Romania, Portugal... |
๐ Browse all abotapi scrapers
๐ฌ Support & custom scrapers
- ๐ Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- ๐ ๏ธ Need another site, extra fields or a private build? Email abotapi@proton.me or message Telegram @abotapi.
- โญ Enjoying it? A quick review on the actor page helps other users find it.