Blog / API guides

Glassdoor API: Company Reviews and Salaries as JSON

Glassdoor's own API is closed to new developers, so you can't sign up for one. The Perceptlayer Glassdoor API returns the same kind of data as JSON instead: search a company by name, take its employer_id, then call the reviews, overview and salaries endpoints. Each successful call costs 1 credit, and failed calls cost nothing.

Is there an official Glassdoor API you can still use?

Not for a new project. Glassdoor's Partner API program was closed to new applications in 2021 (API Evangelist, 2021), and Zuplo's guide to the API says the same: Glassdoor closed off public access to its API in 2021 (Zuplo, 2024). That leaves no self-serve route where you request a key and start calling.

If you hold an existing partner agreement, use it: that's the first-party route and the one with Glassdoor's terms attached. If you don't, the options are scraping the pages yourself or calling an API that returns the public data as JSON. For the maintenance side of the first option, see what maintaining a scraper really involves.

What does the Glassdoor API return?

The Glassdoor API has six endpoints in the Jobs area. Three look up companies, one returns reviews, one returns salaries and one searches job listings. Every response is JSON with named fields, and the data is collected from publicly available sources and returned as found at the time of the call.

Endpoint Returns Credits Required Optional
/v1/glassdoor/companies-autocomplete Companies Autocomplete 1 query none
/v1/glassdoor/companies-search Companies Search 1 query page, limit
/v1/glassdoor/companies-overview Companies Overview 1 employer_id none
/v1/glassdoor/companies-reviews Companies Reviews 1 employer_id page, limit
/v1/glassdoor/salaries Salaries 1 job_title employer_id, page, limit
/v1/glassdoor/jobs-search Jobs Search 1 keyword cursor

The string parameters (query, job_title, keyword) accept up to 100 characters. employer_id and the paging parameters page and limit are integers. The catalogue doesn't document defaults or page sizes for page and limit, so read page, total_pages and has_more from each response instead of assuming a size.

How do you find a company's employer ID?

Call companies-search with the company name. The response lists matching employers, and each one has an id you pass as employer_id to the other endpoints. The search can return several employers with similar names, so check the name and review_count before you pick one.

curl "https://api.perceptlayer.com/v1/glassdoor/companies-search?query=Stripe" \
  -H "X-API-Key: $API_KEY"

A recorded response, trimmed:

{
  "success": true,
  "data": {
    "query": "Stripe",
    "companies": [
      {
        "id": 671932,
        "name": "Stripe",
        "rating": 3.8,
        "review_count": 1619,
        "salary_count": 4702,
        "job_count": 3
      },
      {
        "id": 5554043,
        "name": "Stripe OLT",
        "rating": 4,
        "review_count": 24,
        "salary_count": 38,
        "job_count": 0
      }
    ],
    "page": 1,
    "total_pages": 5,
    "has_more": true
  },
  "meta": {
    "endpoint_family": "company_search",
    "billable": true
  }
}

Two employers match "Stripe". The first, 671932, has 1,619 reviews; the second has 24. A script that blindly takes companies[0] works here, but for ambiguous names it's safer to compare name exactly and fall back to the highest review_count.

For a type-ahead box rather than a full result list, companies-autocomplete takes the same query parameter. Use companies-search when you need the counts and ratings to disambiguate.

How do you get company reviews as JSON?

Pass the employer ID to companies-reviews. The response holds a company object, a reviews array and paging fields. In the recorded Stripe response, total_reviews is 1564 across 157 pages. Reviews are returned as company-level data: a rating, free text, a job title and a location, with no reviewer names.

curl "https://api.perceptlayer.com/v1/glassdoor/companies-reviews?employer_id=671932" \
  -H "X-API-Key: $API_KEY"

A recorded response, trimmed:

{
  "success": true,
  "data": {
    "company": {
      "id": 671932,
      "name": "Stripe",
      …
    },
    "reviews": [
      {
        "id": 106035163,
        "date": "2026-10-20T11:12:55Z",
        "summary": "Progressive environment with intense performance expectations",
        "pros": "Progressive workplace environment\nGood benefits\nGood compensation",
        "cons": "Intense performance ecosystem\nOffice is moving to less convenient location",
        "rating": 4,
        "job_title": "Software Engineer",
        "is_current_employee": true,
        "location": "Toronto, ON"
      },
      {
        "id": 106018689,
        "rating": 3,
        "ratings": {
          "career_opportunities": 3,
          "compensation_and_benefits": 3,
          "culture_and_values": 3,
          "diversity_and_inclusion": 4,
          "senior_leadership": 3,
          "work_life_balance": 3
        },
        …
      }
    ],
    "page": 1,
    "total_pages": 157,
    "total_reviews": 1564,
    "has_more": true
  },
  …
}

