Glassdoor Salary Data API in Python: Estimates by Job Title, City, and Company

Published October 8, 2026

"How much should this role pay?" is really three questions: what does the market pay for the title in this city, what does each target employer pay for the same role, and how wide is the spread between them. Answering it by hand means hours of tab-switching; answering it with a scraper means maintaining proxies, login walls and brittle parsers. A Glassdoor salary data API collapses the whole workflow into documented GET requests.

This guide builds a small compensation-benchmarking script in Python: resolve company names to their Glassdoor company IDs with company-search, pull a salary estimate per employer with company-salaries, get the market-wide baseline with salary-estimate, and assemble the results into a comparison table exported to CSV.

The Glassdoor Employer Data API is an unofficial data service, not an affiliated Glassdoor integration. It returns publicly available content as JSON for research and informational purposes; figures are employee-reported estimates retrieved at request time, not a guarantee of current compensation.

Endpoints at a glance

OperationRequired inputRole in the workflow
company-searchqueryResolve an employer name to its company_id, rating and headquarters
company-salariescompany_id, job_titleMin/median/max total pay for one role at one employer
salary-estimatejob_title, locationMarket pay range for a title in a city — no company needed
company-salaries-v2company_idPage through every reported role at one employer

All four were verified live against a real employer (Google, company ID 9079): search, per-company estimates, market estimates and the full salary list all return current production data. An unknown company ID returns a clean empty result rather than an error.

Step 1 — Prepare an authorized platform key

Sign up and copy an active key from your dashboard. Free credits are included for testing. The examples read it from the OPENDATA_API_KEY environment variable; substitute YOUR_API_KEY only when you actually run a request.

No Glassdoor account, cookie or session token is involved — the platform key is the only credential. Because the key travels in the query URL, keep URLs out of shared links, screenshots and logs, and run production calls server-side.

Step 2 — Resolve company names to IDs

Every company-scoped endpoint keys off the numeric company_id. company-search turns a typed name into ranked hits:

curl --get 'https://api.opendata-api.com/api/project/glassdoor/company-search?key=YOUR_API_KEY' \
  --data-urlencode 'query=google' \
  --data-urlencode 'limit=5'

Each hit in the data array carries company_id, name, rating, review_count, salary_count, job_count, headquarters_location and logo. A search for google returns Google first with company_id 9079. Cache the name-to-ID mapping; it is stable, and re-searching on every run wastes credits.

Step 3 — Pull the salary estimate at one company

company-salaries estimates pay for one role at one employer. Pass company_id and job_title, plus an optional location and years_of_experience band:

curl --get 'https://api.opendata-api.com/api/project/glassdoor/company-salaries?key=YOUR_API_KEY' \
  --data-urlencode 'company_id=9079' \
  --data-urlencode 'job_title=software engineer' \
  --data-urlencode 'location=san francisco' \
  --data-urlencode 'location_type=CITY' \
  --data-urlencode 'years_of_experience=FOUR_TO_SIX'

The response data is a single estimate: min_salary, median_salary and max_salary for total pay, separate *_base_salary and *_additional_pay splits, salary_period (for example YEAR), salary_currency (for example USD), the salary_count of employee reports behind the figure and a confidence label. Always read salary_count and confidence before quoting a number — a wide range backed by thousands of reports means something different from a narrow one backed by three.

Step 4 — Get the market baseline

salary-estimate needs no company at all — just a title and a place:

curl --get 'https://api.opendata-api.com/api/project/glassdoor/salary-estimate?key=YOUR_API_KEY' \
  --data-urlencode 'job_title=software engineer' \
  --data-urlencode 'location=san francisco' \
  --data-urlencode 'location_type=CITY'

It returns an estimated pay range for that role in that market with the salary period and currency. This is the open-question endpoint: it answers "what does a marketing assistant make in Chicago" before any employer shortlist exists, and it is the yardstick for judging whether a specific employer's estimate sits above or below market.

Step 5 — Assemble the comparison table in Python

This bounded script resolves a shortlist of companies, pulls each employer's estimate for one title and city, fetches the market baseline, and writes a CSV. No response is hard-coded; missing fields stay missing.

import csv
import os
import requests

BASE = "https://api.opendata-api.com/api/project/glassdoor"
API_KEY = os.environ["OPENDATA_API_KEY"]


def call(operation, **params):
    try:
        response = requests.get(
            f"{BASE}/{operation}",
            params={**params, "key": API_KEY}, timeout=30,
        )
    except requests.RequestException:
        raise RuntimeError("Request failed; use redacted diagnostics") from None
    if not response.ok:
        raise RuntimeError(f"HTTP {response.status_code}")
    gateway = response.json()
    if gateway.get("code") != 200:
        raise RuntimeError("Gateway business failure; inspect code/message safely")
    return gateway.get("data")


def resolve_company_id(name):
    hits = call("company-search", query=name, limit=5) or []
    for hit in hits:
        if hit.get("name", "").lower() == name.lower():
            return hit.get("company_id"), hit
    return (hits[0].get("company_id"), hits[0]) if hits else (None, None)


