---
title: "Job title taxonomy: how raw titles become normalized titles, ISCO-08 codes, seniority and function"
description: "[NewSearch millions of jobs from your AI agent with MCP→](/blog/jobspipe-mcp-server)"
canonical: https://jobspipe.dev/blog/job-title-taxonomy
last_updated: 2026-09-10
---

[NewSearch millions of jobs from your AI agent with MCP→](/blog/jobspipe-mcp-server)

[All posts](/blog)

![](/listly/card-field.png)

ReferenceTaxonomy

Reference·Sep 9, 2026·8 min read

# Job title taxonomy: how raw titles become normalized titles, ISCO-08 codes, seniority and function

What a job title taxonomy is, why raw titles resist it, how JobsPipe resolves every posting into normalized\_title, occupation\_code, seniority and job\_function, the share of postings with a labelled level on each board, the three classification methods (rules, lookup tables, embeddings), job title versus occupation, and how to filter with occupation\_code\_or and job\_seniority\_or.

![Dvir Atias](/authors/dvir-atias.jpg)

Dvir Atias

Founder, JobsPipe

Raw job titles are the messiest field in any postings dataset and the one every product needs most. This post explains what a job title taxonomy is, why raw titles resist it, how a title becomes a normalised title, an ISCO-08 occupation code, a seniority level and a function in the JobsPipe API, the three classification methods teams use, and how to filter on the result.

## What is a job title taxonomy?

A job title taxonomy is a controlled vocabulary that maps the free-text titles employers write onto a fixed set of occupations, levels and functions, so that “Sr. SWE II” and “Senior Software Engineer” land on the same node. It has layers: a cleaned title, an occupation code, a seniority level and a function, each answering a different question.

Public taxonomies exist for the occupation layer. ISCO-08 is the international standard, covered in the [ISCO-08 post](/blog/isco-08); the US uses SOC, covered in the [SOC codes post](/blog/soc-codes); ESCO adds a European occupation and skill vocabulary. None of them carries seniority, and none was designed around how employers actually write titles, which is why every data vendor builds its own layers on top.

## Why raw job titles are messy

Because a title is marketing, org chart and search keyword at once. The same job appears as Software Engineer, Software Developer, SWE, Developer II, Member of Technical Staff and Ninja, and the same title means different jobs across industries. Titles also smuggle in level, location, team, employment type and internal codes.

-   **Level inside the title.** Senior, Sr., II, III, Lead, Staff, Principal, Head of, VP. A bank’s Vice President is a mid-level individual contributor; a startup’s is an executive. The [job title hierarchy](/blog/job-title-hierarchy) post maps the ladders.
-   **Noise inside the title.** “(Remote)”, “- Austin, TX”, “Req #48213”, “Contract to Hire”, “Platform Team”. All useful, none of it the occupation.
-   **Ambiguity.** Engineer can be software, mechanical or sales. Consultant, Analyst and Manager mean nothing without the function.
-   **Language and locale.** Ingénieur logiciel, Softwareentwickler and Desarrollador de software are one occupation in three spellings, and the same corpus holds all three.

## How a title becomes normalized\_title, occupation\_code, seniority and job\_function

JobsPipe resolves every posting into four fields that answer four questions: what the job is called once the noise is stripped (`normalized_title`), which occupation it is (`occupation_code`, ISCO-08, with `occupation_label`), how senior it is (`seniority`), and which part of the business it sits in (`job_function`).

-   **normalized\_title** keeps the occupation words and drops level tokens, locations, requisition codes and team names. It is the field to group by when you want “data engineer” as one line rather than forty.
-   **occupation\_code** is a four-digit ISCO-08 unit group, resolved from the title with the description as tie-breaker. Because ISCO is hierarchical, a one-, two- or three-digit prefix matches the whole branch: `25` is every ICT professional, `2512` is software developers.
-   **seniority** takes one of five values: `entry_level`, `mid_level`, `senior`, `director` and `executive`. The API records where the level came from in `seniority_source`, and postings that state no level are left null rather than guessed. `is_manager` is a separate boolean for people management.
-   **job\_function** places the posting in a business function such as Engineering, Sales or Finance and Accounting, which is the dimension the [in-demand skills](/blog/in-demand-skills) tables are cut by.

Seniority is the layer with the biggest coverage gap, because most employers do not state a level and the honest output is null. The share of postings with a labelled level differs sharply by board:

-   LinkedIn48.6%
-   Ashby39.0%
-   Greenhouse38.2%
-   Y Combinator36.8%
-   Workday32.9%
-   Lever29.6%
-   SmartRecruiters26.3%
-   Workable22.3%
-   Indeed17.9%
-   Paylocity7.4%

Share of active postings with a labelled seniority level, by board.

That gap is why `job_seniority_or` excludes unlabelled postings by default and offers `include_unlabeled_seniority` to bring them back. Filtering on a level always trades recall for precision; the bars show how much recall each board loses.

How this was measured

Measured from active postings per collected board. Generated 2026-09-09. Shares only: JobsPipe publishes percentages, not counts.

Seniority coverage is the share of a board’s active postings with a non-empty normalised seniority value. Cross-sectional, shares only.

```
curl -X POST https://api.jobspipe.dev/v1/jobs/search \
  -H "Authorization: Bearer $JOBSPIPE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"source_or":["greenhouse"],"job_seniority_or":["senior"],"limit":50}'
```

## Job title classification methods: rules, lookup tables and embeddings

