# NoFluffJobs Scraper – Jobs & Salary Data (`muhammadafzal/nofluffjobs-scraper`) Actor

Extract NoFluffJobs jobs with salary ranges, skills, seniority, locations, benefits, and recruitment steps for hiring research and market analysis.

- **URL**: https://apify.com/muhammadafzal/nofluffjobs-scraper.md
- **Developed by:** [Muhammad Afzal](https://apify.com/muhammadafzal) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 scraped nofluffjobs jobs

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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## NoFluffJobs Scraper

**Free plan limit:** Free-plan users can receive up to **5 result records per run**. Paid-plan and local/unknown runs retain the Actor's existing limits.

Extract public NoFluffJobs job listings, salary contracts, skills, locations, benefits, and recruitment details into an analysis-ready dataset.

This Actor is designed for recruiters, compensation analysts, job-market researchers, ATS teams, and developers who need structured NoFluffJobs data without copying pages manually. It reads the same public JSON listing and job-detail routes used by the website; no NoFluffJobs login, cookies, or separate API key are required.

### What it extracts

| Field group | Examples |
| --- | --- |
| Job identity | Job ID, title, category, seniority, canonical URL |
| Company | Company name, website, employee-count band |
| Location | Cities, countries, remote flag, hybrid-work description |
| Compensation | Minimum, maximum, currency, period, and all contract types |
| Requirements | Primary technology, must-have skills, nice-to-have skills, languages |
| Role details | Description, requirements text, daily tasks |
| Hiring details | Benefits, office perks, recruitment steps, online-interview flag |
| Lifecycle | Posted time, expiry time, scrape time, public detail API URL |

The default dataset contains only homogeneous `job` records. Run diagnostics and warnings are stored separately in the `OUTPUT` key-value record, so downstream automations do not need to filter error rows from job data.

### When to use it

Use this Actor to:

- monitor European technology hiring and published compensation;
- find companies hiring for a stack such as Python, React, AWS, or Kubernetes;
- compare salary ranges by category, seniority, location, contract type, or currency;
- synchronize public vacancies into an internal search index or ATS review queue;
- create recruiting, workforce-planning, or hiring-trend datasets.

Do not use it to apply for jobs automatically, collect private candidate information, bypass access controls, or republish content without checking the source terms and applicable law.

### Input

| Field | Type | Default | Purpose |
| --- | --- | --- | --- |
| `startUrls` | URL array | `[]` | Individual job URLs or regional/category pages such as `https://nofluffjobs.com/pl/backend` |
| `keywords` | string array | `[]` | Match any keyword in title, company, technology, or visible skill tiles |
| `region` | enum | `pl` | Market: `pl`, `cz`, `sk`, `hu`, or `ua` |
| `categories` | string array | `['backend']` | One or more NoFluffJobs category slugs; empty means all |
| `seniority` | string array | `[]` | `Trainee`, `Junior`, `Mid`, `Senior`, `Lead`, or `Expert` |
| `remoteOnly` | boolean | `false` | Keep only listings marked remote |
| `salaryCurrency` | enum | `PLN` | Currency used for list-level salary display |
| `salaryPeriod` | enum | `month` | Monthly or hourly list-level salary display |
| `enrichDetails` | boolean | `true` | Fetch descriptions, contracts, benefits, and recruitment steps |
| `maxResults` | integer | `20` | Maximum delivered and billable jobs, from 1 to 10,000 |
| `maxPages` | integer | `50` | Maximum listing pages scanned, from 1 to 200 |
| `maxConcurrency` | integer | `8` | Simultaneous detail requests, from 1 to 20 |

Direct job URLs are always attempted. A regional/category page contributes its region and category to the search filters. Keyword filtering is case-insensitive and matches any supplied keyword.

#### Console input example

```json
{
  "keywords": ["Python", "AWS"],
  "region": "pl",
  "categories": ["backend", "data"],
  "seniority": ["Senior"],
  "remoteOnly": true,
  "enrichDetails": true,
  "maxResults": 100
}
```

#### Apify API example

```bash
curl -X POST "https://api.apify.com/v2/acts/YOUR_USERNAME~nofluffjobs-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "keywords": ["Kubernetes"],
    "region": "cz",
    "categories": ["devops"],
    "maxResults": 50
  }'
```

After the run finishes, read jobs from the default dataset or follow the `jobs` link in the Actor output. Read `OUTPUT` for the classified outcome, scan counts, and warnings.

### Output example

```json
{
  "type": "job",
  "jobId": "senior-python-engineer-acme-remote",
  "title": "Senior Python Engineer",
  "companyName": "Acme",
  "companyWebsite": "https://acme.example",
  "companySize": "50 - 99",
  "category": "backend",
  "seniority": ["Senior"],
  "locations": ["Remote, Poland"],
  "remote": true,
  "hybridDescription": null,
  "salaryMinimum": 20000,
  "salaryMaximum": 28000,
  "salaryCurrency": "PLN",
  "salaryPeriod": "month",
  "salaryContracts": [
    {
      "employmentType": "b2b",
      "minimum": 20000,
      "maximum": 28000,
      "currency": "PLN",
      "period": "month",
      "paidHoliday": false
    }
  ],
  "primaryTechnology": "Python",
  "mustHaveSkills": ["Python", "AWS"],
  "niceToHaveSkills": ["Kubernetes"],
  "languages": ["en"],
  "description": "Build and operate backend services.",
  "requirements": "Commercial Python and cloud experience.",
  "dailyTasks": ["Build APIs", "Review code"],
  "benefits": ["Private healthcare"],
  "officePerks": ["Free coffee"],
  "recruitmentProcess": ["Technical interview"],
  "onlineInterview": true,
  "applyType": "url",
  "postedAt": "2026-08-31T09:00:00.000Z",
  "expiresAt": "2026-09-30T23:59:59.000Z",
  "jobUrl": "https://nofluffjobs.com/job/senior-python-engineer-acme-remote",
  "apiUrl": "https://nofluffjobs.com/api/posting/senior-python-engineer-acme-remote",
  "scrapedAt": "2026-08-31T10:00:00.000Z"
}
```

Optional values are explicit `null` and list fields are always arrays. The shape stays stable between enriched and fast list-only runs.

### Pay-per-event pricing

This Actor uses **pay-per-event** pricing. These are the current Apify Store event prices:

| Event | Price (USD) | When it is charged |
|---|---:|---|
| `apify-actor-start` | $0.00005 | Actor Start — Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). — Charged once per run. |
| `apify-default-dataset-item` | $0.0009 | Scraped NoFluffJobs job — One validated NoFluffJobs job record written to the default dataset. |

