ResumeJSON

Resume to Excel: turn a folder of CVs into one spreadsheet

To get resumes into Excel, you need one row per candidate and one column per fact: name, email, phone, current title, years of experience, skills. For five CVs, copy those values in by hand. For fifty or five hundred, run each file through a resume parser that returns structured fields, flatten the result into rows, and write a .xlsx or .csv that Excel opens directly. This article covers both routes, gives you a working script for the second, and says where each one stops being worth it.

It is written for the person holding the folder: a recruiter with a shared drive of applications, a developer asked to "just get these into a sheet" before a hiring meeting, a founder sorting a job board's first sign-ups. We build ResumeJSON, the parser the script below calls, so read this as written by an interested party. The manual route needs nothing from us.


Why a CV does not paste into Excel

A resume is a document laid out for a human eye. Opening a PDF and pasting its text into a sheet gives you one long column of lines in reading order, sometimes out of order when the CV uses two columns, with dates written five different ways and skills run together in a paragraph. Excel's own import tools work on data that is already a table, so they cannot help here.

What you actually want is a small, fixed set of columns. A useful default:

ColumnWhere it comes fromWatch out for
Full nameThe header of the CVName written in capitals, or split across two lines
EmailContact blockSeveral addresses on one CV
PhoneContact blockCountry code present on some, missing on others
LocationContact block or latest role"Remote" is a location on some CVs
Current titleMost recent roleThe CV's headline is often a different claim from the job title
Current companyMost recent roleFreelancers list several at once
Years of experienceCounted from the work historyOverlapping roles counted twice by hand
SkillsSkills section, plus the rolesOne cell, separated by a semicolon
Source fileYour folderKeep it, so every row leads back to the document

Decide the columns before you start. Adding a column after 200 rows means reopening 200 files.

The manual way: when it is enough

For a handful of CVs, typing is the right tool. Open the CV beside the sheet, fill one row, move on. A few habits make the result usable later:

  1. Write dates as YYYY-MM. "March 2022", "03/22" and "Mar '22" sort as text in three different places; 2022-03 sorts correctly as plain text.
  2. Put the file name in the last column. When somebody asks where a number came from, the answer is one click away.
  3. Keep skills in one cell, separated by ; . Excel's Text to Columns or a FILTER with SEARCH can split or query them later, and the row stays one row per person.
  4. Count experience from the roles, not from the summary line. "10+ years" in a headline is the candidate's claim. The dates are the evidence.

The manual way is enough when you have fewer than about twenty CVs and will not repeat the job. Past that, typing becomes the slow part of the hiring process, and the errors start: a transposed digit in a phone number, a skill left off because it sat in a role description instead of the skills list.

The faster way: parse, flatten, write the sheet

The automated version has three steps, and only the first needs anything you do not already have.

  1. Parse each file into structured data. A resume parser reads the PDF, DOCX or scanned image and returns the fields as JSON.
  2. Flatten that JSON into one row. Nested lists like the work history become a few chosen columns.
  3. Write the rows to a spreadsheet file.

ResumeJSON returns a resume object with basics (including full_name, email, phone, location, headline), a work array with company, title, start_date, end_date and is_current on each entry, an education array, a skills array of strings, and total_years_experience, which is computed from the work history rather than read off the CV. Dates come back as YYYY-MM, YYYY or null, so habit 1 above is already done for you. Every field is listed in the field reference.

The script

This is Python with two dependencies, requests and openpyxl. Put your CVs in a folder called cvs, set your key, and run it.

import pathlib, requests
from openpyxl import Workbook

URL = "https://resumejson-resume-cv-parser-api.p.rapidapi.com/v1/parse"
HEADERS = {
    "x-rapidapi-key": "YOUR_KEY",
    "x-rapidapi-host": "resumejson-resume-cv-parser-api.p.rapidapi.com",
}
COLUMNS = ["Full name", "Email", "Phone", "Location", "Current title",
           "Current company", "Years of experience", "Skills", "Source file"]

def to_row(resume, source):
    basics = resume["basics"]
    work = resume["work"]
    latest = next((w for w in work if w["is_current"]), work[0] if work else {})
    return [
        basics["full_name"], basics["email"], basics["phone"], basics["location"],
        latest.get("title"), latest.get("company"),
        resume["total_years_experience"],
        "; ".join(resume["skills"]),
        source,
    ]

wb = Workbook()
ok, failed = wb.active, wb.create_sheet("Failed")
ok.title = "Candidates"
ok.append(COLUMNS)
failed.append(["Source file", "Status", "Reason"])

for path in sorted(pathlib.Path("cvs").iterdir()):
    with path.open("rb") as f:
        resp = requests.post(URL, headers=HEADERS, files={"file": f}, timeout=60)
    if resp.ok:
        ok.append(to_row(resp.json()["resume"], path.name))
    else:
        body = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {}
        reason = body.get("error", {}).get("code") or body.get("message") or resp.text[:200]
        failed.append([path.name, resp.status_code, reason])

wb.save("candidates.xlsx")

Open candidates.xlsx and you have a Candidates sheet with one row per CV and a Failed sheet listing every file that did not parse, with the reason. Keep the failure sheet. A file that comes back not_a_resume or unreadable_file is usually a cover letter or a corrupt upload, and you want to see it rather than lose a candidate silently.

If you would rather have a CSV, replace the workbook with Python's csv module and write the same rows; Excel opens a UTF-8 CSV fine, though names with accents survive more reliably in .xlsx.

Choosing which role counts as "current"

The script takes the first role marked is_current, and falls back to the first role listed. That is a reasonable default for a shortlist. Two cases deserve a second look:

Scans, photos and other formats

A folder of real applications is never all clean PDFs. The parser detects the type from the file's own bytes, so a .pdf that is really a scan still works: a PDF without a text layer, or a JPEG, PNG or WebP photo of the page, is read as an image instead. DOCX and plain text are accepted too. Uploads go up to 20 MB each.

If your archive is mostly scans, OCR resume parser covers what changes when the CV is an image.

What it costs, and how long it takes

As of September 2026, our published plans on RapidAPI are:

PlanMonthly priceParses includedPast the quota
Basic$0100Hard cap, never bills
Pro$0None, pay per use$0.05 a parse
Ultra$291,000$0.045 a parse
Mega$995,000$0.018 a parse

A folder of up to 100 CVs a month fits the free Basic plan. A one-off folder of 400 costs $20 on pay per use. A typical parse takes about two seconds, so the script above, calling one file at a time, gets through a few hundred CVs while you make coffee. For thousands, run a few requests at once and keep a status table so a crash does not restart from zero; Bulk resume parsing walks through that.

Every call is metered whatever the answer, including a refused file, so drop duplicates and non-CV attachments from the folder before you run it.

Before you share the sheet

A spreadsheet of candidates is personal data about real people, and it travels further than a folder does. Two habits help:

ResumeJSON parses the document and writes nothing down, so the only copy of the result is the one in your spreadsheet. Our data handling page has the detail.

Try one CV first

Before you write the loop, see what comes back for a real CV from your folder. The free resume parser takes one file with no signup and shows the JSON the script would receive, so you can check that the columns you planned are the ones the document actually fills. If you are building something bigger than a spreadsheet, such as a screening step or a candidate database, Automated resume screening and How to build an ATS pick up where this article stops.

All articles