Three methods cover the field, and production systems use all three in sequence: rules for level and noise, lookup tables for the titles that recur, and a model for the long tail.

-   **Rules.** Regular expressions and token lists strip locations, requisition codes and parentheticals, and detect level words. Rules are transparent, cheap and exactly as good as the list. They handle seniority well and occupation badly.
-   **Lookup tables.** A curated map from cleaned title to occupation code, seeded from the ESCO and ISCO title lists and grown from the corpus. A few thousand entries cover the bulk of postings because titles follow a steep frequency curve. Misses fall through to the next method.
-   **Embeddings and classifiers.** Encode the title, and the first lines of the description for ambiguous cases, and pick the nearest occupation by similarity or with a trained classifier. This handles the long tail and other languages, at the cost of explainability and occasional confident errors on invented titles.

Whichever stack you build, keep the raw title. Every normalisation loses something, and the raw string is the only way to audit a bad code later.

## Job title vs occupation: what is the difference?

A job title is what one employer calls one position; an occupation is the standardised category that many titles map to. Titles vary by company, occupations do not. When you count demand, compare pay or match candidates across employers, you want the occupation; when you talk to the employer, you use the title.

## How to filter with occupation\_code\_or and job\_seniority\_or

Title matching with `job_title_or` is the right tool when you know the exact phrasing you want. Occupation codes are the right tool when you want every phrasing of one job. This pulls senior and director-level ICT professionals in Germany:

```
curl -X POST https://api.jobspipe.dev/v1/jobs/search \
  -H "Authorization: Bearer $JOBSPIPE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "occupation_code_or": ["25"],
    "job_seniority_or": ["senior", "director"],
    "job_country_code_or": ["DE"],
    "posted_at_max_age_days": 30,
    "limit": 50
  }'
```

And the same query with unlabelled postings included, for recall:

```
curl -X POST https://api.jobspipe.dev/v1/jobs/search \
  -H "Authorization: Bearer $JOBSPIPE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "occupation_code_or": ["2512", "2513", "2519"],
    "job_seniority_or": ["senior"],
    "include_unlabeled_seniority": true,
    "posted_at_max_age_days": 30,
    "limit": 50
  }'
```

Each returned row carries `job_title`, `normalized_title`, `occupation_code`, `occupation_label`, `seniority` and `job_function`, so you can group on whichever layer your product needs and audit against the raw title. The skills side of the same records is the [skills taxonomy](/blog/skills-taxonomy); the full record is described in the [job description dataset](/blog/job-description-dataset) post.

Query postings by occupation code and seniority, not by guessing titles.

![](/listly/shape-heart.png)

FAQs

## Frequently Asked Questions

### What is a job title taxonomy?

A controlled vocabulary that maps the free-text titles employers write onto a fixed set of occupations, levels and functions, so that variants such as Sr. SWE II and Senior Software Engineer land on the same node. It has layers: a cleaned title, an occupation code from a public standard such as ISCO-08 or SOC, a seniority level and a business function, each answering a different question.

### How does JobsPipe classify job titles?

Every posting is resolved into four fields: normalized\_title, the title with level, location and noise stripped; occupation\_code, a four-digit ISCO-08 unit group with occupation\_label; seniority, one of entry\_level, mid\_level, senior, director or executive, with seniority\_source recording where it came from and null when the posting states no level; and job\_function, the business function. is\_manager is a separate boolean for people management.

### What methods are used for job title classification?

Three, usually in sequence: rules (regular expressions and token lists) to strip noise and detect level words; lookup tables mapping cleaned titles to occupation codes, seeded from ESCO and ISCO title lists and grown from the corpus; and embeddings or a trained classifier for the long tail and other languages. Rules handle seniority well and occupation badly, tables cover the frequent titles, models cover the rest at the cost of explainability.

### What is the difference between a job title and an occupation?

A job title is what one employer calls one position; an occupation is the standardised category that many titles map to. Titles vary by company, occupations do not. When you count demand, compare pay or match candidates across employers you want the occupation code; when you talk to the employer you use the title.

### How do I filter jobs by occupation code and seniority in the API?

Use occupation\_code\_or with ISCO-08 codes: a four-digit code such as 2512 matches exactly and a one- to three-digit prefix such as 25 matches the whole branch. Use job\_seniority\_or with any of entry\_level, mid\_level, senior, director and executive. Unlabelled postings are excluded by default; pass include\_unlabeled\_seniority true to bring them back, because the share of postings with a labelled level differs sharply by board.

[

← Previous

Job description dataset: what a posting record contains, the schema, and how to pull a live slice

](/blog/job-description-dataset)[

Next →

What is an MCP server? How MCP works, with a real example

](/blog/what-is-an-mcp-server)

---
Canonical URL: https://jobspipe.dev/blog/job-title-taxonomy
Title: Job title taxonomy: how raw titles become normalized titles, ISCO-08 codes, seniority and function
Description: What a job title taxonomy is, why raw titles resist it, how JobsPipe resolves every posting into normalized_title, occupation_code, seniority and job_function, the share of postings with a labelled level on each board, the three classification methods (rules, lookup tables, embeddings), job title versus occupation, and how to filter with occupation_code_or and job_seniority_or.

---
AI agents: the full machine-readable index of this site is https://jobspipe.dev/llms.txt?src=md-twin - API quickstart, no-key sandbox (POST https://api.jobspipe.dev/v1/sandbox/jobs/search), MCP server, pricing. Free key: https://jobspipe.dev/signup