If you're job hunting remotely, or building anything around remote work, salary data is the part you actually want and the part that's hardest to collect. Two job boards publish it in a usable form: Himalayas (salary range, currency, period, and seniority) and Remote OK (salary range in USD, plus tags).
I built two small Apify Actors that turn those listings into clean rows. Here's how to get the salary data into a CSV and do something useful with it.
What each source gives you
Himalayas Remote Jobs Scraper
title, companyName, employmentType, seniority, minSalary, maxSalary, currency, salaryPeriod, isWorldwide, publishedAt, url
Remote OK Jobs Scraper
title, company, location, tags, salaryMinUsd, salaryMaxUsd, publishedAt, url
Himalayas is the better source when seniority matters and when you need to know whether a role is open worldwide (isWorldwide). Remote OK is handy when you want everything already in USD and filterable by tech tags.
Step 1: Run the scrapers
In the browser, open either Actor, click Try for free, fill in the input, and hit Start. Then export the results as CSV.
Or from Python:
pip install apify-client pandas
from apify_client import ApifyClient
import pandas as pd
client = ApifyClient("YOUR_APIFY_TOKEN")
def run(actor_id, run_input):
r = client.actor(actor_id).call(run_input=run_input)
return list(client.dataset(r["defaultDatasetId"]).iterate_items())
himalayas = pd.DataFrame(run("slate_cyclone/himalayas-jobs-scraper",
{"keywords": "python", "salaryRequired": True, "maxJobs": 100}))
remoteok = pd.DataFrame(run("slate_cyclone/remoteok-jobs-scraper",
{"tags": ["python", "react"], "salaryRequired": True, "maxJobs": 100}))
Step 2: Keep only rows with salary data
h = himalayas.dropna(subset=["minSalary", "maxSalary"])
r = remoteok.dropna(subset=["salaryMinUsd", "salaryMaxUsd"])
Step 3: Answer real questions
Median salary range by seniority on Himalayas (yearly, USD only):
yearly_usd = h[(h["currency"] == "USD") & (h["salaryPeriod"].str.lower() == "year")]
print(yearly_usd.groupby("seniority")[["minSalary", "maxSalary"]].median())
Only roles open worldwide:
print(h[h["isWorldwide"] == True][["title", "companyName", "minSalary", "maxSalary", "url"]])
Remote OK salaries for a given tag, for example python:
py = r[r["tags"].apply(lambda t: "python" in [x.lower() for x in (t or [])])]
print(py[["title", "company", "salaryMinUsd", "salaryMaxUsd"]].describe())
Step 4: Save it
h.to_csv("himalayas_salaries.csv", index=False)
r.to_csv("remoteok_salaries.csv", index=False)
Cost
Both Actors are pay-per-result: $0.80 per 1,000 jobs.
Check the actual values in your own export before you rely on a filter. Salary periods and currencies vary by listing, so filter them explicitly, as above, rather than assuming everything is yearly USD.
This post was written with AI assistance.
Top comments (0)