How to scrape Glassdoor job listings and their salary ranges
Last updated
Datapika's job board scraper reads Glassdoor's public search results and returns each listing as a JSON row carrying the pay band Glassdoor attaches to it (low, high, currency, pay period), the posting date, the employer's Glassdoor overview link and the full description. You pick a country code such as usa or uk, add up to 5 search terms and cap results at 100 per term. Glassdoor is fetched through a real browser, so rows land within 1 to 3 minutes. Pricing is $0.005 per delivered job; the actor shows 27,458 runs and a 5.0 rating (August 29, 2026).
What Glassdoor fields does the scraper return?
A Glassdoor row is identified by an id prefixed gd- and a site value of glassdoor, with title, company, location, job_url, date_posted and an is_remote flag. The compensation block is the reason to pick this board: salary_min, salary_max, salary_currency and salary_interval mirror the pay band Glassdoor attaches to the listing header, and salary_source reads direct_data when that band exists. company_url points at the employer's overview page on the Glassdoor country site, company_logo holds the square logo, and listing_type records the sponsorship level, so paid placements can be separated from organic postings. The description is requested for each job and delivered as Markdown by default or HTML on request, and any email addresses found inside it are copied into emails. Fields that Glassdoor's search results do not expose stay null on these rows: company_rating, company_reviews_count, company_num_employees, company_revenue, company_industry, job_type and job_url_direct. If you want a rating next to the pay band, keep Indeed in the same run, because Indeed rows carry company_rating and company_reviews_count.
- Identity: id (gd- prefix), site, title, company, location, job_url, date_posted, is_remote
- Pay: salary_min, salary_max, salary_currency, salary_interval, salary_source
- Employer: company_url (Glassdoor overview page), company_logo, listing_type
- Content: description in Markdown or HTML, emails parsed from the text
- Null on Glassdoor rows: company_rating, company_reviews_count, company size and revenue, job_type, job_url_direct
- Every row also carries search_term, matched_search_term and a scraped_at UTC timestamp
How do Glassdoor salary bands work in the output?
Glassdoor attaches a pay band to most listings, whether the employer supplied it or Glassdoor estimated it, and the scraper records the low and high points of that band as salary_min and salary_max. salary_interval tells you whether the figures are yearly, monthly or hourly, which matters for retail and healthcare roles that Glassdoor quotes per hour. Turn on enforceAnnualSalary and hourly bands are multiplied by 2080 and monthly bands by 12 before they reach the dataset, so a $28 to $35 hourly nursing job and a $95,000 to $120,000 salaried one sort on one axis. salary_currency is the currency code Glassdoor reports for the band, so uk and germany runs return GBP and EUR figures rather than converted dollars. When a listing carries no band and countryIndeed is usa, the scraper scans the description for dollar amounts and sets salary_source to description; outside the US that fallback is not attempted, so a missing salary_min on a uk run means Glassdoor showed no pay for that listing.
- salary_min and salary_max are the low and high points of the band Glassdoor attaches to the listing
- salary_interval is yearly, monthly or hourly; enforceAnnualSalary converts hourly (x 2080) and monthly (x 12) to yearly
- salary_currency is the code Glassdoor reports for the band, so a uk run returns GBP figures
- salary_source is direct_data for Glassdoor bands, description for the US text fallback, null when there is no pay
- Missing pay on a non-US row means Glassdoor displayed no band for that listing
- README example: searchTerm machine learning engineer, location London, countryIndeed uk, enforceAnnualSalary true
Which country, location and filter settings does Glassdoor accept?
Glassdoor runs one site per country, so the countryIndeed input decides which one is queried: usa is the default, and uk, canada, australia, germany, france, india, singapore and uae are among the accepted codes, along with most common country names and 2-letter ISO codes. The location string is resolved against Glassdoor's own place index, which returns a city, state or country entity, so write it the way Glassdoor does, for example Nashville, TN or London. The distance input is not applied to this board because Glassdoor searches by place entity rather than radius. Set isRemote true and the scraper skips the place lookup and queries Glassdoor's remote location entity directly. hoursOld is honored, but Glassdoor filters by whole days, so 24 becomes 1 day and 168 becomes 7 days; values under 24 still count as 1 day. jobType maps to Glassdoor's employment type filter and easyApply restricts results to postings that accept applications on Glassdoor. Results arrive newest first, 30 per page, up to the maxResults cap of 100 per search term, and offset skips whole pages of 30.
- countryIndeed picks the Glassdoor country site; examples: usa, uk, canada, australia, germany, france, india, singapore, uae
- location resolves to a Glassdoor city, state or country entity; distance is not applied
- isRemote true searches Glassdoor's remote location entity without a place lookup
- hoursOld rounds down to whole days with a 1-day minimum (24 = 1 day, 168 = 7 days)
- jobType (fulltime, parttime, contract, internship, temporary) and easyApply both work on Glassdoor
- Newest first, 30 per page, maxResults up to 100 per term, offset skips whole pages
What Glassdoor quirks should you plan for?
Glassdoor's anti-bot wall rejects plain HTTP clients, so every request for this board is issued from a real browser session. That is why Indeed and LinkedIn rows appear 5 to 20 seconds after start while Glassdoor rows take 1 to 3 minutes, and why runs default to 4 GB of memory. Each description is a separate lookup; when a search term's time budget is nearly spent the scraper skips the remaining description fetches so rows still land with their pay bands intact. Cross-board deduplication keeps the first row to arrive per title and company, and since Indeed usually finishes first, a job on both boards is delivered as the Indeed row. Run Glassdoor alone when you need its pay band on every listing, or with Indeed when you want ratings. date_posted is a calendar date derived from Glassdoor's days-old counter, with no time of day. Glassdoor's site migration in April 2026 briefly made every search return zero rows; v1.0.17 on 2026-04-20 restored results, with a Nashville, TN software engineer search returning 10 jobs from Deloitte, KPMG, PwC and Amazon.
- Browser-based fetch: Glassdoor rows land 1 to 3 minutes after start, Indeed and LinkedIn in 5 to 20 seconds
- Descriptions are fetched per job and skipped near the time budget, keeping salary data
- Dedup keeps the first arrival per title and company, so Indeed rows usually win over Glassdoor duplicates
- Run sites: ["glassdoor"] alone to get a Glassdoor pay band on every row that has one
- date_posted has day precision only
- The April 2026 Glassdoor site migration was handled in v1.0.17; results resumed on 2026-04-20
How do you run the Glassdoor scraper from the console, the API or an AI agent?
No Glassdoor account, partner agreement or browser extension is involved. In the Apify Console you enter a search term, set sites to glassdoor, choose the country, and read the dataset in the browser or download it as JSON, CSV, Excel, XML or RSS. From code, POST the same input to https://api.apify.com/v2/acts/openclawai~job-board-scraper/runs with your Apify token, or use run-sync-get-dataset-items for one blocking call that returns the rows; the Python and Node clients wrap both. Agents get the scraper as a tool through the Apify MCP server at https://mcp.apify.com/?tools=fetch-actor-details,openclawai/job-board-scraper, so a Claude or Cursor session can ask for Glassdoor pay bands for a title in a city and reason over the rows. Billing is $0.005 per job delivered: a 20-row test costs $0.10 and 1,000 rows cost $5.00, and an empty result carries no per-job charge. Apify's free plan includes $5 of monthly credit, roughly 1,000 Glassdoor jobs. Zapier, Make and n8n can schedule the run and push new rows to Sheets, Slack or a CRM. The same input can sweep the 7 other boards alongside Glassdoor.
- Console: searchTerm, sites ["glassdoor"], countryIndeed, then export JSON, CSV, Excel, XML or RSS
- REST: POST to /v2/acts/openclawai~job-board-scraper/runs, or run-sync-get-dataset-items for one call
- Python: pip install apify-client, then client.actor("openclawai/job-board-scraper").call(run_input=...)
- MCP: https://mcp.apify.com/?tools=fetch-actor-details,openclawai/job-board-scraper
- Billing only for delivered rows; an empty result carries no per-job charge
- Zapier, Make and n8n schedules push fresh Glassdoor rows into Sheets, Slack or HubSpot
| Field | Populated on Glassdoor? | Notes |
|---|---|---|
| id, site | Yes | Listing id with a gd- prefix; site is glassdoor |
| title, company, location | Yes | location is null and is_remote is true for remote listings |
| job_url, job_url_direct | job_url only | Glassdoor listing page; the employer's apply URL is not exposed |
| date_posted | Yes | Calendar date derived from Glassdoor's days-old counter; no time of day |
| is_remote, job_type | is_remote only | jobType filters the search but is not written to the row |
| listing_type | Yes | Glassdoor sponsorship level, lowercased; separates paid from organic placements |
| company_url, company_logo | Yes | Employer overview page on the Glassdoor country site plus the square logo URL |
| company_rating, company_reviews_count, company_num_employees, company_revenue, company_industry | No | Indeed rows carry these; Naukri rows carry company_rating |
| salary_min, salary_max | Yes | Low and high points of the pay band on the listing; null when Glassdoor shows none |
| salary_currency, salary_interval | Yes | Currency code Glassdoor reports; yearly, monthly or hourly, converted by enforceAnnualSalary |
| salary_source | Yes | direct_data for Glassdoor bands; description only for the US text fallback; null with no pay |
| description, emails | Yes | Markdown or HTML per job; skipped when the time budget is nearly spent |
How to do it
- 1.Open https://apify.com/openclawai/job-board-scraper, type a search term such as data analyst, set sites to glassdoor, and set countryIndeed to the Glassdoor country you want (usa, uk, canada, germany and others).
- 2.Add a location written the way Glassdoor shows it (London or Nashville, TN), or set isRemote true, then pick maxResults up to 100, an optional hoursOld window in whole days, jobType or easyApply, and enable enforceAnnualSalary if you want hourly bands converted to yearly.
- 3.Start the run and wait 1 to 3 minutes for the browser-based fetch; rows stream into the dataset with salary_min, salary_max, salary_currency, salary_interval and the description once the board finishes.
- 4.Export JSON, CSV or Excel from the dataset, call the same input through the Apify API or Python client for a pipeline, or add the MCP URL so an agent can query Glassdoor pay bands on demand.
Questions, answered
Does Glassdoor have an official API?
Not one you can sign up for. Glassdoor retired its public developer API and issues no new developer keys in 2026; the remaining API page on help.glassdoor.com describes Customer Insights, a B2B subscription product for HR teams, not a job-data feed (DEV Community, April 29, 2026; JobsPipe, updated August 29, 2026). Datapika reads the public search pages instead, so there is no key, waitlist or partner contract to obtain.
Do Glassdoor rows include the company rating and review count?
No. company_rating and company_reviews_count are null on rows where site is glassdoor, because the search results the scraper reads do not carry them. You do get company_url, which links to the employer's Glassdoor overview page, and company_logo. Ratings are populated on Indeed and Naukri rows, so a combined Glassdoor plus Indeed run gives you pay bands from one board and ratings from the other.
Why does a Glassdoor run return fewer jobs than maxResults, or none at all?
Usual causes are a location string Glassdoor cannot resolve, a country code that does not match the location, or a narrow hoursOld window; remember hoursOld works in whole days on this board. Duplicates found on faster boards are also removed before Glassdoor's rows arrive. Run Glassdoor alone, loosen the filters, and check that countryIndeed matches the city you typed. An empty result carries no per-job charge.
Which countries can I scrape Glassdoor jobs from?
Any country with its own Glassdoor site. The countryIndeed input accepts codes such as usa, uk, canada, australia, germany, france, india, singapore and uae, plus most common country names and 2-letter ISO codes. The salary_currency on each row is the code Glassdoor reports for that listing, so bands are not converted to dollars. One run queries one country; schedule separate runs per market if you need several.
Can an AI agent or a scheduled pipeline pull Glassdoor salary data?
Yes. Add https://mcp.apify.com/?tools=fetch-actor-details,openclawai/job-board-scraper to Claude Desktop, Cursor or any MCP client and the agent can run a Glassdoor search and read the salary_min, salary_max and salary_interval fields directly. For pipelines, schedule the actor in Apify Console with hoursOld set to 24 or 168, attach a webhook, and push new rows to Sheets, Airtable or a CRM through Zapier, Make or n8n.
Is scraping Glassdoor job listings allowed?
The scraper only reads job postings that Glassdoor shows to any anonymous visitor. It does not log in, does not touch reviews, salaries submitted by employees, or any private profile data, and does not bypass authentication. You remain responsible for using the rows in line with Glassdoor's terms and with laws that apply to you, including GDPR when a description contains a recruiter's email address.