Apify platform usage for this Actor run is included alongside the event prices above; no separate per-run platform-usage fee is passed to users.

This covers Apify platform usage for this Actor run. Other Apify products or usage outside this Actor run may still follow your account plan.

### Reliability and limits

The Actor starts with direct HTTP access to NoFluffJobs' public listing and detail JSON routes. Requests use bounded timeouts, three error-aware attempts, exponential backoff for transient errors, a conservative detail concurrency, stable deduplication by job slug, and a hard result limit.

If one detail request fails, the Actor preserves a valid list-level job when possible and records the enrichment warning in `OUTPUT`. A true no-match search returns an empty dataset with an `EMPTY` summary. A first-page access denial is classified as `BLOCKED`; malformed runtime input is `REJECTED`; unexpected defects are `FAILED`. Before every dataset write, the Actor checks whether another result event fits the run's maximum total charge. A too-low cap returns an actionable `REJECTED` summary, while a cap reached after partial delivery preserves the valid `DATA` rows. The Actor never fabricates a job row to make a run appear successful.

NoFluffJobs can change its public routes or fields. Source fields may also be unavailable for individual listings, especially salary, company website, or hybrid notes. Keyword filtering uses list-visible fields so it remains predictable and does not require fetching every detail page.

### Legal and privacy

This independent Actor is not affiliated with or endorsed by No Fluff Jobs. It accesses public job-advertisement data only and does not request candidate accounts, private profiles, authentication cookies, or application submissions. You are responsible for using the data in accordance with NoFluffJobs' terms, robots and access policies, GDPR and other privacy rules, database rights, copyright, and applicable local law. Minimize retention and avoid using scraped job data for unlawful discrimination, spam, or automated decisions about individuals.

