NoFluffJobs Job Scraper avatar

NoFluffJobs Job Scraper

Pricing

from $1.19 / 1,000 results

Go to Apify Store
NoFluffJobs Job Scraper

NoFluffJobs Job Scraper

Searches NoFluffJobs listings by keyword, category, seniority, or city and returns job titles, companies, salary ranges, skills, locations, and remote status. Each distinct posting ID appears once per run, and requested salary currency and period are applied by the site.

Pricing

from $1.19 / 1,000 results

Rating

0.0

(0)

Developer

Axiom Works

Axiom Works

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

NoFluffJobs Jobs Scraper

Returns: one row per job with title, company, category, seniority, salary range, required skills, and remote status. Input: {"keyword":"python","categories":["backend"],"seniority":["senior"],"maxItems":20} Best for: tracking IT openings, comparing disclosed salaries, and building focused job research datasets.

{"id":"senior-software-engineer-python-codilime-Remote","title":"Senior Software Engineer (Python)","company":"CodiLime","category":"backend","fullyRemote":true,"salaryFrom":20500,"jobUrl":"https://nofluffjobs.com/job/senior-software-engineer-python-codilime-remote"}

What does NoFluffJobs Jobs Scraper do?

NoFluffJobs Jobs Scraper extracts public IT job listings from the NoFluffJobs search API. Give it a keyword, a category, a seniority level, a city, or a combination of filters. It returns a dataset with one row for each distinct job: when NoFluffJobs lists the same job once per location, the locations are merged into one row's cities list. A run stops at the requested maxItems count when enough unique postings exist.

The Actor reads the public search response directly. It does not sign in, submit applications, or read private account information. The API is an internal site endpoint and its response format may change. Each row includes sourceUrl, which identifies the search endpoint and page that supplied that row. The id comes from the listing itself and remains useful for comparing results from later runs.

Use this NoFluffJobs scraper when you need a repeatable collection of listings rather than a manual search page. The NoFluffJobs API response supplies structured location, salary, skill, and posting fields, so the output can be filtered and compared in a spreadsheet or a downstream program. Search filters are sent to the site; the Actor does not infer job suitability or fill gaps with invented data.

What data can you get?

The dataset contains these fields. Some jobs do not disclose every detail. Those values appear as null or, for lists, an empty array. Salary amounts reflect the currency and period requested in the input; the site performs that conversion in the search response.

FieldMeaning
idStable posting ID supplied by NoFluffJobs.
titleJob title in the search result.
companyEmployer or recruiter name.
categoryListing category, such as backend.
senioritySeniority labels supplied as an array.
salaryFromLower salary amount when displayed.
salaryToUpper salary amount when displayed.
salaryCurrencyCurrency attached to the salary.
salaryPeriodPeriod attached to the salary.
contractTypeContract type attached to the displayed salary.
mainTechnologyMain technology named on the card.
requiredSkillsSkill labels from requirement tiles.
fullyRemoteWhether the posting is marked fully remote.
citiesNamed cities associated with the posting, excluding the Remote location label.
countryCountry name from a posting location when present.
countryCodeCountry code of the posting location (for example POL), copied from the source. The source labels some Polish postings Polish instead of Poland in country, so use countryCode to filter reliably.
postedAtPosting timestamp converted to ISO 8601.
sourceUrlSearch API URL and page that supplied the row.

The search API can represent a role in several places. The Actor deduplicates by the listing ID, so a repeated ID contributes only one row and one result event in a run. Postings sharing a job reference are also merged, including their locations when they appear on the same search page. cities can therefore contain several cities even when the retained posting ID names one of them.

A missing salary is not a zero salary. The salary fields are null when the search response does not include a salary object or an amount. Similarly, an empty requiredSkills list means the result had no requirement tiles available in that response. The Actor does not visit a job detail page to retrieve additional descriptions, benefits, application details, or requirements.

How to use

Set remoteOnly to true to collect listings explicitly marked fully remote. The default is false, preserving the existing search scope. The filter uses location metadata first and falls back to the top-level remote flag if the location flag is absent. This also corrects fullyRemote for listings where the top-level flag conflicts with the location flag and workMode says remote. The Actor never infers remote status from a title or city name. Filtering occurs before reference-based deduplication and before maxItems, so the limit counts matching unique jobs. A remote-only search can read additional API pages to find enough matching jobs. If no result is found within the first-result time budget, the run succeeds with zero items and guidance to narrow the search. No detail-page request is added.

