# Resume Parser + Job Match — CV to JSON with 0-100 score (`keith-apis/resume-parser-job-match`) Actor

Parse resumes and CVs (PDF, DOCX or text) into structured JSON: contact, job titles, work history, education, skills. Optionally score each one 0-100 against a job posting with a breakdown. No LLM; resume content is never logged. $0.005 per resume.

- **URL**: https://apify.com/keith-apis/resume-parser-job-match.md
- **Developed by:** [Lai Keith](https://apify.com/keith-apis) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 resume parseds

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

## Resume Parser + Job Match: CVs to JSON with a 0-100 match score

**Resume Parser + Job Match is an Apify Actor that turns a list of resumes or CVs (PDF, DOCX or plain text) into structured JSON (contact details, job titles, work history, education and skills) and, if you give it a job posting, scores every resume against it from 0 to 100 with an explainable breakdown.** It uses deterministic rules, not an LLM, it never logs resume content, and you pay only for resumes it parses ($0.005 each, or $5 per 1,000).

### What does Resume Parser + Job Match do?

You give it a list of resumes, each as plain text or as a URL to a PDF, DOCX or TXT file, plus an optional job (title, description, location). For every resume it returns one **dataset** row with:

- **Contact:** `name`, `email`, `phone`, `location`, `country`, `links` (LinkedIn, GitHub, portfolio)
- **Career:** `current_title`, `current_company`, `total_experience_years` (overlapping jobs merged), `seniority`, `function`, and every `experience` entry with title, company, start and end dates, duration and bullets
- **Education:** `education` entries and `highest_education_level`
- **Skills:** normalised `skills`, plus `skills_detail` (category, mentions, sections, last year used), `certifications`, `languages`
- **Match (when a job is given):** `match_score` 0-100, `matched_skills`, `missing_skills`, `match_breakdown` and `match_reasons` in plain English
- `warnings` when something could not be found, for example a scanned PDF with no text layer

Export the dataset as JSON, CSV or Excel, or read it from the Apify API.

### When should I use it?

- **Screen a pile of applications:** paste the job, add the CV links, sort by `match_score`.
- **Fill an ATS, CRM or spreadsheet** from CV files without retyping.
- **Job boards and talent marketplaces:** turn uploaded CVs into searchable candidate records.
- **Automations:** call it from Make, Zapier, n8n or the Apify API when new applications arrive.

For one resume at a time inside your own app, use the [Resume Parser + Job Match API](https://resume-match-api.fly.dev/) instead. It runs the same parser behind a REST endpoint.

### Input

```json
{
  "resumes": [
    { "id": "candidate-001", "text": "Alex Morgan\nSenior Backend Engineer\nalex.morgan@example.com\n\nEXPERIENCE\nSenior Backend Engineer, Acme Analytics\nJan 2021 - Present\n- Python, Django, AWS" },
    { "id": "candidate-002", "url": "https://example.com/cvs/sam-taylor.pdf" }
  ],
  "jobTitle": "Senior Backend Engineer",
  "jobDescription": "5+ years of experience. Python, Django, PostgreSQL, AWS, Docker, Kubernetes.",
  "jobLocation": "Remote - US"
}
```

| Field | Required | Description |
|---|---|---|
| `resumes` | yes | List of `{"text": ...}` or `{"url": ...}` items, with an optional `id` copied to the output. A bare string also works. Up to 500 per run. |
| `jobTitle` | no | Job to score every resume against. Leave all job fields empty to parse only. |
| `jobDescription` | no | Posting text or HTML; required skills and years of experience are read from it. |
| `jobLocation` | no | Location or remote policy, e.g. `Remote - US`, used for location eligibility. |
| `jobCompany` | no | Company name, removed from the title if repeated there. |

Files must be text-based PDF, DOCX or TXT, up to 5 MB; the first 10 pages of a PDF are read.

### Output

The first row of a run with the prefilled example input (fictional candidate; some fields shortened):

```json
{
  "id": "candidate-001", "source": "text",
  "name": "Alex Morgan", "email": "alex.morgan@example.com",
  "current_title": "Senior Backend Engineer", "current_company": "Acme Analytics",
  "total_experience_years": 9.4, "seniority": "senior", "function": "engineering",
  "highest_education_level": "bachelor",
  "skills": ["Python", "AWS", "Django", "Docker", "Kubernetes", "PostgreSQL"],
  "match_score": 100, "matched_skills": ["AWS", "Django", "Docker", "Kubernetes", "PostgreSQL", "Python"],
  "missing_skills": [],
  "match_reasons": ["6 of 6 skills named in the posting appear in the CV", "seniority matches (senior)",
                    "same function (engineering)", "9.4 years of experience meets the 5+ asked for",
                    "candidate in US, which the posting allows"]
}
```

A `SUMMARY` record in the run's key-value store lists how many resumes were parsed and which were skipped and why.

### How is the match score calculated?

| Component | Weight | Score |
|---|---|---|
| skills | 0.45 | Share of the posting's skills found in the CV |
| seniority | 0.20 | 1.0 same level, 0.6 one step apart, 0.2 two steps, else 0 |
| function | 0.15 | 1.0 same, 0.75 same function but different specialty, else 0 |
| experience | 0.15 | 1.0 if years meet the posting's minimum, else years / minimum |
| location | 0.05 | 1.0 if the CV's country is inside the posting's allowed countries or regions |

A component with no data on either side is left out and the other weights are rescaled, so missing information never counts against the candidate.

### How much does it cost?

It's **pay per event: $0.005 per resume** ($5 per 1,000), including the match score, plus a little Apify platform usage. Empty, unreadable (corrupt, encrypted, scanned) or unparseable inputs are skipped and **not charged**. If you set a maximum spend on the run, it stops when that limit is reached.

### Privacy

Resume text, file URLs and parsed fields are **never written to the run log**; the log names only the position of a skipped input and the reason. The Actor sends nothing to any other service (it only downloads the file URLs you give it), and the results stay in your own Apify storage under your account's retention settings.

### FAQ

**How do I parse resumes in bulk into a spreadsheet?**
Put each CV's file URL (or its text) in `resumes`, run the Actor, and export the dataset as CSV or Excel. Each row is one candidate.

**How do I rank candidates against a job description?**
Fill in `jobTitle` and `jobDescription` (and `jobLocation` if location matters). Every row gets a `match_score` from 0 to 100; sort by it and read `missing_skills` and `match_reasons` to see why.

**Does it use ChatGPT or another LLM?**
No. It uses deterministic rules, so the same CV always gives the same result and there are no model costs or invented details.

**Can it read scanned PDFs or photos of a CV?**
No, there is no OCR. A PDF without a text layer is skipped and not charged; send text-based PDFs, DOCX or plain text.

**How accurate is it?**
On 15 fictional test CVs in different layouts (US, UK, skills-first, dates-first, two-column, no headings, junior, staff, career changer, nurse, sales, HR) it found the contact details, current title, experience entries and education in all 15. Known weak spots: when a title has no level word, seniority is inferred from years of experience; healthcare and other non-office roles get the function `other`; scanned PDFs are not read. It was tested on English-language CVs.

**How does it compare with Affinda, Textkernel (Sovren) or RChilli?**
Those are full commercial parsers with broader language and document coverage; Affinda's self-serve price is $0.10 per document, and Textkernel and RChilli are sold by quote. This Actor is a low-cost, predictable option at $0.005 per resume that also scores the match.

### Related

- [Resume Parser + Job Match API](https://resume-match-api.fly.dev/): the same parser as a REST API, with monthly plans on RapidAPI.

# Actor input Schema

## `resumes` (type: `array`):

One item per resume: {"text": "..."} for plain text, or {"url": "https://..."} for a PDF, DOCX or TXT file (max 5 MB, text-based: no OCR). Optional "id" is copied to the output. A bare string also works (a URL or resume text). Up to 500 per run; charged per resume parsed, empty or unreadable ones are skipped and not charged.

## `jobTitle` (type: `string`):

Title of the job to score every resume against. Leave job fields empty to parse only.

## `jobDescription` (type: `string`):

Job posting text or HTML. Required skills and years of experience are read from it.

## `jobLocation` (type: `string`):

Location or remote policy as written in the posting, e.g. 'Remote - US' or 'London'. Used to check location eligibility.

## `jobCompany` (type: `string`):

Hiring company name; removed from the job title if repeated there.

## Actor input object example

```json
{
  "resumes": [
    {
      "id": "candidate-001",
      "text": "Alex Morgan\nSenior Backend Engineer\nalex.morgan@example.com | +1 555 0100 | Austin, TX, USA\n\nSUMMARY\nBackend engineer with nine years of experience building APIs and data pipelines in Python on AWS.\n\nEXPERIENCE\nSenior Backend Engineer, Acme Analytics\nJan 2021 - Present\n- Built Python and Django services on AWS, PostgreSQL and Redis\n- Moved deployments to Docker and Kubernetes\n\nSoftware Engineer, Contoso Labs\nJun 2017 - Dec 2020\n- Developed REST APIs in Python and Flask\n- Wrote data pipelines with SQL and Airflow\n\nEDUCATION\nBSc Computer Science, Example State University, 2013 - 2017\n\nSKILLS\nPython, Django, Flask, PostgreSQL, Redis, AWS, Docker, Kubernetes, SQL, Airflow"
    },
    {
      "id": "candidate-002",
      "text": "Sam Taylor\nMarketing Coordinator\nsam.taylor@example.com | London, UK\n\nEXPERIENCE\nMarketing Coordinator, Northwind Retail\nSep 2022 - Present\n- Ran email campaigns in HubSpot and reported results in Google Analytics\n- Managed social media calendars\n\nEDUCATION\nBA Marketing, Example University, 2019 - 2022\n\nSKILLS\nHubSpot, Google Analytics, SEO, Copywriting"
    }
  ],
  "jobTitle": "Senior Backend Engineer",
  "jobDescription": "We are hiring a Senior Backend Engineer with 5+ years of experience. You will build APIs in Python and Django on AWS with PostgreSQL, and run services on Docker and Kubernetes.",
  "jobLocation": "Remote - US"
}
```

# Actor output Schema

## `resumes` (type: `string`):

No description

## `summary` (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 = {
    "resumes": [
        {
            "id": "candidate-001",
            "text": "Alex Morgan\nSenior Backend Engineer\nalex.morgan@example.com | +1 555 0100 | Austin, TX, USA\n\nSUMMARY\nBackend engineer with nine years of experience building APIs and data pipelines in Python on AWS.\n\nEXPERIENCE\nSenior Backend Engineer, Acme Analytics\nJan 2021 - Present\n- Built Python and Django services on AWS, PostgreSQL and Redis\n- Moved deployments to Docker and Kubernetes\n\nSoftware Engineer, Contoso Labs\nJun 2017 - Dec 2020\n- Developed REST APIs in Python and Flask\n- Wrote data pipelines with SQL and Airflow\n\nEDUCATION\nBSc Computer Science, Example State University, 2013 - 2017\n\nSKILLS\nPython, Django, Flask, PostgreSQL, Redis, AWS, Docker, Kubernetes, SQL, Airflow"
        },
        {
            "id": "candidate-002",
            "text": "Sam Taylor\nMarketing Coordinator\nsam.taylor@example.com | London, UK\n\nEXPERIENCE\nMarketing Coordinator, Northwind Retail\nSep 2022 - Present\n- Ran email campaigns in HubSpot and reported results in Google Analytics\n- Managed social media calendars\n\nEDUCATION\nBA Marketing, Example University, 2019 - 2022\n\nSKILLS\nHubSpot, Google Analytics, SEO, Copywriting"
        }
    ],
    "jobTitle": "Senior Backend Engineer",
    "jobDescription": "We are hiring a Senior Backend Engineer with 5+ years of experience. You will build APIs in Python and Django on AWS with PostgreSQL, and run services on Docker and Kubernetes.",
    "jobLocation": "Remote - US"
};

// Run the Actor and wait for it to finish
const run = await client.actor("keith-apis/resume-parser-job-match").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 = {
    "resumes": [
        {
            "id": "candidate-001",
            "text": """Alex Morgan
Senior Backend Engineer
alex.morgan@example.com | +1 555 0100 | Austin, TX, USA

SUMMARY
Backend engineer with nine years of experience building APIs and data pipelines in Python on AWS.

EXPERIENCE
Senior Backend Engineer, Acme Analytics
Jan 2021 - Present
- Built Python and Django services on AWS, PostgreSQL and Redis
- Moved deployments to Docker and Kubernetes

Software Engineer, Contoso Labs
Jun 2017 - Dec 2020
- Developed REST APIs in Python and Flask
- Wrote data pipelines with SQL and Airflow

EDUCATION
BSc Computer Science, Example State University, 2013 - 2017

SKILLS
Python, Django, Flask, PostgreSQL, Redis, AWS, Docker, Kubernetes, SQL, Airflow""",
        },
        {
            "id": "candidate-002",
            "text": """Sam Taylor
Marketing Coordinator
sam.taylor@example.com | London, UK

EXPERIENCE
Marketing Coordinator, Northwind Retail
Sep 2022 - Present
- Ran email campaigns in HubSpot and reported results in Google Analytics
- Managed social media calendars

EDUCATION
BA Marketing, Example University, 2019 - 2022

SKILLS
HubSpot, Google Analytics, SEO, Copywriting""",
        },
    ],
    "jobTitle": "Senior Backend Engineer",
    "jobDescription": "We are hiring a Senior Backend Engineer with 5+ years of experience. You will build APIs in Python and Django on AWS with PostgreSQL, and run services on Docker and Kubernetes.",
    "jobLocation": "Remote - US",
}

# Run the Actor and wait for it to finish
run = client.actor("keith-apis/resume-parser-job-match").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 '{
  "resumes": [
    {
      "id": "candidate-001",
      "text": "Alex Morgan\\nSenior Backend Engineer\\nalex.morgan@example.com | +1 555 0100 | Austin, TX, USA\\n\\nSUMMARY\\nBackend engineer with nine years of experience building APIs and data pipelines in Python on AWS.\\n\\nEXPERIENCE\\nSenior Backend Engineer, Acme Analytics\\nJan 2021 - Present\\n- Built Python and Django services on AWS, PostgreSQL and Redis\\n- Moved deployments to Docker and Kubernetes\\n\\nSoftware Engineer, Contoso Labs\\nJun 2017 - Dec 2020\\n- Developed REST APIs in Python and Flask\\n- Wrote data pipelines with SQL and Airflow\\n\\nEDUCATION\\nBSc Computer Science, Example State University, 2013 - 2017\\n\\nSKILLS\\nPython, Django, Flask, PostgreSQL, Redis, AWS, Docker, Kubernetes, SQL, Airflow"
    },
    {
      "id": "candidate-002",
      "text": "Sam Taylor\\nMarketing Coordinator\\nsam.taylor@example.com | London, UK\\n\\nEXPERIENCE\\nMarketing Coordinator, Northwind Retail\\nSep 2022 - Present\\n- Ran email campaigns in HubSpot and reported results in Google Analytics\\n- Managed social media calendars\\n\\nEDUCATION\\nBA Marketing, Example University, 2019 - 2022\\n\\nSKILLS\\nHubSpot, Google Analytics, SEO, Copywriting"
    }
  ],
  "jobTitle": "Senior Backend Engineer",
  "jobDescription": "We are hiring a Senior Backend Engineer with 5+ years of experience. You will build APIs in Python and Django on AWS with PostgreSQL, and run services on Docker and Kubernetes.",
  "jobLocation": "Remote - US"
}' |
apify call keith-apis/resume-parser-job-match --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,keith-apis/resume-parser-job-match"
        }
    }
}
```

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/7W4YQOGjL8ZOzmtgj/builds/4ZveV2N8OlZidYReL/openapi.json