### Support

For a reproducible issue, include the Actor run ID, redacted input, expected outcome, and the affected public job URL. Do not include Apify tokens, cookies, candidate data, or other secrets.

### Pricing

This Actor uses **pay-per-event** pricing. These are the current Apify Store event prices:

| Event | Price (USD) | When it is charged |
|---|---:|---|
| `apify-actor-start` | $0.00005 | Actor Start — Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). — Charged once per run. |
| `apify-default-dataset-item` | $0.0009 | Scraped NoFluffJobs job — One validated NoFluffJobs job record written to the default dataset. |

Apify platform usage for this Actor run is included alongside the event prices above; no separate per-run platform-usage fee is passed to users.

This covers Apify platform usage for this Actor run. Other Apify products or usage outside this Actor run may still follow your account plan.

# Changelog

This Actor's version history is a separate document: https://apify.com/muhammadafzal/nofluffjobs-scraper/changelog.md

# Actor input Schema

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

Use this for individual job or regional/category pages. Accepts URLs such as https://nofluffjobs.com/job/example-slug or https://nofluffjobs.com/pl/backend. Direct job URLs are always collected; page URLs add region/category filters.

## `keywords` (type: `array`):

Use this to keep jobs matching any title, company, technology, or visible skill keyword. Enter literal strings such as Python or Kubernetes. Empty means no keyword filter.

## `region` (type: `string`):

Use this to select the NoFluffJobs market. Choose the site region code; defaults to Poland. This is not a free-form location filter.

## `categories` (type: `array`):

Use this to keep one or more NoFluffJobs categories such as backend, frontend, data, or devops. Empty means every category.

## `seniority` (type: `array`):

Use this to keep jobs at selected experience levels. Empty means all levels; values map to the listing's seniority tags.

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

Use this to keep listings that NoFluffJobs marks as fully remote or containing a Remote location. Defaults to false and is not the same as hybrid work.

## `salaryCurrency` (type: `string`):

Use this to request list-level salary normalization from NoFluffJobs. Enter a three-letter currency such as PLN, EUR, USD, GBP, CZK, HUF, or UAH. Original detail contracts remain in their published currency.

## `salaryPeriod` (type: `string`):

Use this to request list-level salary normalization per month or hour. Original detail contracts preserve their published period.

## `enrichDetails` (type: `boolean`):

Use this to fetch each public job-detail endpoint for descriptions, contract salaries, must-have skills, benefits, and recruitment steps. Disable for faster list-only collection.

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

Use this to cap delivered and billable job records. Defaults to 20; accepted range is 1 to 10000. This is not a page limit.

## `maxPages` (type: `integer`):

Use this to bound how far keyword filters scan the public listing feed. Defaults to 50; accepted range is 1 to 200. Direct job URLs do not consume this allowance.

## `maxConcurrency` (type: `integer`):

Use this to tune simultaneous public detail requests. Defaults to 8; accepted range is 1 to 20. Higher values may trigger upstream throttling.

## Actor input object example

```json
{
  "startUrls": [],
  "keywords": [
    "Python"
  ],
  "region": "pl",
  "categories": [
    "backend"
  ],
  "seniority": [],
  "remoteOnly": false,
  "salaryCurrency": "PLN",
  "salaryPeriod": "month",
  "enrichDetails": true,
  "maxResults": 25,
  "maxPages": 50,
  "maxConcurrency": 8
}
```

# Actor output Schema

## `jobs` (type: `string`):

Structured NoFluffJobs job records.

## `summary` (type: `string`):

Outcome, counts, warnings, and scan diagnostics for this run.

# 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 = {
    "keywords": [
        "Python"
    ],
    "maxResults": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammadafzal/nofluffjobs-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 = {
    "keywords": ["Python"],
    "maxResults": 25,
}

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

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

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

```

## CLI example

```bash
echo '{
  "keywords": [
    "Python"
  ],
  "maxResults": 25
}' |
apify call muhammadafzal/nofluffjobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,muhammadafzal/nofluffjobs-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/mNznjFhZKEQ8NiDmb/builds/1LqTFfRnotn85RVtu/openapi.json