Open the Actor input form and set the filters that describe the jobs you want. For a focused search, start with a keyword and one or two categories. keyword is optional: an empty keyword with a category can browse that category. Leave category, seniority, and city arrays empty when you do not want those restrictions. Set maxItems to the number of rows needed. Start the run, then download the dataset in JSON, CSV, or Excel from the run's output.

The prefilled example searches for Python jobs in the backend category at senior level. The keyword is matched by NoFluffJobs as a technology or title term, so a title may not contain the literal word; check mainTechnology and requiredSkills. Extra fields: jobUrl (public posting page), reference, renewedAt and workMode.

The Actor requests page 1 first and uses totalPages from the response for subsequent pages. It stops when it reaches maxItems, the last reported page, or an empty page. Requests are paced at approximately one request per second between pages. If the site responds with a rate limit, server error, CAPTCHA wall, or access block, requests are retried with backoff. When an Apify Proxy is configured, each retry uses a fresh proxy session. A persistent block or unexpected search response ends the run successfully with the jobs already saved, or zero results and a status message suggesting another attempt or Apify Proxy. Block detection checks visible page text rather than script contents, avoiding retries triggered solely by anti-bot script names.

Input

All filters are optional. Defaults let the Actor browse public jobs in the Polish region. The input form prefills a narrower Python example for an immediately useful first run.

InputTypeDefaultHow it affects the search
keywordstringEmptyFree-text search matched against technology and title, e.g. python.
categoriesstring arrayEmptyCategory slugs, e.g. backend, devops.
senioritystring arrayEmptySeniority levels, e.g. senior.
citiesstring arrayEmptyCity names, e.g. Warszawa.
regionstringplTwo-letter region code for the search endpoint.
salaryCurrencystringPLNRequested salary display currency.
salaryPeriodstringmonthRequested salary display period.
remoteOnlybooleanfalseReturn only jobs marked fully remote; the limit counts matching unique jobs.
maxItemsinteger50Maximum unique rows to return, from 1 through 10000.
proxyConfigurationobjectDirect connectionApify Proxy settings for requests to NoFluffJobs.

For a search with filters, use:

{
"keyword": "python",
"categories": ["backend"],
"seniority": ["senior"],
"cities": [],
"region": "pl",
"salaryCurrency": "PLN",
"salaryPeriod": "month",
"maxItems": 20,
"proxyConfiguration": {"useApifyProxy": false}
}

For a category browse, omit keyword and provide categories, for example {"categories":["devops"],"maxItems":25}. NoFluffJobs decides which results match each submitted filter. To make comparisons across runs, use the same region, currency, period, and filter values each time. A nonsense keyword can legitimately produce an empty dataset and a warning. In that case, broaden the term or remove a restrictive filter.

salaryCurrency accepts PLN, EUR, USD, GBP, or CHF. salaryPeriod accepts month, day, hour, or year. Seniority values can be trainee, junior, mid, senior, or expert. Category and city options follow the site's search vocabulary. The Actor validates input shapes and values that have fixed choices; the site validates the actual category and location search results.

Output

This record is from a local run using the prefilled filters with maxItems: 20. It is a representative output item, not a promise that the same listing will remain available on future runs:

{
"id": "senior-software-engineer-python-codilime-Remote",
"title": "Senior Software Engineer (Python)",
"company": "CodiLime",
"category": "backend",
"seniority": [
"Senior"
],
"salaryFrom": 20500,
"salaryTo": 27000,
"salaryCurrency": "PLN",
"salaryPeriod": "Month",
"contractType": "b2b",
"mainTechnology": "Python",
"requiredSkills": [
"Python",
"AI",
"Claude Code",
"REST"
],
"fullyRemote": true,
"cities": [
"Warszawa"
],
"country": "Poland",
"countryCode": "POL",
"postedAt": "2026-09-26T22:00:35.850Z",
"sourceUrl": "https://nofluffjobs.com/api/search/posting?salaryCurrency=PLN&salaryPeriod=month&region=pl&language=en-GB&page=1",
"jobUrl": "https://nofluffjobs.com/job/senior-software-engineer-python-codilime-remote",
"reference": "UJWOC1XS",
"renewedAt": "2026-10-14T22:00:35.850Z",
"workMode": "remote"
}

The sourceUrl is an API search page, not the public job detail page. This is deliberate: every output value comes from the search result object returned by that endpoint. The id lets you reconcile rows across repeated collections. The Actor groups place-specific variants by the source reference within each page, retains the first posting ID, merges their cities, and suppresses the same reference on subsequent pages.

