moxlade/guides/upwork freelancer scraper
Upwork freelancer scraper: search talent by rate, JSS, badge and country — with exact earnings and every contract
Ours. This page sells the Moxlade Upwork freelancer scraper on Apify. It answers a search from a census of Upwork profiles we keep and refresh every day, so a query with filters comes back in seconds, and it reads a profile live when you ask for the whole record. Every number below is from our own table or our own runs, dated.
published 2026-09-13 · updated 2026-09-13- what it is
- an Apify actor: 65 typed fields per freelancer
- where rows come from
- a census of 30,042 full profiles, 71,351 indexed, 153 countries — refreshed daily (read 2026-09-13)
- a stored search
- 25 rows in 0.4–1.9 s of run time; 500 rows in one call
- a live search
- Upwork's current result, its order, 25 rows in under 30 s
- a full profile
- every contract with charges and feedback both ways, education, employment, languages, certificates
- price
- $4 / $5 / $20 per 1,000 rows — stored / live search / full profile. No start fee.
- code
- working examples in Python, JavaScript and curl
Open the actor on Apify, run a stored search with the filters you need, export the dataset.
$4.00 per 1,000 stored rows · $5.00 per 1,000 live search rows · $20.00 per 1,000 full profiles · no start fee, a zero-row run is freeFilters a page scrape cannot do
Upwork's own talent search filters by fixed bands and one order. Ours filters on the numbers a client actually cares about, at the thresholds you choose, because they are columns in our table, not boxes on a page:
- Rate band —
rateMin/rateMaxas numbers. Measured on the release runs: 25 of 25 rows inside the band, every time. - Job Success Score —
jssMin. JSS is on 90.3% of stored rows, as a percentage, not a flag. - Badge —
topRated,topRatedPlus,risingTalent. - Place —
countries(any of) and Upwork'sregions. - Track record —
hoursMin,jobsMin,earnedMin,hireAgainMin,memberSinceAfter,lastWorkedWithinDays. - Skills (any of),
availability,idVerified,excludeAgencies. - Change —
changedSincereturns only freelancers whose rate, title, JSS, badge, hours, jobs, skills or availability moved since a date or a window (7d), with the changes listed.
Nine sort orders: relevance, rate, hours, JSS, earnings, recency and more. Worked examples: Top Rated US Python developers at $50–100/h and JSS 95+, 1,000+ hours, worked in the last 60 days — run them as they are.
What a profile page hides, in the row
A visitor to an Upwork profile sees an earnings band, a rate and a title. The row we return carries the figures behind them:
- Exact lifetime earnings where Upwork exposes the figure, with
earnings_precisionsayingexactorband, andearnings_hiddenwhen the freelancer hides it. A figure is on 47.7% of stored rows today and the share grows as the census re-reads profiles. - Hours, jobs (hourly and fixed), completed contracts, hire-again rate, average rating, member-since, last-worked date, availability, ID and phone verification — on every profiled row.
- The contract history.
include: ["contracts"]adds every completed contract we hold for the freelancer: title, type, dates, hours, charges, the client's name, the client's feedback with its six detail scores, and what the freelancer wrote about the client. 395,022 contract rows over 30,031 profiles, 156,836 of them with feedback in both directions (read 2026-09-13). - The sections a visitor never sees. Education, employment history, languages with proficiency, certificates, other experiences — fetched on 99.2% of stored profiles and on every live read.
- History.
fetched_at,age_days,first_seen_at,last_seen_at, aversionscount, andchangeswhen you asked what moved. - Private profiles are an answer, not a gap: 5,313 profiles that went private are tracked and come back as
status: privatewith the date and their last public state.
Three ways to ask, three prices
| mode | input | what comes back | measured | per 1,000 rows |
|---|---|---|---|---|
| stored search | query + filters | rows from the census, sorted, with provenance stamps; rows older than maxAgeDays (default 30) left out unless you ask | 25 rows in 0.4–1.9 s | $4.00 |
| live search | liveSearch: true + query + filters | Upwork's current result for the query, in Upwork's order, filters applied server-side; rows join the census | 25 rows in under 30 s, 25 of 25 on every filter | $5.00 |
| full profile | profileUrls + fullProfiles: true | the profile read now, every contract fetched and stored, all the sections | 3 profiles in 33.7 s cold | $20.00 |
The lookup path takes profileUrls (URLs or ~01… ids) and answers from the census at the stored price. Ids the census has not seen are listed in the run's status message, not invented.
Why it is built this way
Every other Upwork talent scraper on the store reads the same search result at run time. That is why they all return the same 25 people in the same order for the same query, differ only in fields and price, and why most of them return nothing on a given day (measured 2026-09-11: 4 of 11 delivered rows). A run-time scrape filters only on what the search result offers, at the steps it offers; it cannot filter on hire-again rate or last-worked date, because those are on the profile, and it cannot say what changed since last week, because it has no last week.
A census can. We read profiles every day, keep every version, and answer searches from the table. The cost of that is honesty about age — every row says when it was read — and the benefit is everything above.
Start with one of the five worked examples, then change the query.
$4.00 per 1,000 stored rows · $5.00 per 1,000 live search rows · $20.00 per 1,000 full profiles · no start fee, a zero-row run is freeQuestions
- How fresh is a stored row?
- Each row carries
fetched_atandage_days. A stored search leaves out rows older thanmaxAgeDays(default 30) unless you setincludeStale. The census re-reads the oldest profiles on a rolling basis;liveSearchreads Upwork at run time when you need the current result. - Does it need my Upwork account?
- No. Nothing is read through a buyer's account or browser. The census is built from public profiles with anonymous sessions, the same pages a logged-out visitor can open.
- What does a run cost?
- One event per row that lands in your dataset — $4 per 1,000 stored rows, $5 per 1,000 live search rows, $20 per 1,000 full profiles. No start fee, no minimum, and a zero-row run costs nothing. 500 stored rows are $2.00.
- Can I get the data as CSV?
- Yes — every run's dataset exports as CSV, JSON, Excel or XML from the Apify console or the API. How to export Upwork freelancers to CSV or JSON.
- How does it compare with the other Upwork scrapers on Apify?
- We measured the lane on one day with the same query and filters: Best Upwork freelancer scrapers, measured.