# Glassdoor Salary Data by Job Title (`xtracto/glassdoor-salaries`) Actor

Median base pay, median total pay and the full percentile spread for any job title on Glassdoor, plus how many reported salaries back each figure. Returns one row per title.

- **URL**: https://apify.com/xtracto/glassdoor-salaries.md
- **Developed by:** [Farhan Febrian Nauval](https://apify.com/xtracto) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Glassdoor Salary Data by Job Title

Get the median pay for any job title on Glassdoor — base pay, total pay, the full percentile spread, and how many reported salaries each figure is based on.

### Why use this actor

- **Median base pay *and* median total pay**, kept separate — most tools blur the two
- **Full percentile spread** (10th / 25th / 50th / 75th / 90th) so you can see the range, not just the midpoint
- **Sample size on every row** — a median from 58,000 reports means something different from one built on 40
- **Additional pay broken out** (bonus, commission, profit sharing) where Glassdoor publishes it
- No account and no key required
- Stable JSON output, ready for a spreadsheet or a database

### How it works

1. You give the actor a list of job titles (or paste Glassdoor salary page addresses directly).
2. It looks up each title's salary page and reads the published pay figures.
3. Every row records the job title, the pay figures, the currency, the pay period and the number of salary reports behind it.
4. Results stream into your dataset, ready to download as JSON, CSV or Excel.

You don't need to manage scrapers or infrastructure. **Use the default US residential proxy** — Glassdoor limits how many salary pages a single address may request in a short window, and a fresh address per request is what keeps results complete.

### Input

```json
{
  "jobTitles": ["data scientist", "product manager"],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "US"
  }
}
```

| Field | Type | Description |
|---|---|---|
| `jobTitles` | array | Job titles to look up, e.g. `"software engineer"`. One row per title. |
| `startUrls` | array | Optional. Glassdoor salary page addresses, for company- or location-specific pages. |
| `maxItems` | integer | Maximum titles/pages per run. Default 20. |
| `proxyConfiguration` | object | Defaults to US residential — recommended, see above. |

### Output

Real sample from a live run:

```json
{
  "_input": "data scientist",
  "_source": "S1-detailed",
  "_scrapedAt": "2026-08-26T08:12:44Z",
  "recordType": "SALARY_AGGREGATE",
  "url": "https://www.glassdoor.com/Salaries/data-scientist-salary-SRCH_KO0,14.htm",
  "jobTitle": "Data Scientist",
  "salariesCount": 58116,
  "payPeriod": "ANNUAL",
  "currency": "USD",
  "baseMedian": 120678.43,
  "basePay": { "percentile10": 79345.37, "percentile25": 96771.16, "median": 120678.43, "percentile75": 150491.99 },
  "totalMedian": 157630.82,
  "totalPay": { "percentile25": 124485.45, "median": 157630.82, "percentile75": 202225.34 },
  "additionalPay": { "percentile10": 21432.39, "percentile25": 27714.29, "median": 36952.39, "percentile75": 51733.35 }
}
```

| Field | Type | Description |
|---|---|---|
| `jobTitle` | string | The job title as Glassdoor labels it. |
| `salariesCount` | integer | How many reported salaries the figures are based on. |
| `baseMedian` | number | Median base pay. |
| `basePay` | object | Base pay percentiles (10th–90th, where published). |
| `totalMedian` | number | Median total pay (base plus additional). |
| `totalPay` | object | Total pay percentiles. |
| `additionalPay` | object | Bonus / commission / profit sharing percentiles. |
| `payPeriod` | string | Usually `ANNUAL`. |
| `currency` | string | Currency code, e.g. `USD`. |
| `url` | string | The page the figures came from. |

### Notes and limits

- **Coverage measured 5 of 6 titles on a live run** (nurse, accountant, marketing manager, software developer, teacher all returned full figures; `software engineer` did not). A handful of very high-traffic pages are served in a layout that carries no aggregate — `software developer` works where `software engineer` does not, so try a close synonym if a title comes back empty.
- **A title with no published data returns an error row, not an empty one.** If Glassdoor has no aggregate for a title (or serves a reduced page because the address has been requesting too quickly), the row carries `_error` explaining which happened, so a gap never looks like a zero.
- **Base pay is only available on the richer page layout.** When only the summary layout is served, total pay is reported and `baseMedian` is left empty rather than quietly filling it with a total-pay figure — the two are genuinely different numbers.
- Run titles in modest batches. Requesting many pages very quickly from one address triggers a cool-down; the residential proxy default handles this for you.
- Figures are Glassdoor's own estimates from self-reported salaries, not verified payroll data.

# Actor input Schema

## `jobTitles` (type: `array`):

Job titles to look up, e.g. "software engineer". One row is returned per title with its median pay and the number of reported salaries behind it.

## `startUrls` (type: `array`):

Optional. Paste Glassdoor salary page addresses directly — useful for company- or location-specific pages that a plain job title cannot express.

## `maxItems` (type: `integer`):

Maximum number of job titles or pages to process in one run.

## `proxyConfiguration` (type: `object`):

A US residential proxy is strongly recommended. Glassdoor limits how many salary pages one address may request in a short window, and a fresh address per request keeps results complete.

## Actor input object example

```json
{
  "jobTitles": [
    "data scientist",
    "product manager"
  ],
  "startUrls": [
    {
      "url": "https://www.glassdoor.com/Salaries/data-scientist-salary-SRCH_KO0,14.htm"
    }
  ],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `recordType` (type: `string`):

Which kind of row this is.

## `url` (type: `string`):

Direct link to the scraped item.

## `jobTitle` (type: `string`):

Job title.

## `salariesCount` (type: `string`):

Salaries Count. Whole number.

## `payPeriod` (type: `string`):

Pay Period as reported by the source.

## `currency` (type: `string`):

ISO currency code of the price.

## `baseMedian` (type: `string`):

Base Median as reported by the source.

## `basePay` (type: `string`):

Base Pay as reported by the source.

## `totalMedian` (type: `string`):

Total Median as reported by the source.

## `totalPay` (type: `string`):

Total Pay as reported by the source.

## `additionalPay` (type: `string`):

Additional Pay as reported by the source.

## `jobTitleId` (type: `string`):

Job Title Id as reported by the source.

## `queryLocation` (type: `string`):

Query Location as reported by the source.

## `raw` (type: `string`):

Unmodified payload from the source.

## `_input` (type: `string`):

The input value this row was produced from.

## `_source` (type: `string`):

Which extraction strategy produced the row.

## `_scrapedAt` (type: `string`):

UTC timestamp of the scrape, ISO 8601.

## `_error` (type: `string`):

Set only on diagnostic rows - why that target produced no data.

## `_errorDetail` (type: `string`):

Extra context for the error.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "jobTitles": [
        "data scientist",
        "product manager"
    ],
    "startUrls": [
        {
            "url": "https://www.glassdoor.com/Salaries/data-scientist-salary-SRCH_KO0,14.htm"
        }
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("xtracto/glassdoor-salaries").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "jobTitles": [
        "data scientist",
        "product manager",
    ],
    "startUrls": [{ "url": "https://www.glassdoor.com/Salaries/data-scientist-salary-SRCH_KO0,14.htm" }],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("xtracto/glassdoor-salaries").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "jobTitles": [
    "data scientist",
    "product manager"
  ],
  "startUrls": [
    {
      "url": "https://www.glassdoor.com/Salaries/data-scientist-salary-SRCH_KO0,14.htm"
    }
  ],
  "maxItems": 20
}' |
apify call xtracto/glassdoor-salaries --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,xtracto/glassdoor-salaries"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/hOprC654vBnjtjt0t/builds/OtYmrGpwIOB94GJ5I/openapi.json