JOB_TITLE = "software engineer"
LOCATION = "san francisco"
COMPANIES = ["google", "meta", "netflix"]

market = call("salary-estimate", job_title=JOB_TITLE,
              location=LOCATION, location_type="CITY")

rows = []
for name in COMPANIES:
    company_id, hit = resolve_company_id(name)
    if company_id is None:
        continue  # no match: skip instead of retrying
    estimate = call("company-salaries", company_id=company_id,
                    job_title=JOB_TITLE, location=LOCATION,
                    location_type="CITY") or {}
    rows.append({
        "company": (hit or {}).get("name", name),
        "company_id": company_id,
        "rating": (hit or {}).get("rating"),
        "min_total": estimate.get("min_salary"),
        "median_total": estimate.get("median_salary"),
        "max_total": estimate.get("max_salary"),
        "currency": estimate.get("salary_currency"),
        "reports": estimate.get("salary_count"),
        "confidence": estimate.get("confidence"),
    })

for row in rows:
    print(f"{row['company']:<12} median={row['median_total']} "
          f"({row['reports']} reports, {row['confidence']})")
print("Market baseline:", market)

with open("compensation-comparison.csv", "w", newline="") as handle:
    writer = csv.DictWriter(handle, fieldnames=list(rows[0].keys()))
    writer.writeheader()
    writer.writerows(rows)

The same flow from JavaScript is one fetch per step — for example fetch(`https://api.opendata-api.com/api/project/glassdoor/company-salaries?key=${key}&company_id=${id}&job_title=${title}`) — keeping the key in server-side environment configuration, never in shipped client code.

For a wider pay-distribution view at one employer, company-salaries-v2 pages through every reported role (sorted by report count, pay or recency) instead of querying one title at a time — the right shape for CSV exports of an entire salary surface.

HTTP status versus business status

Two layers matter. The HTTP status reflects transport; the gateway envelope carries code, message and data, where code 200 indicates gateway business success — HTTP 200 alone does not. Inside a successful envelope, a company search with no matches returns an empty data array, and an unknown company_id on the overview endpoint comes back with no data field at all. Program against both layers: check the HTTP status first, then the business code, then whether data is present before reading fields.

Use cases

  • Offer evaluation — compare a candidate's offer against the employer's median and range for the role before advising acceptance.
  • Compensation benchmarking — build a table of min/median/max pay across target employers for the same title, exactly as the script above does.
  • Recruiter enablement — quote real figures per company, role and experience band instead of generic ranges.
  • Relocation analysis — run salary-estimate for the same title across several cities and rank them.
  • Pay-equity checks — contrast experience-band estimates by location within one employer.

FAQ

Does Glassdoor have an official public API for developers?

No public official API exists. This project is an unofficial data service that returns publicly available Glassdoor content as documented JSON, so you do not maintain scrapers, proxy pools or login handling yourself.

How do I get Glassdoor data programmatically?

Call the project endpoints over plain GET requests with your platform API key, as shown above. Python requests, JavaScript fetch or curl all work; there is no SDK to install.

How do I scrape Glassdoor without getting blocked?

Don't scrape; call the API. The endpoints return structured JSON with documented pagination, which removes the IP-rotation, CAPTCHA and HTML-parsing burden entirely.

How do I find a Glassdoor company ID?

Call company-search with the employer name and read company_id from the top hit — 9079 for Google. Cache the mapping; every other company endpoint accepts that token.

How do I get salary data for a job title in a specific city?

Use salary-estimate with job_title and location (set location_type=CITY for precision) for the market range, or company-salaries with a company_id for one employer's estimate.

How do I pull Glassdoor reviews into Python?

Call company-reviews with a company_id and page through ten reviews per request; each review carries structured pros, cons, a rating and per-category sub-ratings ready for sentiment analysis.

How do I search Glassdoor jobs by location and date posted?

job-search takes query and location plus a date_posted window (today, 3 days, week, 2 weeks or month), remote_only, easy_apply_only and min_company_rating filters, with cursor pagination.

How do I get interview questions reported for a company?

Call company-interviews with the company_id; reports include process_description, the actual questions candidates were asked, difficulty, experience sentiment and outcome.

What is the best Glassdoor scraper API?

Judge on coverage and honesty signals: per-endpoint filters, sample-size fields like salary_count and confidence, graceful handling of unknown IDs, and cursor or page pagination that survives long crawls. This project exposes all of those; try it against your own company list.

How do I monitor employee reviews for a company automatically?

Poll company-reviews with sort=MOST_RECENT on a schedule, deduplicate by review_id, and alert when recent ratings for a tracked employer turn negative.

How do I build a salary comparison tool with real data?

Follow the pipeline in this guide: resolve IDs once, pull per-employer estimates for the same title and location, fetch the market baseline with salary-estimate, and store salary_count and confidence next to every figure so thin samples never read as fact.

Try the company search, company salaries and salary estimate references, or start from the Glassdoor project page. APIs for similar platforms — Indeed, LinkedIn Jobs, ZipRecruiter, Levels.fyi, AmbitionBox, Kununu, Comparably, Blind and others — can be added on request through the contact page; private source-code deployment is also available.