# Job Posting Requirement Decoder (`mrdoe/job-posting-requirement-decoder`) Actor

Compares real job postings for the same role across multiple companies and shows which requirements are genuinely common versus inflated listing fluff, with a plain-language breakdown of what actually matters.

- **URL**: https://apify.com/mrdoe/job-posting-requirement-decoder.md
- **Developed by:** [MrDoe](https://apify.com/mrdoe) (community)
- **Categories:** Jobs
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $180.00 / 1,000 requirement comparison report returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

![Job Posting Requirement Decoder — see which job requirements are real, not inflated fluff](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/job-posting-requirement-decoder--website.png)

### What does Job Posting Requirement Decoder do?

Job Posting Requirement Decoder compares real, currently open job postings for the same role across several companies and separates the requirements that show up everywhere from the ones that only appear once. You give it a role title (for example "Senior Backend Engineer") and a short list of companies; it finds each company's matching postings, reads the full requirement text, and returns a per-company breakdown plus one cross-company comparison: which requirements are probably real (they appear in most or all postings), which are probably inflated listing fluff (a single posting, an unusually high years-of-experience ask), a normalized requirement list, and a plain-language summary of what actually matters for that role.

It is built for job seekers deciding what to actually study or highlight, and for recruiters and hiring managers benchmarking a job description against the real market.

### Why use Job Posting Requirement Decoder?

- **Signal, not just postings** - other tools give you a pile of job ads; this one tells you which lines in them are real requirements and which are filler.
- **Evidence per requirement** - every requirement lists exactly which companies asked for it.
- **Cross-company comparison** - one run compares every company at once instead of forcing you to read each posting yourself.
- **Clean, structured output** - a comparison report with consistent field names, ready for a spreadsheet or a study plan.
- **Simple input** - a role title and a short company list; the Actor finds and reads the matching postings.
- **Automatable** - schedule a recurring run over your target companies and watch how the requirement bar shifts.

### What makes this different

Job-board scrapers stop at the raw listing. This Actor adds the comparison layer a candidate or hiring manager actually needs: it reads the full requirement text of every matching posting, classifies each distinct requirement as core, common, or fluff based on how many companies actually ask for it, and writes a plain-language "what actually matters" summary grounded only in the postings it read. The comparison uses a no-cost default model, so the per-run cost stays low.

### How it works

![How Job Posting Requirement Decoder works: input role and companies, collection engine, requirement comparison report](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/job-posting-requirement-decoder--how-it-works.png)

1. **Your input** - a role title and a list of companies, each with its public job-board identifier.
2. **The Actor collects it** - it finds each company's postings matching the role, reads the full requirement text of each, then compares every matched posting across companies.
3. **Your output** - one comparison report: the matched postings per company, a requirement-frequency breakdown, a normalized "what's real" list, the probable fluff, and a summary. Export to JSON, CSV, or Excel, or read it from the API.

### What data can you extract?

| Field                        | Description                                                                                  |
| ----------------------------- | ---------------------------------------------------------------------------------------------- |
| `role`                        | The role title that was decoded.                                                              |
| `companiesAnalyzed`           | Number of companies given as input.                                                           |
| `companiesWithMatches`        | Number of companies that had at least one posting matching the role.                          |
| `totalPostingsMatched`        | Total matching postings read and compared across every company.                               |
| `companies`                   | Per-company breakdown: `companyName`, `ats`, `totalOpenRoles`, `matchedPostingsCount`, and `postings` (each with `title`, `location`, `department`, `url`, `postedAt`, `textExcerpt`, `requirementLines`). |
| `requirementFrequency`        | Every distinct requirement found, with `companiesCount`, `companies`, and a `classification` of `core`, `common`, or `fluff`. |
| `normalizedRequirementList`   | A deduplicated, plain-language list of the requirements that actually matter, most common first. |
| `probablyRealRequirements`    | The requirements the comparison judged most likely to be real, load-bearing asks.             |
| `probablyFluffRequirements`   | The requirements that look like inflated filler - present in only one posting or unusually high. |
| `whatActuallyMatters`         | A short plain-language summary of the real bar for this role.                                 |
| `enrichmentConfidence`        | The comparison's own confidence: high, medium, or low.                                        |
| `enrichmentStatus`            | Whether the comparison was produced, and if not, why.                                         |
| `scrapedAt`                   | ISO timestamp of the run.                                                                      |

### How to use Job Posting Requirement Decoder

1. Open the Actor in the Apify Console.
2. In **Role to decode**, enter the job title to compare, for example "Senior Backend Engineer".
3. In **Companies**, list each company with its name, its public job-board identifier, and its board type.
4. Set **Max postings per company** if you want more or fewer postings read per company.
5. Press **Start**.
6. When the run finishes, open the **Dataset** tab and export to CSV, JSON, or Excel, or connect it to your workflow.

![Job Posting Requirement Decoder input form with a role and three companies filled in](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/job-posting-requirement-decoder--input.png)

### Input Parameters

| Parameter               | Type            | Required | Default                    | Description                                                                                                                    |
| ------------------------ | --------------- | -------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `role`                   | string          | Yes      | "Senior Backend Engineer"  | The job title to compare across companies.                                                                                     |
| `companies`               | array           | Yes      | 3 example companies        | One entry per company: `name`, `atsSlug` (its job-board identifier), and `ats` (`greenhouse`, `lever`, or `ashby`).            |
| `maxPostingsPerCompany`  | integer         | No       | 3                            | Cap on matching postings read in full per company. Range 1-10.                                                                 |
| `useCache`               | boolean         | No       | false                        | Reuse previously collected postings for the same role and company to speed up recurring runs.                                 |
| `openRouterApiKey`       | string (secret) | No       | -                            | Optional key for the comparison service. Without it, matched postings are still returned and the comparison fields are empty. |
| `proxyConfiguration`     | object          | Yes      | Apify Proxy                  | Proxy settings. A proxy is required; the default uses Apify Proxy.                                                             |

### Output Data

One dataset item per run - the full comparison. Real sample record:

```json
{
    "role": "Senior Backend Engineer",
    "companiesAnalyzed": 3,
    "companiesWithMatches": 3,
    "totalPostingsMatched": 7,
    "companies": [
        {
            "companyName": "Reddit",
            "ats": "greenhouse",
            "atsSlug": "reddit",
            "totalOpenRoles": 147,
            "matchedPostingsCount": 3,
            "postings": [
                {
                    "title": "Senior Backend Engineer, IAM",
                    "location": "United States",
                    "department": "Engineering",
                    "url": "https://job-boards.greenhouse.io/reddit/jobs/8044767",
                    "postedAt": "2026-08-11T00:00:00.000Z",
                    "textExcerpt": "Reddit is a community of communities...",
                    "requirementLines": ["5+ years of backend engineering experience", "Experience with distributed systems at scale"]
                }
            ],
            "readStatus": "ok"
        }
    ],
    "requirementFrequency": [
        {
            "requirement": "5+ years of experience in backend development",
            "category": "core",
            "companiesCount": 3,
            "companies": ["Reddit", "Ramp", "Spotify"],
            "classification": "core"
        },
        {
            "requirement": "10+ years of experience in backend development",
            "category": "fluff",
            "companiesCount": 1,
            "companies": ["Ramp"],
            "classification": "fluff"
        }
    ],
    "normalizedRequirementList": [
        "5+ years of experience in backend development",
        "Experience with a general-purpose programming language",
        "Experience with cloud infrastructure (Kubernetes, AWS, GCP)",
        "Experience with databases (Postgres, Redis)",
        "Experience with APIs (REST, GraphQL)"
    ],
    "probablyRealRequirements": ["5+ years of experience in backend development", "Experience with cloud infrastructure"],
    "probablyFluffRequirements": ["10+ years of experience in backend development", "Experience with AI-powered developer tools"],
    "whatActuallyMatters": "A Senior Backend Engineer should have at least 5 years of backend experience, proficiency in a general-purpose language, and experience with cloud infrastructure, databases, and APIs. A 10-year bar and niche AI-tooling asks show up at only one company and are likely not load-bearing.",
    "enrichmentConfidence": "high",
    "enrichmentStatus": "ok",
    "scrapedAt": "2026-09-04T21:44:00.000Z"
}
```

![Job Posting Requirement Decoder dataset export with requirement frequency and the real vs fluff breakdown](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/job-posting-requirement-decoder--export.png)

![Job Posting Requirement Decoder field map: one comparison report with every field labelled](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/job-posting-requirement-decoder--output.png)

### Usage Examples

- **Study plan for a job search** - decode the role you're targeting across 4-6 real employers, then focus prep on `normalizedRequirementList` instead of every line in one posting.
- **Sanity-check a draft job description** - run your own company alongside 2-3 competitors for the same role and see whether your requirements line up with `probablyRealRequirements` or read like `probablyFluffRequirements`.
- **Compensation-band research support** - use `requirementFrequency` to see which skills are genuinely in demand for a title before setting a leveling bar.
- **Recurring market check** - schedule a monthly run over key employers and track how `whatActuallyMatters` shifts as the market moves.

### Tips for Best Results

- Compare 3 or more companies - a single posting has nothing to be compared against, so `requirementFrequency` and the fluff/core split need at least two, ideally three or more.
- Use the exact working job-board identifier for each company (visible in its careers page URL) - a wrong `atsSlug` returns zero matched postings for that company.
- Raise `maxPostingsPerCompany` for a broad title (e.g. "Software Engineer") so the comparison sees more of that company's postings for the role.
- Provide an analysis service API key for the comparison fields; the raw matched postings work without one.

### Known Limitations

- Only companies publishing on a supported public job board can be read. Companies using a different or private system are not supported.
- A role title with no matching postings at a company is reported with zero matches for that company, not an error.
- Requirement classification is a judgment call based on the postings given - it is not a guarantee of what a company will actually enforce in an interview.
- `department`, `location`, and `postedAt` are null when the source does not provide them.
- The comparison quality reflects the default no-cost model and can be terse when very few postings match.

### Integrations

Connect the dataset to Google Sheets, Airtable, Make, Zapier, or n8n; call the Actor from the Apify API; trigger it with webhooks; or schedule recurring runs from the Apify Console.

### Export Formats

JSON, CSV, Excel, and XML, from the Dataset tab or the Apify API.

### Frequently Asked Questions

#### Do I need an account or login?

No. The Actor reads only publicly listed job postings and never logs in anywhere.

#### Which companies can it compare?

Any company that publishes its open roles on a supported public job board. You provide the company's job-board identifier and board type in the input.

#### How do I find a company's job-board identifier?

It's the segment of the company's careers-page URL after the board's domain - for example the "reddit" in a Reddit careers-board URL.

#### Why is a company reported with zero matched postings?

Either the company has no open posting whose title matches the role you asked for, or the job-board identifier is wrong. `totalOpenRoles` shows how many roles were found in total, so you can check the identifier resolved correctly.

#### What counts as a "fluff" requirement?

A requirement the comparison found in only one company's posting, or one that reads as an outlier (an unusually high years-of-experience ask, an oddly specific tool) relative to the rest of the postings compared.

#### Am I charged for failed results?

You are charged once per finished comparison report written to the dataset. A run that fails before a report is written is not charged.

#### How fresh is the data?

Postings are read live at run time, unless caching is enabled, in which case a repeat within the cache window reuses the earlier read. Re-run with caching off, or wait for the cache to expire, to force a fresh read.

#### Can it export to Google Sheets?

Yes. Connect the dataset to the Google Sheets integration or pull it from the API.

#### Does it handle duplicate companies?

Yes. Companies are deduplicated by board type and identifier; a duplicate entry is read once.

### Support

Questions and bug reports: use the **Issues** tab on the Actor's Console page. Include the input you ran and the run ID.

### Legal / Responsible Use

You are responsible for complying with the target job boards' terms of use, applicable law, and responsible data-use requirements. Job-posting text is generally not personal data, but where a posting includes named contact details you are responsible for meeting any applicable privacy and data-protection obligations (for example GDPR) for personal data you collect and store.

# Actor input Schema

## `role` (type: `string`):

The job title to compare across companies, for example "Senior Backend Engineer" or "Product Marketing Manager". Matched against each company's posting titles.

## `companies` (type: `array`):

One entry per company to compare, each with "name", "atsSlug" (the company's identifier on its job board), and "ats" ("greenhouse", "lever", or "ashby"). Example: {"name":"Acme","atsSlug":"acme","ats":"greenhouse"}.

## `maxPostingsPerCompany` (type: `integer`):

Cap on how many matching postings are read in full per company. Higher covers more listings for the role at a large company; lower is faster. Range 1-10.

## `useCache` (type: `boolean`):

Reuse previously collected postings for the same role and company to reduce repeated requests and speed up recurring runs. Disabled by default.

## `openRouterApiKey` (type: `string`):

Optional. A key for the service that compares the postings and writes the requirement breakdown. Without it, the Actor still returns every matching posting it found and leaves the comparison fields empty. Stored securely and never shown in output or logs.

## `proxyConfiguration` (type: `object`):

A proxy is required. The default routes requests through Apify Proxy. You can also supply your own proxy URLs.

## Actor input object example

```json
{
  "role": "Senior Backend Engineer",
  "companies": [
    {
      "name": "Reddit",
      "atsSlug": "reddit",
      "ats": "greenhouse"
    },
    {
      "name": "Ramp",
      "atsSlug": "ramp",
      "ats": "ashby"
    },
    {
      "name": "Spotify",
      "atsSlug": "spotify",
      "ats": "lever"
    }
  ],
  "maxPostingsPerCompany": 3,
  "useCache": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `comparisonReport` (type: `string`):

No description

# 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 = {
    "role": "Senior Backend Engineer",
    "companies": [
        {
            "name": "Reddit",
            "atsSlug": "reddit",
            "ats": "greenhouse"
        },
        {
            "name": "Ramp",
            "atsSlug": "ramp",
            "ats": "ashby"
        },
        {
            "name": "Spotify",
            "atsSlug": "spotify",
            "ats": "lever"
        }
    ],
    "maxPostingsPerCompany": 3,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("mrdoe/job-posting-requirement-decoder").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 = {
    "role": "Senior Backend Engineer",
    "companies": [
        {
            "name": "Reddit",
            "atsSlug": "reddit",
            "ats": "greenhouse",
        },
        {
            "name": "Ramp",
            "atsSlug": "ramp",
            "ats": "ashby",
        },
        {
            "name": "Spotify",
            "atsSlug": "spotify",
            "ats": "lever",
        },
    ],
    "maxPostingsPerCompany": 3,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("mrdoe/job-posting-requirement-decoder").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 '{
  "role": "Senior Backend Engineer",
  "companies": [
    {
      "name": "Reddit",
      "atsSlug": "reddit",
      "ats": "greenhouse"
    },
    {
      "name": "Ramp",
      "atsSlug": "ramp",
      "ats": "ashby"
    },
    {
      "name": "Spotify",
      "atsSlug": "spotify",
      "ats": "lever"
    }
  ],
  "maxPostingsPerCompany": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call mrdoe/job-posting-requirement-decoder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mrdoe/job-posting-requirement-decoder"
        }
    }
}
```

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/nf1obpBB4UFQkESDc/builds/4BzLWR0CEZrhe3olH/openapi.json
