# Duunitori Jobs Scraper (`solidcode/duunitori-fi-scraper`) Actor

\[💰 $1.8 / 1K] Extract job listings from Duunitori, Finland's largest job board. Search by keyword, location, category, employment type, remote work, and ad language, or paste search URLs. Returns title, company, location, salary, posting date, description, and apply link — one row per job.

- **URL**: https://apify.com/solidcode/duunitori-fi-scraper.md
- **Developed by:** [SolidCode](https://apify.com/solidcode) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.80 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Duunitori Jobs Scraper

Pull job listings from Duunitori — Finland's largest job board, with 18,000+ live postings — including title, company, location, declared monthly salary in EUR, posting and closing dates, and the direct apply link to each employer's application system. Filter across 24 job categories, three ad languages, employment and contract type, and remote-only roles, or paste a Duunitori search URL and have its filters honored verbatim. Built for Finnish recruiters, labor-market analysts, and relocating job seekers who need clean, structured Duunitori data without copy-pasting listings one page at a time.

### Why This Scraper?

- **24 mapped job categories** — pick from clean English titles (IT, Industry & technology, Sales & commerce, Healthcare, Construction, Social & care work, and 18 more); the actor translates each to Duunitori's exact Finnish field name for you, umlauts and all.
- **Three ad-language filter** — return only Finnish, Swedish, or English-language ads — the relocation/expat power move for finding roles you can actually apply to in English.
- **Declared salary parsed to EUR/month** — when an employer publishes pay, you get `salaryMin`, `salaryMax`, `salaryCurrency`, and `salaryPeriod` as structured numbers, not a free-text blob to clean up later.
- **Direct employer apply link** — `applyUrl` captures the external link straight into the employer's own application system or ATS, not just the Duunitori listing page.
- **Employment + contract type as separate filters** — full-time vs part-time *and* permanent / fixed-term / summer job, exposed as two independent dropdowns instead of buried in free text.
- **"Also search ad text" recall switch** — match your keyword inside the full ad body, not just the title; a single niche term can jump from a handful of title hits to thousands of body matches.
- **Phone numbers pulled from the ad** — `extractedPhones` surfaces contact numbers written into the description, ready for recruiter or sales outreach.
- **Paste-a-URL seeding** — dial in any search on Duunitori's own site, paste the URL, and every filter baked into it is respected exactly as-is — no rebuilding the query by hand.
- **Per-job-ID deduplication** — each listing is returned once even when it appears across multiple pages or keyword searches, keyed on the stable Duunitori job ID.

### Use Cases

**Recruitment & Talent Sourcing**
- Track which competitors are actively hiring and for which roles
- Build candidate-outreach lists filtered by city, category, and language
- Monitor newest postings in your specialty with the "Newest first" sort
- Spot summer-job and fixed-term openings ahead of seasonal hiring waves

**Labor-Market & Salary Research**
- Benchmark Finnish wages from employer-declared EUR/month salary ranges
- Measure hiring demand by category, region, or employment type over time
- Quantify how many roles are offered as remote across industries
- Compare full-time vs part-time and permanent vs fixed-term mix by sector

**Lead Generation**
- Treat companies that are actively hiring as growth signals for B2B prospecting
- Pull apply links and ad phone numbers for direct outreach
- Segment target accounts by location and job field
- Find fast-growing employers posting across multiple categories at once

**Job-Aggregator & Niche Board Feeds**
- Power a vertical job board with fresh Finnish listings on a schedule
- Feed a candidate-matching engine with structured title, category, and location
- Keep an internal opportunity dashboard current with daily pulls

**Relocation & Expat Job Search**
- Filter to English-language ads only to surface roles open to non-Finnish speakers
- Focus on Helsinki, Tampere, or any city while keeping the language filter on
- Combine remote-only with English ads to find location-flexible openings

### Getting Started

#### Simple Keyword Search

Search a single keyword across all of Finland:

```json
{
    "searchQueries": ["ohjelmistokehittäjä"],
    "maxResults": 50
}
````

#### Keyword + Location + Category + Language

Narrow to English-language IT roles in Helsinki:

```json
{
    "searchQueries": ["developer"],
    "location": "Helsinki",
    "category": "teollisuus ja teknologia (ala)",
    "language": "eng_lang",
    "maxResults": 100
}
```

#### Direct URL with Full Details

Paste a dialed-in Duunitori search URL and enrich every result:

```json
{
    "startUrls": [
        "https://duunitori.fi/tyopaikat?haku=sairaanhoitaja&alue=Tampere&filter_work_type=full_time"
    ],
    "fetchDescription": true,
    "sortBy": "date",
    "maxResults": 300
}
```

### Input Reference

#### Search

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `searchQueries` | string\[] | `["ohjelmistokehittäjä"]` | Job titles or keywords to search for. Each keyword runs its own search. Leave empty for the broadest result set. Up to 50 keywords per run. |
| `location` | string | `""` | City or region in Finland (e.g. "Helsinki", "Tampere", "Turku", "Oulu"). Empty searches the whole country. Applies to every keyword. |
| `startUrls` | string\[] | `[]` | Paste full Duunitori search-result URLs. Any filters baked into the URL are respected as-is. Up to 50 URLs per run. |

#### Filters & Limits

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `category` | select | `Any category` | Limit to one of 24 Duunitori job fields (IT, sales, healthcare, construction, and more), shown with English titles. |
| `employmentType` | select | `Any` | Full-time or part-time. |
| `contractType` | select | `Any` | Permanent, fixed-term, or summer job. |
| `remoteOnly` | boolean | `false` | Only return roles that can be done remotely. |
| `language` | select | `Any` | Only return ads written in Finnish, Swedish, or English. |
| `searchDescriptions` | boolean | `false` | Also match keywords inside the full ad text, not just the title — broadens results. |
| `sortBy` | select | `Best match` | Order results by best match or newest first. |
| `maxResults` | integer | `100` | Maximum listings to collect across all keywords and URLs. Set to 0 to collect all available. Keeps the full final page, so a small cap can slightly overshoot. |
| `onlyUniqueJobs` | boolean | `true` | Return each job once, deduplicated by its job ID across pages and searches. |

#### Output

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `fetchDescription` | boolean | `true` | Fetch the full description, salary, dates, and apply link from each job's detail page. Turn off for lighter, faster records with just titles, companies, locations, and links. |

### Output

Each row is one job posting. Here's a representative result with full details enabled:

```json
{
    "jobId": "20316302",
    "title": "Full Stack -kehittäjä, Yle-sovellus ja yle.fi",
    "company": "Yle",
    "companyLogoUrl": "https://duunitori.imgix.net/media/next/f5408481.jpg?w=177",
    "location": "Helsinki",
    "municipality": "Helsinki",
    "region": "Uusimaa",
    "latitude": 60.1699,
    "longitude": 24.9384,
    "salaryText": "4200–5000 EUR / month",
    "salaryMin": 4200,
    "salaryMax": 5000,
    "salaryCurrency": "EUR",
    "salaryPeriod": "MONTH",
    "employmentType": "Full-time",
    "contractType": "Fixed-term",
    "category": "tieto- ja tietoliikennetekniikka",
    "occupation": "ohjelmistokehittäjä",
    "remoteWork": true,
    "description": "Haemme frontend-painotteista full stack -kehittäjää...",
    "descriptionHtml": "<p>Haemme frontend-painotteista...</p>",
    "url": "https://duunitori.fi/tyopaikat/tyo/full-stack-kehittaja-yle-20316302",
    "applyUrl": "https://yle.rekrytointi.com/paikat/?o=A_RJ&jgid=1",
    "postedDate": "2026-05-29",
    "validThrough": "2026-06-30",
    "extractedEmails": ["rekry@yle.fi"],
    "extractedPhones": ["+358401234567"],
    "searchQuery": "ohjelmistokehittäjä",
    "scrapedAt": "2026-06-11T21:14:43+00:00"
}
```

#### Core Fields

| Field | Type | Description |
|-------|------|-------------|
| `jobId` | string | Stable Duunitori listing ID — the cross-page dedup key. |
| `title` | string | Job title, properly cased. |
| `company` | string | Employer or recruiter name. |
| `companyLogoUrl` | string | Company logo image URL. |
| `category` | string | The listing's own job-field tag (free-form), distinct from the Job Category input filter. |
| `url` | string | Canonical Duunitori job URL. |

#### Location

| Field | Type | Description |
|-------|------|-------------|
| `location` | string | Location text as shown on the listing. |
| `municipality` | string | Normalized city / municipality when parseable. |
| `region` | string | Region or area when available. |
| `latitude` | number | Latitude when published. |
| `longitude` | number | Longitude when published. |

#### Salary (when declared)

| Field | Type | Description |
|-------|------|-------------|
| `salaryText` | string | Human-readable salary summary (range, currency, and pay period). |
| `salaryMin` | number | Parsed minimum salary. |
| `salaryMax` | number | Parsed maximum salary. |
| `salaryCurrency` | string | Currency code (typically EUR). |
| `salaryPeriod` | string | Pay period — usually MONTH. |

#### Detail Fields (with `fetchDescription` on)

| Field | Type | Description |
|-------|------|-------------|
| `employmentType` | string | Full-time / part-time. |
| `contractType` | string | Permanent / fixed-term / summer job — reflects the Contract Type filter you applied, when set. |
| `occupation` | string | Occupation or role classification. |
| `remoteWork` | boolean | Whether the role can be done remotely. |
| `description` | string | Full job description, plain text. |
| `descriptionHtml` | string | Full job description, HTML. |
| `applyUrl` | string | Direct link to the employer's application system. |
| `postedDate` | string | Publication date (ISO). |
| `validThrough` | string | Listing closing / expiry date. |
| `extractedEmails` | string\[] | Emails found in the ad body. |
| `extractedPhones` | string\[] | Phone numbers found in the ad body. |

#### Provenance

| Field | Type | Description |
|-------|------|-------------|
| `searchQuery` | string | The keyword or URL that surfaced this row. |
| `scrapedAt` | string | ISO timestamp the row was collected. |

### Tips for Best Results

- **Turn on "Also search ad text" to catch hidden matches** — a skill like "Kubernetes" often appears in the body of an ad but not its title; this switch can take a niche keyword from a handful of hits to thousands.
- **Use the English-language filter for expat searches** — set `language` to English to instantly surface only the roles open to non-Finnish speakers, skipping ads you can't act on.
- **Let the category dropdown do the translation** — the 24 categories use plain English titles in the UI, and the actor maps each to Duunitori's exact Finnish field name behind the scenes, so you never have to type Finnish.
- **Keep `fetchDescription` on for salary and apply links** — declared EUR/month pay, closing dates, and the direct apply URL all live on the detail page; turn it off only when you want a fast, lightweight list.
- **Sort by "Newest first" for monitoring** — pair `sortBy: "date"` with a scheduled run to catch fresh postings the moment they appear.
- **Combine keywords with location and filters** — every keyword inherits your location, category, and type filters, so one run can sweep several titles across the same target market.
- **Start small, then scale** — run with `maxResults: 50` first to confirm the data fits your needs, then raise the cap.

### Pricing

**From $1.80 per 1,000 results** — a flat per-result rate that undercuts comparable Finnish job extractors. No compute or time-based charges — you pay per result, plus a small fixed per-run start fee. Bronze, Silver, and Gold subscribers pay progressively less; the table below shows total cost at each discount tier.

| Results | No discount | Bronze | Silver | Gold |
|---------|-------------|--------|--------|------|
| 100 | $0.21 | $0.20 | $0.19 | $0.18 |
| 1,000 | $2.10 | $2.00 | $1.90 | $1.80 |
| 10,000 | $21.00 | $20.00 | $19.00 | $18.00 |
| 100,000 | $210.00 | $200.00 | $190.00 | $180.00 |

A "result" is any job row in the output dataset.

### Integrations

Export data in JSON, CSV, Excel, XML, or RSS. Connect to 1,500+ apps via:

- **Zapier** / **Make** / **n8n** — Workflow automation
- **Google Sheets** — Direct spreadsheet export
- **Slack** / **Email** — Notifications on new results
- **Webhooks** — Trigger custom APIs on run completion
- **Apify API** — Full programmatic access

### Legal & Ethical Use

This actor is designed for legitimate recruitment research, labor-market analysis, and lead generation. You are responsible for complying with applicable laws and Duunitori's Terms of Service. Do not use extracted data for spam, harassment, or any unlawful purpose, and handle any personal data found in job ads in line with GDPR and other privacy regulations.

# Actor input Schema

## `searchQueries` (type: `array`):

Job titles or keywords to search for, such as 'ohjelmistokehittäjä', 'myyjä', or 'sairaanhoitaja'. Each keyword runs its own search. Leave empty to collect the broadest result set for the chosen location and filters. Up to 50 keywords per run.

## `location` (type: `string`):

City or region in Finland to search in, such as 'Helsinki', 'Tampere', 'Turku', or 'Oulu'. Matches what you would type into Duunitori's location box. Leave empty to search the whole country. Applies to every search keyword.

## `startUrls` (type: `array`):

Paste full Duunitori search-result URLs (e.g. https://duunitori.fi/tyopaikat?haku=ohjelmistokehittaja\&alue=Helsinki) to scrape them directly. Useful when you have already dialed in a search on the website — any filters baked into the URL are respected as-is. Up to 50 URLs per run.

## `category` (type: `string`):

Limit results to one Duunitori job field. Leave on 'Any' to include all categories.

## `employmentType` (type: `string`):

Full-time or part-time. Leave on 'Any' to include both.

## `contractType` (type: `string`):

Permanent, fixed-term, or summer job. Leave on 'Any' to include all.

## `remoteOnly` (type: `boolean`):

Only return jobs that can be done remotely. Leave off to include on-site and hybrid roles too.

## `language` (type: `string`):

Only return job ads written in this language. Leave on 'Any' to include all languages.

## `searchDescriptions` (type: `boolean`):

Also match your keywords inside the full job-ad text, not just the title. Broadens results — turn on when a keyword returns too few jobs.

## `sortBy` (type: `string`):

Order results by best match or by newest first.

## `maxResults` (type: `integer`):

Maximum number of job listings to collect across all keywords and URLs. Set to 0 to collect all available results (an internal upper bound still applies to prevent runaway pagination). Listings are fetched page by page: the actor stops once your cap is reached but keeps the whole final page, so a small cap can return up to a full page more than you asked for. Jobs repeated across pages are deduplicated, so the final count can also run slightly below your cap.

## `onlyUniqueJobs` (type: `boolean`):

When on, each job is returned once even if Duunitori lists it across several pages or searches. Deduplicates by the listing's job ID. Turn off to keep every copy.

## `fetchDescription` (type: `boolean`):

Fetch the full job description, salary, employment details, expiry date, and apply link from each job's detail page. Leave on for the most complete data. Turn off for lighter, faster records when you only need titles, companies, locations, and links from the results list.

## Actor input object example

```json
{
  "searchQueries": [
    "ohjelmistokehittäjä"
  ],
  "startUrls": [],
  "category": "",
  "employmentType": "",
  "contractType": "",
  "remoteOnly": false,
  "language": "",
  "searchDescriptions": false,
  "sortBy": "relevance",
  "maxResults": 100,
  "onlyUniqueJobs": true,
  "fetchDescription": true
}
```

# Actor output Schema

## `overview` (type: `string`):

Table of scraped job listings with key fields like title, company, location, salary, and posting date.

## `detail` (type: `string`):

Complete job data including full descriptions, parsed salary fields, employment and contract types, dates, and apply links.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchQueries": [
        "ohjelmistokehittäjä"
    ],
    "location": "",
    "startUrls": [],
    "category": "",
    "employmentType": "",
    "contractType": "",
    "remoteOnly": false,
    "language": "",
    "searchDescriptions": false,
    "sortBy": "relevance",
    "maxResults": 100,
    "onlyUniqueJobs": true,
    "fetchDescription": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("solidcode/duunitori-fi-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchQueries": ["ohjelmistokehittäjä"],
    "location": "",
    "startUrls": [],
    "category": "",
    "employmentType": "",
    "contractType": "",
    "remoteOnly": False,
    "language": "",
    "searchDescriptions": False,
    "sortBy": "relevance",
    "maxResults": 100,
    "onlyUniqueJobs": True,
    "fetchDescription": True,
}

# Run the Actor and wait for it to finish
run = client.actor("solidcode/duunitori-fi-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "ohjelmistokehittäjä"
  ],
  "location": "",
  "startUrls": [],
  "category": "",
  "employmentType": "",
  "contractType": "",
  "remoteOnly": false,
  "language": "",
  "searchDescriptions": false,
  "sortBy": "relevance",
  "maxResults": 100,
  "onlyUniqueJobs": true,
  "fetchDescription": true
}' |
apify call solidcode/duunitori-fi-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=solidcode/duunitori-fi-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Duunitori Jobs Scraper",
        "description": "[💰 $1.8 / 1K] Extract job listings from Duunitori, Finland's largest job board. Search by keyword, location, category, employment type, remote work, and ad language, or paste search URLs. Returns title, company, location, salary, posting date, description, and apply link — one row per job.",
        "version": "1.0",
        "x-build-id": "PLiJMXWGZjAcA6QcY"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/solidcode~duunitori-fi-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-solidcode-duunitori-fi-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/solidcode~duunitori-fi-scraper/runs": {
            "post": {
                "operationId": "runs-sync-solidcode-duunitori-fi-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/solidcode~duunitori-fi-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-solidcode-duunitori-fi-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchQueries": {
                        "title": "Search Keywords",
                        "maxItems": 50,
                        "type": "array",
                        "description": "Job titles or keywords to search for, such as 'ohjelmistokehittäjä', 'myyjä', or 'sairaanhoitaja'. Each keyword runs its own search. Leave empty to collect the broadest result set for the chosen location and filters. Up to 50 keywords per run.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "location": {
                        "title": "Location",
                        "type": "string",
                        "description": "City or region in Finland to search in, such as 'Helsinki', 'Tampere', 'Turku', or 'Oulu'. Matches what you would type into Duunitori's location box. Leave empty to search the whole country. Applies to every search keyword."
                    },
                    "startUrls": {
                        "title": "Direct Duunitori URLs",
                        "maxItems": 50,
                        "type": "array",
                        "description": "Paste full Duunitori search-result URLs (e.g. https://duunitori.fi/tyopaikat?haku=ohjelmistokehittaja&alue=Helsinki) to scrape them directly. Useful when you have already dialed in a search on the website — any filters baked into the URL are respected as-is. Up to 50 URLs per run.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "category": {
                        "title": "Job Category",
                        "enum": [
                            "",
                            "asennus, huolto ja kunnossapito (ala)",
                            "asiakaspalvelu (ala)",
                            "asiantuntijatyöt ja konsultointi (ala)",
                            "hallinto ja yleiset toimistotyöt (ala)",
                            "henkilöstöala (ala)",
                            "hyvinvointi- ja henkilöpalvelut (ala)",
                            "johtotehtävät (ala)",
                            "julkinen sektori ja järjestöt (ala)",
                            "kiinteistöala (ala)",
                            "kuljetus, logistiikka ja liikenne (ala)",
                            "kulttuuri-, viihde- ja taidealat (ala)",
                            "lakiala (ala)",
                            "markkinointi (ala)",
                            "markkinointi, mainonta, media ja viestintä (ala)",
                            "myynti- ja kaupan ala (ala)",
                            "opetusala (ala)",
                            "opiskelijoiden työpaikat (ala)",
                            "rakennusala (ala)",
                            "ravintola- ja matkailuala (ala)",
                            "siivous, puhtaanapito ja jätehuolto (ala)",
                            "sosiaali- ja hoiva-ala (ala)",
                            "taloushallinto ja pankkiala (ala)",
                            "teollisuus ja teknologia (ala)",
                            "terveydenhuoltoala (ala)"
                        ],
                        "type": "string",
                        "description": "Limit results to one Duunitori job field. Leave on 'Any' to include all categories.",
                        "default": ""
                    },
                    "employmentType": {
                        "title": "Employment Type",
                        "enum": [
                            "",
                            "full_time",
                            "part_time"
                        ],
                        "type": "string",
                        "description": "Full-time or part-time. Leave on 'Any' to include both.",
                        "default": ""
                    },
                    "contractType": {
                        "title": "Contract Type",
                        "enum": [
                            "",
                            "permanent",
                            "fixed_term",
                            "summer_job"
                        ],
                        "type": "string",
                        "description": "Permanent, fixed-term, or summer job. Leave on 'Any' to include all.",
                        "default": ""
                    },
                    "remoteOnly": {
                        "title": "Remote Only",
                        "type": "boolean",
                        "description": "Only return jobs that can be done remotely. Leave off to include on-site and hybrid roles too.",
                        "default": false
                    },
                    "language": {
                        "title": "Ad Language",
                        "enum": [
                            "",
                            "fi_lang",
                            "swe_lang",
                            "eng_lang"
                        ],
                        "type": "string",
                        "description": "Only return job ads written in this language. Leave on 'Any' to include all languages.",
                        "default": ""
                    },
                    "searchDescriptions": {
                        "title": "Also Search Ad Text",
                        "type": "boolean",
                        "description": "Also match your keywords inside the full job-ad text, not just the title. Broadens results — turn on when a keyword returns too few jobs.",
                        "default": false
                    },
                    "sortBy": {
                        "title": "Sort By",
                        "enum": [
                            "relevance",
                            "date"
                        ],
                        "type": "string",
                        "description": "Order results by best match or by newest first.",
                        "default": "relevance"
                    },
                    "maxResults": {
                        "title": "Maximum Results",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum number of job listings to collect across all keywords and URLs. Set to 0 to collect all available results (an internal upper bound still applies to prevent runaway pagination). Listings are fetched page by page: the actor stops once your cap is reached but keeps the whole final page, so a small cap can return up to a full page more than you asked for. Jobs repeated across pages are deduplicated, so the final count can also run slightly below your cap.",
                        "default": 100
                    },
                    "onlyUniqueJobs": {
                        "title": "Only Unique Jobs",
                        "type": "boolean",
                        "description": "When on, each job is returned once even if Duunitori lists it across several pages or searches. Deduplicates by the listing's job ID. Turn off to keep every copy.",
                        "default": true
                    },
                    "fetchDescription": {
                        "title": "Fetch Full Job Descriptions",
                        "type": "boolean",
                        "description": "Fetch the full job description, salary, employment details, expiry date, and apply link from each job's detail page. Leave on for the most complete data. Turn off for lighter, faster records when you only need titles, companies, locations, and links from the results list.",
                        "default": true
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
