ResumeJSON

Open source ATS: the options, and how to add resume parsing

An open source ATS gives you an applicant tracking system you can host, read and change yourself, with no per-seat fee. The three projects most teams end up comparing are OpenCATS (a dedicated recruiting ATS in PHP), the Recruitment app in Odoo's open source Community edition, and the recruitment module in Frappe HR. Each tracks jobs, candidates and pipeline stages well. What none of them gives you out of the box is reliable structured data from an uploaded CV: the name, contact details, work history and skills as fields rather than an attached file. This guide compares the three, then shows how to close that gap.

We build ResumeJSON, a CV parsing API, so read the parsing section as written by an interested party. The comparison of the ATS projects applies whatever you parse with, and for some teams the answer is to parse nothing at all.


What "open source ATS" should mean before you pick one

The phrase covers three different things, and the difference decides your maintenance bill:

Then check the licence. "Open source" ranges from weak copyleft to strong copyleft, and it matters the moment you modify the code and offer it to anyone outside your company.

Open source ATS options compared

All figures below were read from each project's own pages and repository as of October 2026.

OpenCATSOdoo Recruitment (Community)Frappe HR
What it isDedicated ATS and recruiting CRMRecruitment app in an ERP suiteRecruitment module in an HR and payroll suite
LanguagePHPPythonPython
LicenceMPL 2.0, older code under CATS Public License 1.1aLGPLv3GPLv3
Latest releasev0.11.1, September 2026Ongoing suite releasesOngoing suite releases
Best forStaffing agencies and recruiting teamsCompanies already on, or moving to, OdooCompanies wanting HR and payroll beside hiring
Structured CV fields out of the boxNo; the old import service ships disabledApplicant details from the online formApplicant details from the job application form

OpenCATS

OpenCATS describes itself on its home page as:

a free, community-maintained applicant tracking system and recruiting CRM for teams that need a practical way to manage candidates, jobs, submissions, and hiring activity without vendor lock-in.

It is the most focused of the three. Candidates, jobs, companies, contacts and submissions are first-class records, and the model fits a staffing agency placing people at client companies. The repository shows active work as of October 2026, with a public roadmap that names PHP 8.4 and 8.5 fixes alongside larger API and integration features, and the README asks contributors to read CONTRIBUTING.md first.

The resume side is where it shows its age. The default config.php in the repository carries this line:

/* Resfly.com Resume Import Services Enabled */
define('PARSING_ENABLED', false);

Below it are paths to antiword, pdftotext, html2text and unrtf. Those tools turn an uploaded document into text so it can be searched. They do not turn it into fields. A recruiter still types the candidate's name, phone and job history into the record, or relies on keyword search across the extracted text.

Odoo Recruitment (Community edition)

Odoo is a full business suite published under LGPLv3. Its recruitment page describes a pipeline where you "click and drag an applicant card to quickly change where they are in the pipeline," plus stage-based automated emails and online interview scheduling. The hosted Odoo Online offers one app free "with unlimited users," per the same page; the paid tiers on odoo.com are per user per month and cover all apps.

Odoo's page says that "when applicants apply online, their info is indexed and added to their application automatically." Read that as the fields the applicant typed into the careers form, attached to the applicant card along with their documents. If your candidates arrive through your own website form, that covers a lot. If they arrive as a folder of PDFs, an email inbox or an old database export, you still need something to read the CV.

Frappe HR

Frappe HR is an open source HR and payroll system on the Frappe framework, licensed GPLv3, with job openings and job applicants in its recruitment module. Its site pitches it as covering everything "from recruitment to exits." It suits a company that wants hiring, onboarding, attendance and payroll in one place and has, or wants, Python developers. Like Odoo, it is a suite first, so the recruitment screens are one part of a larger system you operate.

The gap all three share: CVs as files, not fields

Every ATS above stores the CV. None of them, in its default open source form, reliably turns that CV into structured fields you can filter on: years of experience, last employer, each job's dates, a skills list. That matters for three jobs:

You have two honest choices: parse inside the ATS's own stack, or call a parsing service from a small hook.

How to add resume parsing to a self-hosted ATS

The pattern is the same whichever ATS you run. A file arrives, you send it to a parser, and you write the returned fields onto the candidate record.

  1. Find the hook. In Odoo and Frappe HR, a server-side automation or a small custom module fires when an applicant record is created with an attachment. In OpenCATS, the upload handling in its PHP modules is where a call fits, or you run a separate job that watches the attachments table.
  2. Send the file to a parser. With ResumeJSON, that is one multipart request:
   curl -X POST 'https://resumejson-resume-cv-parser-api.p.rapidapi.com/v1/parse' \
     -H 'x-rapidapi-key: YOUR_KEY' \
     -H 'x-rapidapi-host: resumejson-resume-cv-parser-api.p.rapidapi.com' \
     -F 'file=@cv.pdf'
  1. Map the response onto your fields. The response carries a resume object with basics (name, email, phone, location), a work array, an education array, skills, certifications, languages and total_years_experience. Dates come back as YYYY-MM, YYYY or null, and a field the CV does not state is null. The field reference lists every field.
  2. Keep the original file. Store the parsed JSON beside the CV, never instead of it. A recruiter should always be able to open what the candidate actually sent.
  3. Show the parsed values for review. Prefill the candidate form and let a person confirm it. Parsing removes the typing, and a human still owns the record.

For a Python suite, the call from a server action is a few lines of requests; Python resume parser has the full example. For OpenCATS, Resume parser PHP shows the same call with cURL in PHP. You can try a CV on the free parser first to see what comes back before you wire anything.

Or keep it all self-hosted

If no candidate data may leave your servers, an external API is the wrong answer, whatever its quality. Then the open source parsers are the route: Open source resume parser compares what exists and where each one breaks. Expect to spend real time on layouts, two-column PDFs and scans, which is the work a hosted parser exists to absorb.

Which open source ATS to choose

When you do not need parsing at all

Parsing earns its place with volume or with imports. Skip it when:

Add parsing when retyping becomes the bottleneck, or when you are about to import a backlog. Before then, an open source ATS on its own is a perfectly good tool.

All articles