Which review fields can you rely on?

The excerpt above shows the first review in full and only the rating fields of the second; the full recorded sample has two reviews. Both carry id, date, summary, pros, cons, rating, job_title, is_current_employee and location. Only the second also carries a ratings object (shown above) with career_opportunities, compensation_and_benefits, culture_and_values, diversity_and_inclusion, senior_leadership and work_life_balance. Treat ratings as optional in your code.

pros and cons are plain strings with line breaks (\n), and some reviewers format them as bullet lists with leading dashes. Split on newlines and strip a leading - if you want one point per row.

What can you do with review data?

Aggregate it. Average rating per month, count reviews by job_title, or split by is_current_employee to compare current and former staff. Because every review has an id, you can store them and deduplicate when you re-pull. Keep the analysis at company level: group and count, and don't try to identify who wrote a review.

How do you get salary data by job title?

Call salaries with a job_title. employer_id is optional. In the recorded call below, which doesn't pass it, the response holds rows for several employers plus an estimate block for the whole title. Each row has base pay, additional pay and total_pay percentiles.

curl "https://api.perceptlayer.com/v1/glassdoor/salaries?job_title=software+engineer" \
  -H "X-API-Key: $API_KEY"

A recorded response, trimmed:

{
  "success": true,
  "data": {
    "job_title": "software engineer",
    "salaries": [
      {
        "job_title": "Software Engineer",
        "employer": {
          "id": 9079,
          "name": "Google",
          "rating": 4.4
        },
        "currency": "USD",
        "pay_period": "ANNUAL",
        "base_pay_mean": 184722.83,
        "additional_pay_mean": 126972.82,
        "total_pay": {
          "p10": 207909.08,
          "p25": 251388.51,
          "p50": 311695.65,
          "p75": 396273.52,
          "p90": 486503.67
        }
      },
      …
    ],
    "page": 1,
    "total_pages": 10438,
    "total_results": 104377,
    "has_more": true,
    "estimate": {
      "location": "United States",
      "confidence": "CONFIDENT",
      "salaries_count": 727155,
      "total_pay": {
        "p10": 99464.84,
        "p50": 152101.59,
        "p90": 237195.82
      },
      …
    }
  },
  …
}

How do you read the percentiles?

In this recording, the Google row has a total_pay median (p50) of 311,695.65 USD a year, against 152,101.59 USD for the estimate across all employers in the United States. The gap between base_pay_mean (184,722.83) and additional_pay_mean (126,972.82) shows why total pay, not base pay, is the field to compare for employers that pay in stock and bonuses.

Two cautions. These are figures as found at the time of the call, not a guarantee of accuracy, and the estimate carries its own confidence value and salaries_count. Check both before you quote a number. Also, with 10,438 pages for one title, don't page through everything: plan your questions so one page answers them.

Which parameters narrow a salary query?

Parameter Type Required Use
job_title string, up to 100 characters yes The title to look up, such as software engineer
employer_id integer no An employer id from companies-search
page integer no Move through results; read total_pages and has_more
limit integer no Ask for a number of rows per page

What does it cost to pull a company's data?

Every Glassdoor endpoint is 1 credit per successful call, and a failed call returns X-Credits-Used: 0 and bills nothing. A full pull of one company is cheap: one search call, one overview call and one call per page of reviews.

Using the recorded Stripe numbers, 157 pages of reviews means 157 calls. The arithmetic: 1 search + 1 overview + 157 review pages = 159 credits, which fits inside the 1,000 free credits you get every month after verifying an email address. No credit card is needed.

At volume, you buy prepaid credit packs of 10,000 (Starter), 50,000 (Build), 200,000 (Growth), 500,000 (Pro), 1,000,000 (Scale) or 5,000,000 (Volume) credits. Purchased credits last 12 months. See pricing for what credits cost.

Tracking 100 employers, each pulled once with all 157 pages as in the Stripe example, is 100 × 159 calls × 1 credit = 15,900 credits. That's more than the Starter pack's 10,000 and within the Build pack's 50,000. Real companies vary widely in review count, so read total_pages from the first reviews response before you loop. See credits in the docs.

Every successful response carries X-Credits-Used and X-Credits-Remaining, so you can stop a loop when the balance gets low. The service is prepaid: when credits run out, calls return insufficient_credits (402) and nothing more is debited.

How do you handle errors and rate limits?

Errors come back with an HTTP status and a JSON body: {"error": {"code", "message", "request_id"}}. The ones you'll meet on this API are invalid_parameters (422) for parameters the endpoint doesn't accept, invalid_api_key (401), insufficient_credits (402), rate_limited (429) and temporarily_unavailable (503).

