# Glassdoor Jobs Scraper: Salary, ZIP & Company (`kuantum/glassdoor-jobs-scraper`) Actor

Scrape public Glassdoor jobs by profession, city, ZIP code, company, salary, remote status, job type, and posting date. Export formatted Excel and Google Sheets-ready data.

- **URL**: https://apify.com/kuantum/glassdoor-jobs-scraper.md
- **Developed by:** [\[R\] Kuantum](https://apify.com/kuantum) (community)
- **Categories:** Jobs, Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$4.99 / 1,000 saved job results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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 Jobs Scraper: Salary, ZIP & Company

Collect clean, structured public Glassdoor job listings by **profession, job title, keyword, city, area, ZIP/postal code, company, salary, workplace type, and posting age**. Export the results as a professionally formatted Excel workbook, a Google Sheets-ready table, CSV, JSON, XML, or through the Apify API.

This Actor is designed for recruiters, sourcing teams, labor-market researchers, job boards, competitive-intelligence teams, sales operations, and job seekers who need repeatable job-market data without manual copying.

### What can this Glassdoor scraper do?

- Search multiple professions or job titles in one run.
- Combine every keyword with multiple cities, regions, or ZIP/postal codes.
- Resolve ZIP codes through Glassdoor's public location selector and apply a mileage radius.
- Include selected companies or exclude staffing firms and unwanted employers.
- Filter by minimum and maximum salary with hourly/yearly normalization.
- Search for remote jobs, Easy Apply listings, employment types, and recent postings.
- Match keywords in the job title or description.
- Accept canonical Glassdoor search URLs and individual job URLs.
- Deduplicate jobs across overlapping searches.
- Return complete, stable records with unavailable fields represented as `null`.
- Save blocks and extraction errors separately from successful job results.

### Quick start

1. Enter one or more values in **Job titles or keywords**.
2. Add cities, regions, or ZIP codes and choose a search radius.
3. Add any company, salary, remote, date, or employment filters.
4. Set the maximum number of jobs and click **Start**.
5. Download the dataset or connect it to your workflow through the API, webhook, Make, Zapier, Google Sheets, or another Apify integration.

For the most reliable run, keep **Open every job for full details** disabled. Summary mode normally returns the job title, company, rating, location, salary, Easy Apply status when visible, and job URL. Enable full details only when you need descriptions, skills, benefits, or qualifications.

### Example input with multiple filters

```json
{
  "keywords": ["registered nurse", "nurse practitioner"],
  "locations": ["Miami, FL"],
  "zipCodes": ["33101"],
  "radiusMiles": 25,
  "companyNames": ["Baptist Health", "HCA"],
  "excludeCompanies": ["Staffing Agency"],
  "descriptionKeywords": ["pediatrics", "ICU", "emergency"],
  "postedWithinDays": 14,
  "remoteOnly": false,
  "easyApplyOnly": false,
  "employmentTypes": ["FULL_TIME"],
  "minSalary": 80000,
  "maxSalary": 180000,
  "salaryPeriod": "YEAR",
  "includeSalaryUnknown": false,
  "includeJobDetails": false,
  "maxItems": 100,
  "maxConcurrency": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

This example searches two nursing professions around Miami and ZIP `33101`, keeps jobs from either selected healthcare company, excludes matching staffing companies, applies salary and posting-age limits, and retains title/description matches for any of the requested clinical terms.

#### How multiple filters are combined

- Different filter categories are combined with **AND**.
- Multiple `keywords` create separate Glassdoor searches.
- Keywords are combined with every value in `locations` and `zipCodes`, up to 50 generated search combinations.
- Multiple `companyNames` use **OR**: a job can match any included company.
- Multiple `descriptionKeywords` use **OR**: the title or description can contain any requested term.
- Multiple `employmentTypes` use **OR**.
- Any `excludeCompanies` match removes the job.

Description and employment-type data are usually available only in full-detail mode. Glassdoor can block direct job-detail pages, so those filters are best effort.

### Output example

Each successful dataset item represents one job:

```json
{
  "recordType": "job",
  "jobId": "JV_IC1132200_KO0,60_KE61,76",
  "title": "Automation & Internal Tools Builder",
  "companyName": "Example Company",
  "companyRating": 4.2,
  "locationText": "Brooklyn, NY",
  "city": null,
  "state": null,
  "postalCode": null,
  "country": null,
  "workplaceType": "unknown",
  "employmentTypes": [],
  "employmentTypesText": null,
  "salaryMin": 20,
  "salaryMax": 35,
  "salaryCurrency": "USD",
  "salaryPeriod": "HOUR",
  "salaryAnnualMin": 41600,
  "salaryAnnualMax": 72800,
  "salaryHourlyMin": 20,
  "salaryHourlyMax": 35,
  "salaryText": "$20.00 - $35.00 Per Hour (Employer provided)",
  "salarySource": "employer",
  "datePosted": null,
  "descriptionText": null,
  "skills": [],
  "skillsText": null,
  "easyApply": null,
  "jobUrl": "https://www.glassdoor.com/job-listing/...",
  "searchKeyword": "software engineer",
  "searchLocation": "10001",
  "source": "generated-search",
  "scrapedAt": "2026-09-16T06:13:21.715Z",
  "error": null
}
```

#### Available fields

| Group | Fields |
|---|---|
| Job | `jobId`, `title`, `jobUrl`, `applyUrl`, `employmentTypes`, `employmentTypesText`, `easyApply` |
| Company | `companyName`, `companyRating`, `companyWebsiteUrl`, `companyLogoUrl`, nested `company` |
| Location | `locationText`, `streetAddress`, `city`, `state`, `postalCode`, `country`, nested `location` |
| Salary | `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`, `salaryAnnualMin`, `salaryAnnualMax`, `salaryHourlyMin`, `salaryHourlyMax`, `salaryText`, `salarySource`, nested `salary` |
| Details | `descriptionText`, `descriptionHtml`, `responsibilities`, `qualifications`, `skills`, `skillsText`, `benefits`, `educationRequirements`, `experienceRequirements`, `industry` |
| Dates | `datePosted`, `validThrough`, `scrapedAt` |
| Provenance | `searchUrl`, `searchKeyword`, `searchLocation`, `source` |

Fields that are not published or accessible are returned as `null` or an empty array. They are not silently omitted.

### Excel and Google Sheets output

Every successful run creates three spreadsheet-friendly outputs:

1. **Formatted Excel workbook** — open the run's Key-value store and download `GLASSDOOR-JOBS.xlsx`, or use `OUTPUT.spreadsheet.formattedExcelUrl`. The workbook includes:
   - a styled **Jobs** sheet with frozen headers, filters, alternating rows, readable column widths, and number/date formatting;
   - clickable links for the Glassdoor job, application, company website, company logo, and originating search;
   - separate listed, annualized, and hourly salary columns;
   - a **Run Summary** sheet containing the filters and run statistics; and
   - a **Data Notes** sheet explaining missing values, salary normalization, and link behavior.
2. **Native XLSX or CSV export** — use the links in `OUTPUT.spreadsheet.excelDownloadUrl` and `OUTPUT.spreadsheet.csvDownloadUrl` for a lightweight ordered export.
3. **Google Sheets-ready dataset** — select the **Excel & Google Sheets** dataset view, then use Apify's Google Sheets integration to send each result into a spreadsheet. The dedicated view contains only flat columns, so arrays and nested objects do not create malformed cells.

All links are preserved as complete URLs. The text versions of multi-value fields (`employmentTypesText` and `skillsText`) keep one clean value per spreadsheet cell while the original arrays remain available in JSON.

### Pricing

This Actor uses **pay per event** pricing:

- `job-result`: **$0.00499 per successfully saved job** — equivalent to **$4.99 per 1,000 results**.
- Failed requests, filtered-out jobs, duplicates, empty searches, and records written to the diagnostic error dataset do not trigger the `job-result` charge.
- A run stops safely when its Apify charge limit is reached.

Apify platform usage, including residential proxy traffic and compute, is billed separately to the run owner. Start with a small `maxItems` value to confirm the search before scaling up.

### Salary filtering

Salary filters compare overlapping pay ranges after normalization:

- `YEAR`: hourly pay × 2,080; daily pay × 260; weekly pay × 52; monthly pay × 12.
- `HOUR`: annual pay ÷ 2,080.

When Glassdoor does not publish compensation, `includeSalaryUnknown` controls whether that job is retained. Salary values can be employer-provided estimates, Glassdoor estimates, or structured page data; inspect `salarySource` and `salaryText` when source distinctions matter.

### ZIP code and location behavior

Glassdoor commonly maps a ZIP/postal code to its canonical city or locality. The Actor uses that resolved location plus `radiusMiles`. For example, live validation resolved ZIP `10001` to New York, NY and returned jobs from the surrounding search area.

The Actor supports city, state, metro-area, county, country, and remote searches when Glassdoor recognizes the supplied location.

### Reliability and responsible crawling

Glassdoor is a technically difficult target. This Actor uses Playwright, residential proxy support, rotating persistent sessions, retries, conservative concurrency, randomized delays, media blocking, canonical URL deduplication, and transparent block detection.

It also fetches and enforces Glassdoor's current `robots.txt`. It does not call disallowed internal APIs, solve CAPTCHAs, or crawl disallowed paginated search URLs. Consequently, it does not claim to return every job available on Glassdoor. Coverage depends on the public pages Glassdoor exposes at run time.

For best results:

- Keep residential proxy enabled.
- Use concurrency 1–3.
- Search specific professions and locations.
- Start with `includeJobDetails: false`.
- Use canonical `searchUrls` when you already have a working Glassdoor results URL.

### Error handling

Successful jobs are stored in the default dataset. Access blocks, robots exclusions, navigation failures, and parsing errors go to a separate named dataset: `glassdoor-job-errors`.

This separation keeps exported job datasets clean and ensures failed pages are not mistaken for paid results.

### API access

The Actor can be run from Apify Console, the API, JavaScript, Python, CLI, schedules, webhooks, or integrations.

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('kuantum/glassdoor-jobs-scraper').call({
  keywords: ['data analyst'],
  locations: ['Austin, TX'],
  minSalary: 80000,
  salaryPeriod: 'YEAR',
  maxItems: 50
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient('YOUR_APIFY_TOKEN')
run = client.actor('kuantum/glassdoor-jobs-scraper').call(run_input={
    'keywords': ['data analyst'],
    'locations': ['Austin, TX'],
    'maxItems': 50,
})

items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use cases

- Build recruiting and candidate-sourcing market maps.
- Monitor hiring activity by company, profession, or location.
- Compare salary ranges across cities and employers.
- Populate a niche job board or internal opportunity database.
- Track remote-job availability and Easy Apply listings.
- Research regional labor demand and skill requirements.
- Feed job intelligence into dashboards, CRMs, spreadsheets, or data warehouses.

### Legal and ethical use

Only collect and use data you are legally permitted to process. Follow Glassdoor's terms, applicable privacy and employment laws, and reasonable request limits. Do not use the output for unlawful discrimination, spam, harassment, or automated employment decisions about individuals.

Glassdoor is a trademark of its owner. This independent Actor is not affiliated with or endorsed by Glassdoor.

### FAQ

#### Can it search by profession or job title?

Yes. Add one or more professions, titles, or skills to `keywords`.

#### Can it search by company name?

Yes. Use `companyNames` to include matching employers and `excludeCompanies` to remove unwanted employers. If no search keyword is supplied, included company names are also used as search terms.

#### Can it filter job descriptions?

Yes. `descriptionKeywords` matches any requested term in the title or extracted description. Enable `includeJobDetails` when description-body matching is required.

#### Why are some detail fields null?

Search-summary mode is the reliable default. Descriptions and other enrichment fields require direct job-page access, which Glassdoor may block even when the search page is available.

#### Can it scrape every page of results?

No. The Actor intentionally avoids Glassdoor routes disallowed by the current robots policy. It prioritizes compliant, transparent extraction over an unrealistic coverage claim.

#### Does it support CSV and Excel?

Yes. Each run creates a styled `GLASSDOOR-JOBS.xlsx` workbook and direct native XLSX/CSV download links in the run output. The Dataset tab also supports JSON, JSONL, CSV, Excel, XML, and other Apify formats.

#### Can I send the results to Google Sheets?

Yes. Use the **Excel & Google Sheets** dataset view with Apify's Google Sheets integration. It provides ordered, flat columns for job, employer, location, salary, description, provenance, and every available link.

#### Am I charged for failed jobs?

The `job-result` event is triggered only for a successful record written to the default job dataset. Error records are written separately and do not trigger that event. Platform resource usage may still apply.

### Support

If Glassdoor changes its layout or a filter stops behaving as expected, open an issue from the Actor page and include the run ID, input, and a short description. Do not include passwords, API tokens, or private candidate data.

# Actor input Schema

## `keywords` (type: `array`):

One or more searches, such as Software Engineer, Project Manager, or Registered Nurse.

## `locations` (type: `array`):

City, state, metro area, county, or country names. Combined with each keyword.

## `zipCodes` (type: `array`):

ZIP/postal codes to search. Glassdoor resolves each code to its canonical locality, combines it with every keyword, and applies radiusMiles.

## `companyNames` (type: `array`):

Case-insensitive company-name filters applied before a record is saved.

## `excludeCompanies` (type: `array`):

Skip companies whose names contain any of these values.

## `descriptionKeywords` (type: `array`):

Save a job when its title or description contains at least one of these terms.

## `searchUrls` (type: `array`):

Optional canonical Glassdoor job-search URLs. Allowed URLs are combined with generated searches and checked against Glassdoor robots.txt.

## `jobUrls` (type: `array`):

Optional direct /job-listing/ URLs to extract in addition to search results.

## `radiusMiles` (type: `integer`):

Best-effort radius sent to Glassdoor for generated location searches.

## `postedWithinDays` (type: `integer`):

Best-effort Glassdoor search filter. Use 0 for any date.

## `remoteOnly` (type: `boolean`):

Ask Glassdoor for remote jobs and filter out clearly on-site results.

## `easyApplyOnly` (type: `boolean`):

Save only listings marked Easy Apply. This flag is not always available on direct job pages.

## `employmentTypes` (type: `array`):

Optional output filters. A listing can expose more than one employment type.

## `minSalary` (type: `number`):

Minimum lower-bound salary after normalization to the selected salary period.

## `maxSalary` (type: `number`):

Maximum upper-bound salary after normalization to the selected salary period.

## `salaryPeriod` (type: `string`):

Convert reported hourly, monthly, and yearly pay before applying min/max salary filters.

## `includeSalaryUnknown` (type: `boolean`):

When salary filters are set, retain records whose salary is not published.

## `includeJobDetails` (type: `boolean`):

Optional. Attempts to extract descriptions, dates, employment type, address, qualifications, and benefits. Direct detail pages are more frequently blocked; leave disabled for the most reliable title/company/location/salary results.

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

Maximum number of successful job records saved per run.

## `maxConcurrency` (type: `integer`):

Parallel browser pages. Glassdoor is sensitive to high concurrency; 2–4 is recommended.

## `maxRetries` (type: `integer`):

Retries for navigation and temporary access failures.

## `requestDelayMs` (type: `integer`):

Minimum delay before each Glassdoor navigation. Higher values reduce pressure and blocking.

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

Residential proxy is recommended for Glassdoor. Datacenter IPs are cheaper but are frequently blocked.

## Actor input object example

```json
{
  "keywords": [
    "software engineer"
  ],
  "locations": [
    "Los Angeles, CA"
  ],
  "zipCodes": [],
  "companyNames": [],
  "excludeCompanies": [],
  "descriptionKeywords": [],
  "searchUrls": [],
  "jobUrls": [],
  "radiusMiles": 25,
  "postedWithinDays": 7,
  "remoteOnly": false,
  "easyApplyOnly": false,
  "employmentTypes": [],
  "salaryPeriod": "YEAR",
  "includeSalaryUnknown": false,
  "includeJobDetails": false,
  "maxItems": 50,
  "maxConcurrency": 3,
  "maxRetries": 2,
  "requestDelayMs": 2000,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `jobs` (type: `string`):

All successful job records with raw and normalized fields.

## `spreadsheetView` (type: `string`):

Flat, ordered job columns designed for spreadsheets and integrations.

## `formattedExcel` (type: `string`):

Download the styled workbook with Jobs, Run Summary, and Data Notes sheets.

## `csv` (type: `string`):

Download clean job records as CSV.

## `nativeExcel` (type: `string`):

Download the lightweight Apify dataset export as XLSX.

## `runSummary` (type: `string`):

Counters, completion status, and direct spreadsheet download URLs.

# 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 = {
    "keywords": [
        "software engineer"
    ],
    "locations": [
        "Los Angeles, CA"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("kuantum/glassdoor-jobs-scraper").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 = {
    "keywords": ["software engineer"],
    "locations": ["Los Angeles, CA"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("kuantum/glassdoor-jobs-scraper").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 '{
  "keywords": [
    "software engineer"
  ],
  "locations": [
    "Los Angeles, CA"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call kuantum/glassdoor-jobs-scraper --silent --output-dataset

```

## MCP server setup

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

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/MHgrsJAfKpwBA6YAQ/builds/puZnzjyZxOSIpYfcg/openapi.json