How much does it cost?

The Actor is charged per result pushed to the dataset. A run that returns fewer results than maxItems only has result events for the rows actually returned. Duplicate IDs and invalid records are not pushed or charged. A run with no matches returns no data rows. Check the Actor's Pricing tab for the current charge settings before running a large search.

maxItems is both a practical dataset size control and an upper bound on result events. The Actor checks the remaining item count before pushing another record. If an account spending limit is reached, it stops before saving an additional result. The requested item count is not a guarantee of availability: the site may have fewer matches or may reject a search temporarily.

Use with AI agents (MCP)

Apify MCP can expose the Actor as a tool to an AI agent. Configure the MCP server URL with the Actor's Store path:

https://mcp.apify.com?tools=axiomworks/nofluffjobs-jobs-scraper

An agent can pass the same JSON inputs shown above. The dataset provides structured fields for follow-up comparisons and summaries. The agent should treat null values as missing source information and should not assume a listing is still open without checking a current run.

Example prompts for an agent include “Find up to 20 senior backend postings in Poland and summarize the disclosed salary ranges by company,” “Collect DevOps postings and show the required skill labels that recur most often,” and “Compare the current job IDs with last week's dataset to identify newly observed postings.” Each prompt maps to fields actually returned by the Actor. For a salary comparison, ask the agent to keep currency and period consistent across the runs being compared.

The first example can use {"keyword":"python","categories":["backend"],"seniority":["senior"],"maxItems":20}. The DevOps example can use {"categories":["devops"],"maxItems":50}. A comparison across weeks requires the agent or your workflow to retain a previous dataset; the Actor itself produces the current search results and does not store a history of earlier runs.

Integrations and API

The Actor can be started from the Apify API, the Apify SDK, or an automation platform that can call the API. Replace the token placeholder in your own environment. Do not place a live token in shared scripts or reports. The examples request the input described in this README and retrieve the run's dataset items.

Python example:

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("axiomworks/nofluffjobs-jobs-scraper").call(run_input={
"keyword": "python", "categories": ["backend"], "maxItems": 20
})
items = list(client.dataset(run["defaultDatasetId"]).iterate_items())
print(len(items))

JavaScript example:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('axiomworks/nofluffjobs-jobs-scraper').call({
keyword: 'python', categories: ['backend'], maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

cURL example:

curl -X POST \
'https://api.apify.com/v2/acts/axiomworks~nofluffjobs-jobs-scraper/run-sync-get-dataset-items' \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"keyword":"python","categories":["backend"],"maxItems":20}'

For ongoing collection, schedule a run with stable filter settings and store each exported dataset with its run date. Use id to compare observed postings. postedAt is the site's posting timestamp, not the time your collection ran. If you need the collection time, keep the run metadata alongside the dataset rather than interpreting postedAt as an observation timestamp.

FAQ

Does this include full job descriptions? No. The Actor extracts fields in the search response. It does not visit detail pages, so the output contains the listed title, company, salary, skills, location, and related search fields only.

Why can a job appear for a keyword that is absent from its title? NoFluffJobs performs the search and determines matches. The Actor sends rawSearch but does not impose a second text match on the returned title. The search service may match other posting content.

Why are salary fields empty on some jobs? The source does not always disclose pay in its search object. Null means the relevant amount or salary detail was absent. It does not mean the amount is zero.

Can I search outside Poland? The region field sends a two-letter region code to the search endpoint. Availability and results depend on what NoFluffJobs serves for that code. Use the same region when comparing datasets.

How are duplicates handled? The Actor keeps one row per exact posting ID and shared job reference within a run. It merges locations for a shared reference on the same page, retains the first posting ID, and skips that reference on later pages.

What happens if the site blocks a request? The Actor retries eligible errors with backoff. If a proxy is configured, each retry uses a fresh session. Persistent errors end successfully with a clear status message when no jobs were saved; the Actor does not create placeholder job rows.

This Actor reads publicly available search results without logging in. Rules for using, retaining, and redistributing collected information depend on your location and purpose. Review the site's terms and applicable law for your use case. The Actor is an independent tool and is not affiliated with or endorsed by NoFluffJobs. It does not access private accounts or submit applications.

Feedback

If a field becomes empty after a site change, provide a run link and a sample id in the Actor's feedback channel. Include the filters used, especially region, currency, and period, because those can change what the search API returns. For repeated blocks, describe whether a proxy was enabled and which error appeared in the run log. Those details help distinguish a source format change from a temporary request failure.