For 429 and 503, wait the number of seconds in the Retry-After header and try again. Requests have no idempotency key, so if a client timeout hides the reply, the call may have succeeded and been billed. Count that possibility in your retry logic, and see the error codes and rate limits in the docs. The pattern is covered in retrying web API calls without paying twice.

How do you page through a long reviews list?

Loop on page until has_more is false. Start at 1, keep the id of every review you store, and stop early if X-Credits-Remaining falls under your floor. On a 429 or 503, wait the Retry-After seconds and retry the same page. The loop below needs only requests.

import os
import time
import requests

BASE = "https://api.perceptlayer.com/v1/glassdoor"
HEADERS = {"X-API-Key": os.environ["API_KEY"]}
CREDIT_FLOOR = 50

def get(path, **params):
    while True:
        r = requests.get(f"{BASE}/{path}", headers=HEADERS, params=params, timeout=30)
        if r.status_code in (429, 503):
            time.sleep(int(r.headers.get("Retry-After", "1")))
            continue
        r.raise_for_status()
        return r.json()["data"], int(r.headers["X-Credits-Remaining"])

(found, _) = get("companies-search", query="Stripe")
company = found["companies"][0]
reviews, page = {}, 1
while True:
    data, remaining = get("companies-reviews", employer_id=company["id"], page=page)
    for review in data["reviews"]:
        reviews[review["id"]] = review
    if not data["has_more"] or remaining < CREDIT_FLOOR:
        break
    page += 1

print(company["name"], len(reviews), "reviews;", remaining, "credits left")

Keying the dictionary on id means a repeated page can't create duplicates. A free account is limited to 1 request a second (60 a minute), so the 157 pages of the Stripe example take about 3 minutes, and a 429 sends the loop to sleep for the Retry-After it is given. Paid accounts run at least 5 requests a second. If a client timeout hides a reply, that page may have been billed once already, which the id keys absorb on the re-pull but the credits don't. For a fuller treatment, see paginating a web data API in Python, and to avoid paying twice for the same page, cache API responses.

Run the first call in the playground on the Glassdoor API page to see the shape before you write code, then get a free API key. For authentication details, see the docs. If you're building job-market tooling, the Indeed Jobs API guide covers postings, and the Trustpilot reviews guide covers customer reviews of the same companies.

APIs in this post

Frequently asked questions

Does Glassdoor have a public API?

Not one you can join today. Its Partner API was closed to new applications in 2021 (API Evangelist, 2021), and public access to the API ended that year (Zuplo, 2024). The Perceptlayer Glassdoor API fills that gap with six endpoints and one key, at 1 credit per successful call.

How much does the Glassdoor API cost?

Each of the six endpoints costs 1 credit per successful call. You get 1,000 free credits every month after verifying an email, with no credit card. Paid packs start at 10,000 credits (Starter), so 10,000 calls × 1 credit = 10,000 credits; pricing has what credits cost. Failed calls cost nothing.

Can I get reviewer names from the reviews endpoint?

The recorded companies-reviews response has no reviewer names. Each review has a rating, summary, pros, cons, job title, employment status and location. That fits company-level analysis such as rating trends and themes, and you should keep your analysis at that level too.

How do I get salaries for one company only?

Look up the company with companies-search, then call salaries with both job_title and that company's employer_id, which is an optional parameter. The recorded call without it returned rows across many employers plus an overall estimate. Check the rows' employer field for the company you asked about. Both forms cost 1 credit per call.

Can an AI agent call these endpoints?

Yes. The MCP server at https://api.perceptlayer.com/mcp exposes search_endpoints, get_endpoint and call_endpoint. The first two only look up the catalogue and cost nothing; call_endpoint spends the endpoint's 1 credit on success. Setup is in the MCP docs.

  1. Salary Data from Job Sites: Reading Ranges Without Bias

    Glassdoor's salaries endpoint returns p10 to p90 total pay, a currency and a national count. How to read those ranges and the biases of self-reported pay.

  2. Indeed Jobs API: Get Job Postings as JSON

    One GET to /v1/indeed/jobs returns job postings with company, location and apply URL as JSON for 1 credit. Parameters, a real response and monthly cost.

  3. Cars.com API: Used Car Listings and Price Evaluations

    Search Cars.com listings with its six required parameters (zip, radius_miles, stock_type, sort, page, page_size), then listing, dealer and price-eval calls.

Start with 1,000 free credits

No password to set. We email you a sign-in link, and your key works on every API.

No credit card. 1,000 free credits a month.