# How to Configure Salary Benchmarking with Custom Data in AI-Job-Search

> Configure salary benchmarking with custom data in AI-Job-Search. Place salary_data.json and run salary_lookup.py for personalized job application salary comparisons.

- Repository: [Mads Lorentzen/ai-job-search](https://github.com/MadsLorentzen/ai-job-search)
- Tags: how-to-guide
- Published: 2026-08-05

---

**Place a [`salary_data.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/salary_data.json) file at the repository root and run [`salary_lookup.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/salary_lookup.py) to enable personalized salary comparisons during job applications.**

The AI-Job-Search repository by **MadsLorentzen** includes a dedicated **salary benchmarking system** that lets you compare job offers against proprietary data. This guide explains how to **configure salary benchmarking with custom data** using the built-in [`salary_lookup.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/salary_lookup.py) utility and optional conversion tools.

## Required File Structure

The system expects a single JSON file at a specific location:

- **File**: [`salary_data.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/salary_data.json)
- **Location**: Repository root (same directory as [`salary_lookup.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/salary_lookup.py))
- **Discovery path**: `Path(__file__).parent / "salary_data.json"` in [[`salary_lookup.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/salary_lookup.py) line 27](https://github.com/MadsLorentzen/ai-job-search/blob/master/salary_lookup.py#L27)

If the file is missing, the tool exits gracefully and the `/apply` workflow skips salary comparison entirely.

## Creating Your Custom Salary Data

### Option 1: Manual JSON Creation

Create [`salary_data.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/salary_data.json) with this structure:

```json
{
  "metadata": {
    "source": "My Union Statistics 2025",
    "index_baseline": 100,
    "index_label": "Index",
    "baseline_description": "Index 100 = median salary for private sector"
  },
  "companies": [
    {
      "company": "Novo Nordisk A/S",
      "city": "Bagsværd",
      "categories": {
        "all_employees": { "count": 500, "index": 108.5 },
        "engineering":   { "count": 120, "index": 112.3 }
      }
    },
    {
      "company": "Ørsted A/S",
      "city": "Fredericia",
      "categories": {
        "all_employees": { "count": 200, "index": 105.2 }
      }
    }
  ]
}

```

**Required fields**:
- `metadata.index_baseline` — numeric baseline for percentage calculations
- `companies[].company` — full legal name (normalization handles suffixes)
- `companies[].categories` — object with numeric `index` and optional `count`

### Option 2: Convert from Excel

Use the helper script to transform spreadsheet data:

```bash
pip install openpyxl
python3 tools/convert_salary_excel.py path/to/salary-data.xlsx \
  --source "My Salary Data 2025" \
  --baseline 100 \
  --baseline-desc "Index 100 = median salary"

```

The script in [[`tools/convert_salary_excel.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/convert_salary_excel.py) line 295](https://github.com/MadsLorentzen/ai-job-search/blob/master/tools/convert_salary_excel.py#L295) auto-detects company/city columns and outputs [`salary_data.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/salary_data.json) to the repository root.

## Validating Your Configuration

Before using your data, verify its structure:

```bash
python3 salary_lookup.py --validate

```

The validation logic in [`collect_validation_issues()`](https://github.com/MadsLorentzen/ai-job-search/blob/master/salary_lookup.py#L54-L125) checks:

- Metadata object presence
- Companies array structure
- Required field completeness
- Numeric type consistency

Hard errors trigger `fail_data_error()` and abort execution; warnings print but allow continuation.

## Querying Your Custom Benchmarks

### CLI Usage

```bash

# Human-readable table (default)

python3 salary_lookup.py "Novo Nordisk"

# Machine-readable JSON

python3 salary_lookup.py "Ørsted" --json

```

### How Fuzzy Matching Works

The `search_company()` function in [[`salary_lookup.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/salary_lookup.py) lines 63-89](https://github.com/MadsLorentzen/ai-job-search/blob/master/salary_lookup.py#L63-L89) implements:

1. **Normalization**: Lower-casing, stripping legal suffixes, removing non-alphanumerics via `normalize()` ([lines 64-70](https://github.com/MadsLorentzen/ai-job-search/blob/master/salary_lookup.py#L64-L70))
2. **Anglicization**: Character substitutions via `anglicize()` ([lines 73-78](https://github.com/MadsLorentzen/ai-job-search/blob/master/salary_lookup.py#L73-L78))
3. **Scoring**: `match_score_optimized()` with pre-calculated query representations
4. **Filtering**: Results with score ≥ 30 are retained

### Programmatic Access

```python
from salary_lookup import load_data, search_company

data = load_data()                     # validates & reads salary_data.json

matches = search_company(data, "COWI") # returns ranked list of matches

print(matches[0]["categories"]["engineering"]["index"])

```

## Integration with Job Applications

When [`salary_data.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/salary_data.json) exists, the `/apply` command automatically:

1. Extracts company name from the job posting
2. Calls `search_company()` for fuzzy matching
3. Injects formatted results into the application report via `format_entry()`

If no match exists, the workflow continues without salary data—no blocking errors.

## Key Implementation Files

| File | Purpose | Critical Functions |
|------|---------|------------------|
| [`salary_lookup.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/salary_lookup.py) | Core engine | `load_data()`, `search_company()`, `validate_data()` |
| [`tools/convert_salary_excel.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/convert_salary_excel.py) | Excel→JSON conversion | Autodetection logic at [line 263](https://github.com/MadsLorentzen/ai-job-search/blob/master/tools/convert_salary_excel.py#L263) |
| [`tools/README_SALARY_TOOL.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/README_SALARY_TOOL.md) | Format documentation | Schema examples and field descriptions |
| [`tests/test_salary_lookup.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tests/test_salary_lookup.py) | Behavior reference | Edge cases and validation scenarios |

## Summary

- **Place** [`salary_data.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/salary_data.json) at the repository root to activate custom benchmarking
- **Create** data manually or convert from Excel using [`tools/convert_salary_excel.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/convert_salary_excel.py)
- **Validate** with `python3 salary_lookup.py --validate` before deployment
- **Query** via CLI or Python API; fuzzy matching tolerates naming variations
- **Integrate** automatically with `/apply` workflow when file is present

## Frequently Asked Questions

### What happens if I don't create salary_data.json?

The AI-Job-Search tool exits cleanly with an informative message, and the `/apply` workflow proceeds without salary comparison. No application errors occur.

### How does the fuzzy matching handle company name variations?

The `normalize()` function strips legal suffixes like "A/S" and "Inc.", converts to lowercase, and removes special characters. The `anglicize()` function further standardizes international characters. Scores below 30 are filtered out automatically.

### Can I use multiple data sources or update the file dynamically?

The system reads [`salary_data.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/salary_data.json) once per invocation. You can replace or modify the file between runs; no caching persists. To merge multiple sources, consolidate them into a single JSON file before placement.

### What Excel formats does convert_salary_excel.py support?

The script uses `openpyxl` for `.xlsx` files. Column headers should include "company" and optionally "city"; remaining numeric columns become category indices. Run with `--help` to see all CLI options for baseline configuration.