Upwork Freelancer Scraper — Rates, Earnings, JSS, Work History
Pricing
from $2.00 / 1,000 stored profile rows
Upwork Freelancer Scraper — Rates, Earnings, JSS, Work History
Search Upwork freelancers by keyword, skills, rate, JSS, badge, country, hours and tenure. Per profile: exact earnings, every contract with feedback both ways, education, employment, languages, certificates. Seconds from a maintained census; live search on request. Pay per row, no start fee.
Pricing
from $2.00 / 1,000 stored profile rows
Rating
0.0
(0)
Developer
Moxlade
Maintained by CommunityActor stats
0
Bookmarked
43
Total users
32
Monthly active users
8 hours ago
Last modified
Categories
Share
Search Upwork freelancers the way a client would — by rate, Job Success Score, badge, country, hours billed, tenure, hire-again rate and skills — and get what a profile page hides: exact lifetime earnings, hours, every contract with the feedback in both directions, education, employment history, languages, certificates. Answered in seconds from a maintained census of 28,000+ full profiles (69,000+ indexed, refreshed daily), with a live search on request. One event per delivered row, no start fee, a zero-row run costs nothing.
Why this one
| Live | liveSearch returns Upwork's current result in its own order. fullProfiles reads a profile and its entire contract history on the spot. |
| Stored | A maintained census answers in seconds. $4 per 1,000 rows, no start fee, zero-row runs free. |
| Filter inputs | JSS, hours billed, lifetime earnings, hire-again rate, tenure, badge, country, region, skills — inputs, not just output columns. Hourly rate is numeric (rateMin/rateMax), not a preset bracket. |
| Verified | 25 of 25 rows inside the requested band, re-checked on every release run. |
| The lane, 2026-09-11 | All 11 Upwork freelancer scrapers, same query: 4 returned any rows, 0 could filter by a numeric rate. Comparison and harness published — run it with your own token. |
Top Rated Python developers in the US, $50–100/h
Give it this:
{"query": "python developer","topRated": true,"countries": ["United States"],"rateMin": 50,"rateMax": 100,"maxItems": 25}
Back comes one record per freelancer — the fields below are the ones this real row carried; every row has the same 65, and a field the source did not show arrives as null, not as a zero:
{"ciphertext": "~0165a1005d516f24fc","url": "https://www.upwork.com/freelancers/~0165a1005d516f24fc","person_id": "424140398147256320","name": "Denis G.","title": "AI Developer | AI Voice Agent | AI Automation | AI Agent","overview": "I was building software before 🤖 ChatGPT made “AI expert” everyone’s favorite job title.\n\nHello, I’m an AI Developer & A …","country": "United States","country_code": "US","region": "Americas","city": "West Palm Beach","state": "FL","timezone": "UTC-04:00 Eastern Time (US & Canada)","rate": 90,"jss": 100,"jss_hidden": false,"total_earnings": 33532.24,"earnings_precision": "exact","earnings_hidden": false,"badge": "top_rated_plus","top_rated": true,"top_rated_plus": true,"hours": 1,"jobs_total": 10,"jobs_hourly": 1,"jobs_fixed": 11,"contracts_total": 9,"member_since": "2009-09-14","last_worked_on": "2026-06-12","hire_again_pct": 100,"rating": 5,"feedback_count": 8,"recent_hours": 0,"recent_jobs": 2,"availability": "fullTime","contract_to_hire": true,"id_verified": false,"phone_verified": true,"skills": ["TensorFlow", "Python", "JavaScript", "Artificial Intelligence", "Machine Learning", "Deep Learning", "Data Science", "Neural Network", "Artificial Neural Network", "… 11 more"],"portfolio_count": 13,"agency_name": "AI Visionary Labs","agency_ciphertext": "~01eadb1277dc0075d8","status": "public","source": "stored","completeness": "profile","fetched_at": "2026-09-09T11:30:42.836752Z","age_days": 7,"first_seen_at": "2026-09-09T06:34:37.686125Z","last_seen_at": "2026-09-17T07:03:11.075062Z","card_seen_at": "2026-09-17T07:03:11.075062Z","versions": 2,"contracts_complete": false,"sections_fetched_at": "2026-09-12T20:26:35.309224Z","rank": 5}
The same actor, asked differently:
- Active, proven: JSS 95+, 1,000+ hours, worked in the last 60 days —
{"jssMin": 95, "hoursMin": 1000, "lastWorkedWithinDays": 60, "sort": "jss", "maxItems": 50} - Look up profiles by URL —
{"profileUrls": ["https://www.upwork.com/freelancers/~01d699cdd471617458"]} - Profiles with their contract history —
{"query": "django", "topRated": true, "include": ["contracts", "languages", "education"], "maxItems": 25} - Fresh full profiles, every contract —
{"profileUrls": ["~01d699cdd471617458", "~01b237e28ffe15f101"], "fullProfiles": true} - What changed since a date —
{"query": "python", "changedSince": "7d", "includeStale": true, "maxItems": 100}
What the record holds that a profile page does not
Filters a page scrape cannot do. Job Success Score, hours billed, jobs worked, lifetime earnings, member-since, last-worked-within-N-days, hire-again rate, availability, identity verification and skills are filter inputs here, not just output columns. A numeric rate band (rateMin / rateMax) works as stated — every acceptance run checks 25 of 25 rows.
The stats a profile page hides. Exact lifetime earnings where Upwork exposes the figure (with earnings_precision saying exact or band), total hours, hourly vs fixed jobs, completed contracts, hire-again percentage, average rating, member-since and last-worked dates, availability, contract-to-hire and verification flags — 53 typed fields per row.
History, not a snapshot. Every row carries fetched_at, age_days, first_seen_at, last_seen_at and a versions count. changedSince returns only freelancers whose rate, title, JSS, badge, hours, jobs, skills, availability or hire-again rate moved since a date — with the changes as {field, from, to, at}.
Contract history with feedback in both directions. include: ["contracts"] adds each freelancer's completed contracts — title, type, dates, hours, charges, client name, the client's feedback with its six detail scores, and what the freelancer wrote about the client. fullProfiles: true re-reads a profile now and stores every contract it has, charges included on private ones.
The sections a profile page does not show a visitor. Education, employment history, languages with proficiency, certificates and other experiences — on every full profile read, and on stored rows as they are refreshed (sections_fetched_at says when). include adds them to any row.
Private profiles are an answer. Look up a list of ids and the ones that went private come back as status: private with private_since and their last public state (5,000 such profiles tracked, re-checked weekly), instead of silently missing.
Seconds, not minutes. A stored search answers 25 rows in well under 5 s and 500 rows in one call; it cannot be blocked or rate-limited because it reads a maintained table. liveSearch: true asks Upwork for the current result in its own order when you need that.
All 65 fields of a row
Every row carries all of them. A field the source did not show arrives as null, never as a zero or an empty string, and the note says when that happens.
Who they are
| field | type | what it holds |
|---|---|---|
ciphertext | string | Upwork's stable profile id (~01…). Deduplicate and join on this. Filled on every row. |
url | string | The public profile URL. Filled on every row. |
person_id | string | Upwork's numeric person id. Filled on every row. |
name | string | Display name as Upwork shows it (first name + initial). Filled on every row. |
title | string | The profile headline. Filled on every row. |
overview | string | The profile overview, full text. Filled on every row. |
country | string | Country as shown on the profile. Filled on every row. |
country_code | string | ISO 3166-1 alpha-2. Filled on every row. |
region | string | Upwork's region: Americas, Asia, Europe, Africa, Oceania. Filled on 9% of rows. |
city | string | City. Filled on every row. |
state | string | State or province, where Upwork shows one. Filled on 99% of rows. |
timezone | string | Timezone as Upwork labels it (e.g. UTC+08:00 …). Filled on 9% of rows. |
agency_name | string | Agency the freelancer belongs to, when shown on the card. Filled on 3% of rows. |
agency_ciphertext | string | That agency's Upwork id. Filled on 3% of rows. |
Rate, earnings and score
The numbers a client shortlists on — and the flags that say when Upwork itself is hiding one.
| field | type | what it holds |
|---|---|---|
rate | number | Listed hourly rate, USD. Filled on every row. |
jss | integer | Job Success Score, 0–100. Null when Upwork shows none (new, or hidden). Filled on 90% of rows. |
jss_hidden | boolean | The freelancer hides their JSS. Filled on 9% of rows. |
total_earnings | number | Lifetime earnings, USD. Exact when earnings_precision is exact; a lower bound ($10K+ → 10000) when band. Filled on 48% of rows. |
earnings_precision | string | exact (read from Upwork's search payload), band (the card's rounded figure), or null. Filled on 48% of rows. |
earnings_hidden | boolean | The freelancer hides their earnings. Filled on every row. |
badge | string | top_rated_plus, top_rated, rising_talent, or null. Filled on 74% of rows. |
top_rated | boolean | Top Rated (includes Top Rated Plus). Filled on every row. |
top_rated_plus | boolean | Top Rated Plus. Filled on every row. |
hire_again_pct | number | Share of clients who would hire again, 0–100. Null when Upwork does not show the stat (it needs enough client feedback first). Filled on 74% of rows. |
rating | number | Average client rating, 0–5. Filled on every row. |
feedback_count | integer | Contracts with client feedback. Filled on every row. |
Volume and tenure
| field | type | what it holds |
|---|---|---|
hours | number | Total hours billed on Upwork. Filled on every row. |
jobs_total | integer | Jobs worked, as the profile reports it. Filled on every row. |
jobs_hourly | integer | Hourly contracts. Filled on every row. |
jobs_fixed | integer | Fixed-price contracts. Filled on every row. |
contracts_total | integer | Completed contracts in the work history. Filled on every row. |
member_since | string | Account creation date. Filled on every row. |
last_worked_on | string | Date of the most recent work on Upwork. Filled on every row. |
recent_hours | number | Hours billed in the recent window Upwork reports. Filled on every row. |
recent_jobs | integer | Jobs in the recent window Upwork reports. Filled on every row. |
Availability, verification, skills
| field | type | what it holds |
|---|---|---|
availability | string | fullTime, partTime, notSure (as needed). Filled on every row. |
contract_to_hire | boolean | Open to contract-to-hire. Filled on every row. |
id_verified | boolean | Identity verified by Upwork. Filled on every row. |
phone_verified | boolean | Phone verified by Upwork. Filled on every row. |
skills | array | Skills in the profile's own order. Filled on every row. |
portfolio_count | integer | Portfolio items. Filled on every row. |
Contracts
With include: ["contracts"] or a full profile read: each contract with its feedback in both directions.
| field | type | what it holds |
|---|---|---|
contracts | array | With include=contracts: completed contracts, newest first — title, type, dates, hours, rate, charges, client name, the client's feedback (score, comment, six detail scores) and the freelancer's feedback about the client. A full profile fetch stores every contract; a stored row carries the page the profile showed (contracts_total says how many exist). Filled on 0% of rows. |
contracts_in_progress | array | With include=contracts: contracts open at the last read. Filled on 0% of rows. |
contracts_complete | boolean | True when every contract is stored (a full profile fetch happened); false when only the profile page's newest ones are. Filled on every row. |
The sections a visitor does not see
Attached by include, and on every full profile read. sections_fetched_at says when they were last read.
| field | type | what it holds |
|---|---|---|
portfolios | array | With include=portfolios: portfolio items — title, role, description, URL, skills. Filled on 0% of rows. |
testimonials | array | With include=testimonials: client testimonials on the profile. Filled on 0% of rows. |
specialized_profiles | array | With include=specialized_profiles: the freelancer's specialized profiles and their occupations. Filled on 0% of rows. |
education | array | With include=education: schools — institution, degree, area of study, from/to. Filled on 0% of rows. |
employment_history | array | With include=employment_history: employment outside Upwork — company, title, city, country, from/to, current, description. Filled on 0% of rows. |
languages | array | With include=languages: languages with proficiency (basic, conversational, fluent, native or bilingual) and whether Upwork verified it. Filled on 0% of rows. |
certificates | array | With include=certificates: certificates — name, provider, earned on, expires on, verified. Filled on 0% of rows. |
other_experiences | array | With include=other_experiences: the profile's other experience entries — subject and description. Filled on 0% of rows. |
sections_fetched_at | string | When education, employment, languages, certificates and other experiences were last read; null when never (they are read on every profile fetch since 2026-09-12). Filled on 99% of rows. |
What the census remembers
The half a live scrape cannot have: when the profile was first and last seen, what has changed since, and whether it is still public.
| field | type | what it holds |
|---|---|---|
versions | integer | How many distinct states of this profile the census has recorded. Filled on every row. |
changes | array | With changed_since: the fields that moved in the window, as {field, from, to, at}. |
first_seen_at | string | When the census first saw this person. Filled on every row. |
last_seen_at | string | When the census last saw this person (search or profile). Filled on every row. |
card_seen_at | string | When this person last appeared in a search result we read. Filled on 9% of rows. |
fetched_at | string | When this row's data was read from Upwork. Filled on every row. |
age_days | integer | Days since fetched_at. Filled on every row. |
completeness | string | profile (full profile read) or card (search card only — the stats fields are null). Filled on every row. |
source | string | stored (answered from the census) or live (fetched for this run). Filled on every row. |
status | string | public, or private when the profile is no longer public — then private_since says since when and the other fields are the last public state. Filled on every row. |
private_since | string | When we first saw the profile private. Filled on 0% of rows. |
How the row was reached
| field | type | what it holds |
|---|---|---|
rank | integer | Position in the result set (1-based). |
Ways to run it
Stored search with filters. Set query and any filters; rows come from the census in seconds, sorted by relevance, rate, hours, JSS, earnings or recency. Use maxItems to cap rows and spend. Ready-made: Top Rated US Python developers at $50–100/h and Active and proven: JSS 95+, 1,000+ hours, worked recently.
Look up specific profiles. Pass profileUrls (URLs, ~01… ids, or custom URLs like upwork.com/freelancers/<username>). Private profiles answer as status: private; ids the census has not seen yet are listed in the run's status message. A custom URL the census has never followed is resolved on its first run with fullProfiles: true and answered from the census after that.
What changed since last week. Set changedSince to a date or a window (7d, 2w, 1m): only profiles that moved come back, each with a changes list. Pair it with includeStale: true to cover the whole census. Ready-made, schedule it weekly: What changed this week.
Full profiles with every contract. Pass profileUrls with fullProfiles: true: each profile is read from Upwork now, its complete contract history fetched and stored, and the row comes back source: live with contracts, education, employment_history, languages, certificates, other_experiences, portfolios, testimonials and specialized_profiles. Billed as profile_live per profile. Ready-made: Full profiles: every contract, feedback both ways, education.
Upwork's own order, right now. Set liveSearch: true with a query (and any of the badge, country, region, rate, JSS or earnings filters): the run fetches the current Upwork result for that query, returns it in Upwork's order as source: live, and those rows join the census. Ready-made: Live search in Upwork's own order.
Everything you can ask for
Who to look for
The words and the places. Leave them all empty and the census answers by relevance over everyone it holds.
| input | accepts | default | what it changes |
|---|---|---|---|
query | string | — | Matched against the profile title, overview and skills, in any word form (developer also finds developers). All words must match. Write alternatives with OR (media buyer OR creative strategist), a phrase in quotes, -word to exclude. Leave empty to filter the whole census by the fields below. When the census holds fewer matching profiles than maxItems, the rest come from Upwork's live search, kept to the same every-word match and billed as card_live (not when a filter the live search cannot apply is set). |
skills | array | — | Skill names as Upwork lists them, e.g. Python, Django, Web Scraping. A profile matches if it lists any of them. |
countries | array | — | Country names as Upwork shows them, e.g. United States, United Kingdom, Germany. Any of these. |
regions | array | — | Upwork's regions. Any of these. |
availability | array | — | As stated on the profile: more than 30 hrs/week (fullTime), less than 30 (partTime), as needed (notSure). |
excludeAgencies | boolean | — | Drop freelancers listed under an agency. |
The numbers they must hit
Filter inputs, not just output columns: a freelancer is only returned when every one of these is satisfied.
| input | accepts | default | what it changes |
|---|---|---|---|
rateMin | integer | — | Listed hourly rate at least this. |
rateMax | integer | — | Listed hourly rate at most this. |
jssMin | integer | — | 0–100. Profiles without a shown JSS are excluded when this is set. |
hoursMin | integer | — | Total hours billed on Upwork. |
jobsMin | integer | — | Jobs worked, as the profile reports it. |
earnedMin | integer | — | Uses the exact figure where known, the card's lower bound otherwise. |
hireAgainMin | integer | — | Share of clients who would hire again. |
topRated | boolean | — | Only Top Rated freelancers (includes Top Rated Plus). |
topRatedPlus | boolean | — | Only Top Rated Plus. |
risingTalent | boolean | — | Only freelancers with the Rising Talent badge. |
idVerified | boolean | — | Only freelancers whose identity Upwork has verified. |
hasContracts | boolean | — | Only freelancers with at least one completed contract. |
memberSinceAfter | string | — | Joined Upwork on or after this date (YYYY-MM-DD). |
memberSinceBefore | string | — | Joined Upwork on or before this date (YYYY-MM-DD). |
lastWorkedWithinDays | integer | — | Last work on Upwork within this many days — active freelancers only. |
Look up people you already have
Profile URLs, ~01… ids or custom URLs. Ids the census has not seen are named in the run's status message instead of silently missing.
| input | accepts | default | what it changes |
|---|---|---|---|
profileUrls | array | — | Look up specific freelancers instead of searching: profile URLs (https://www.upwork.com/freelancers/~01…), bare ids (~01…), or custom profile URLs (https://www.upwork.com/freelancers/ |
includePrivate | boolean | false | Search results also return profiles that are no longer public (status: private, with private_since and the last public state). Lookups by id always answer them. |
What to attach to each row
Contracts, portfolios and the profile sections a visitor does not see. Attached blocks are not charged separately.
| input | accepts | default | what it changes |
|---|---|---|---|
include | array | — | Sections to add to every row from the stored profile at no extra charge: contracts (completed contracts with feedback both ways; the full list after a fullProfiles read), portfolios, testimonials, specialized_profiles, education, employment_history, languages, certificates, other_experiences. |
fullProfiles | boolean | false | With profileUrls: re-read each profile from Upwork now and fetch everything it has — the complete contract history (hours, charges also on private contracts, the client's feedback and the freelancer's feedback about the client), education, employment history, languages, certificates, other experiences, portfolios, testimonials and specialized profiles. Billed as profile_live per profile; about 10 s per profile. Without it, the stored profile is returned (profile_stored). |
Stored or live, and how fresh
The census answers in seconds; a live read asks Upwork during your run. Every row says when it was read (fetched_at, age_days).
| input | accepts | default | what it changes |
|---|---|---|---|
liveSearch | boolean | false | Ask Upwork for the current result for the query instead of the stored census: Upwork's own relevance order, and freelancers the census has not seen yet. Slower (under a minute for 25 rows), billed as card_live per row. Needs a query. |
maxPages | integer | 10 | With liveSearch, how many result pages to walk at most (10 rows per page) before returning what passed the filters. |
maxAgeDays | integer | 30 | Stored rows read from Upwork longer ago than this are left out of a search. Every row carries fetched_at and age_days regardless. |
includeStale | boolean | false | Ignore maxAgeDays and return every matching stored profile. |
changedSince | string | — | ISO date or timestamp, or a window like 7d, 2w, 1m or 7 days (so a scheduled task never needs editing). Only profiles whose rate, title, JSS, badge, hours, jobs, skills, availability or hire-again rate moved since then; each row carries the changes as {field, from, to, at}. |
Order and run size
The spending cap: nothing is charged for a row that is not in your dataset.
| input | accepts | default | what it changes |
|---|---|---|---|
sort | relevance / rate / rate_asc / hours / jss / earnings / last_worked_on / first_seen / fetched | "relevance" | Order of the stored results. Upwork's own relevance order comes only with liveSearch. |
maxItems | integer | 50 | Upper bound on rows returned — and on what the run can cost. |
If an input can't be used
The run still ends Succeeded and charges nothing. Its status message begins INPUT REJECTED and says what to change. The dataset holds a single row, {"error": true, "code": …, "message": …}, with no results, and the key-value record ERROR repeats it, so an agent should check error on the first row. A search that finds nothing is not an error, only an empty dataset. A run marked Failed is a fault on our side, not your input; it costs nothing and reaches us.
Before you run it
What sets this apart from other Upwork freelancer scrapers? Measured, not asserted. On 2026-09-11 we ran one query against all 11 Upwork freelancer scrapers then on the store: 4 returned any rows at all, and 0 could filter by a numeric hourly rate — the harness is published, run it with your own token (comparison, code). The structural difference is that this one reads a maintained census instead of opening a search during your run, so it answers in seconds, it keeps the profile's earlier versions (changedSince returns only the freelancers who moved, with the changes), and a profile that went private still answers — as status: private with the date. Price is the other one: $4.00 per 1,000 stored profiles, where the other profile scrapers on the store charge between $0.005 and $0.023 per profile (our own store census, read 2026-09-23). When you need Upwork's live result in its own order, liveSearch does that.
Where does the data come from, and how fresh is it? From a census of public Upwork freelancer profiles that is refreshed every day and re-reads the oldest profiles on a rolling basis. Every row says when it was read (fetched_at, age_days); a stored search leaves out rows older than maxAgeDays (default 30) unless you set includeStale. liveSearch reads Upwork at run time.
Are the earnings exact? Where Upwork exposes the figure, yes — earnings_precision: exact. Where only a rounded band is shown, total_earnings is that band's lower bound and earnings_precision is band. When the freelancer hides earnings, earnings_hidden is true and the figure is null. The share of rows with an exact figure grows as the census re-reads profiles; it is stated on the Output tab from the latest acceptance run.
Why is a profile missing? A stored search only returns profiles the census holds. If you need someone the census has not reached, liveSearch finds them for a keyword, and a lookup by id reports the missing ids in the status message so you can see exactly what was not found.
Is this legal, and what about personal data? Profiles are read from the pages Upwork serves the open web — what a client sees and a search engine indexes — with no login and nothing behind a paywall. The record keeps what a professional profile publishes: title, overview, rates, earnings, hours, ratings, skills, work history, and the country and city the freelancer put on it. No contact details are stored: no e-mail, no phone number, no street address; id_verified and phone_verified are Upwork's own flags, never the values behind them. A profile that goes private is served as status: private with private_since and its last public state, not as fresh data. A freelancer who writes to the support address is removed from every answer this Actor gives and their stored record is dropped. Whether your use is lawful — and, in the EU or the UK, what basis you have for it — depends on what you do with it, and that part is yours, not ours.
How do I get the rows out? They land in the run's dataset: download them as JSON, CSV, Excel or XML from the run page, or read the same rows over the Apify API (the API tab has the call for this Actor). Save a run as a task, schedule it, and point the store's integrations at it — webhooks, Zapier, Make, Slack, Google Drive — or let an agent call the Actor over MCP. Every row carries a stable ciphertext id, so repeated runs deduplicate against your own table, and changedSince keeps the pull incremental.
Where is this documented in more depth? On moxlade.com: what the actor returns, field by field, how to export freelancers to CSV or JSON, how to filter by rate, Job Success Score and country, the official Upwork API against this census, and every Upwork freelancer scraper on Apify measured on one day. The MCP corpus behind the buyer side of Upwork is at buyer.moxlade.com.
Who makes this, and what else is there? Moxlade — corpora your agent can ask. Its other actors are the Vinted seller census (who carries a brand, how far under the market they price, what each closet holds) and the Reddit scraper (subreddit listings, search and full comment trees); its MCP endpoint for Upwork buyer intelligence is buyer.moxlade.com.
Is there example code? Yes — ready-to-run scripts for every job on this page (a filtered shortlist to CSV, a one-call export, enriching a list of profile URLs, stored versus live, full profiles, weekly changes) in Python, JavaScript and curl: github.com/getmoxlade/upwork-freelancers-examples. The comparison with the other Upwork scrapers on the store is reproducible from github.com/getmoxlade/upwork-scraper-comparison.
What it costs
Charged per row, and only once the row is in your dataset, so maxItems is also your spending cap. No start fee, no minimum charge, and an empty run is free: on the release runs the charged event count equalled the row count on every run, and the zero-row run charged $0.00. Speed on the same runs: 25 stored rows in 0.4–1.9 s of run time; 25 live rows in Upwork's order in under 30 s including the search.
| event | what one event is | per 1,000 |
|---|---|---|
profile_stored | One freelancer row answered from the census (search or lookup). Charged only after the row is in your dataset. | $4.00 |
card_live | One row of a live Upwork search: liveSearch: true, or the rows that complete a stored search short of maxItems. | $5.00 |
profile_live | One freshly read full profile by id. | $20.00 |
Who asks this
Recruiters and talent teams — shortlist by the numbers a client cares about — JSS, hours, hire-again rate, rate band, country, recent activity — and export 500 profiles in one run.
Agencies and freelancers benchmarking — see what people with your skills and badge actually charge and earn, by country and tenure, from real listed rates and exact earnings.
Market and labor researchers — a census with time on it: member-since cohorts, rate and badge changes over time, who went private — questions a live scrape cannot answer.
Product and lead-gen builders — one API-shaped dataset with a stable id (ciphertext) to join on, typed fields, and changedSince for incremental pulls.
Questions
Every figure on this page was measured on our own runs or read from our own tables, on the date given next to it.