moxlade/guides/export upwork freelancers to csv
How to export Upwork freelancers to CSV or JSON — a filtered list with rates, JSS, earnings and contracts, in one run
Upwork has no export button for talent search, and its API needs a reviewed key. This is the route that works today: run our Upwork freelancer scraper on Apify with the filters you want, then download the result as CSV, JSON, Excel or XML — 65 typed columns per freelancer, from a census of 30,042 profiles. About five minutes the first time.
published 2026-09-13 · updated 2026-09-13The steps
- Open the actor. moxlade/upwork-freelancers on the Apify Store. A free Apify account is enough; the actor bills per delivered row on top of it.
- Set what you want. A
query(matched against title, overview and skills), then the filters:rateMin/rateMax,jssMin,topRated,countries,hoursMin,lastWorkedWithinDays,skills, and so on. SetmaxItems— it is both the row cap and the spending cap. - Start the run. A stored search of 500 rows answers in one call, in seconds. A
liveSearchasks Upwork now and takes under a minute for 25 rows. - Export. On the run's Output tab, choose Export → CSV, JSON, Excel, XML, HTML or RSS. Pick the columns you want, or take all 65.
Or pull it over the API
One request runs the actor and returns the rows in the format you name — for a pipeline, a sheet that refreshes, or an agent:
curl -X POST "https://api.apify.com/v2/acts/moxlade~upwork-freelancers/run-sync-get-dataset-items?token=YOUR_TOKEN&format=csv" \
-H 'Content-Type: application/json' \
-d '{"query": "python developer", "topRated": true, "countries": ["United States"], "rateMin": 50, "rateMax": 100, "maxItems": 200}'
format=json, xlsx or xml work the same way; add &fields=name,title,rate,jss,total_earnings,url to keep only the columns you need. The Apify client libraries for Python and JavaScript wrap the same call — ready-to-run scripts for every export on this page are in getmoxlade/upwork-freelancers-examples.
What the columns are
| group | columns |
|---|---|
| identity | ciphertext (the stable id to join on), person_id, url, name, title, overview |
| place | country, country_code, state, city, region, timezone |
| money | rate (USD/h), total_earnings, earnings_precision (exact / band), earnings_hidden |
| track record | jss (percentage), jss_hidden, hours, jobs_total, jobs_hourly, jobs_fixed, contracts_total, hire_again_pct, rating, feedback_count, recent_hours, recent_jobs, member_since, last_worked_on |
| badges and flags | badge, top_rated, top_rated_plus, availability, contract_to_hire, id_verified, phone_verified, agency_name |
| skills | skills (display names, an array), portfolio_count |
| provenance | source (stored / live), fetched_at, age_days, first_seen_at, last_seen_at, versions, changes, status (public / private), private_since |
on request (include) | contracts (every completed contract with client feedback and the freelancer's feedback about the client), contracts_in_progress, education, employment_history, languages, certificates, other_experiences, portfolios, testimonials, specialized_profiles |
Three exports people actually run
A shortlist for a role
query + topRated + countries + a rate band + jssMin: 90 + lastWorkedWithinDays: 60, sorted by jss, maxItems: 200. 200 rows, $0.80. Ready-made: Top Rated US Python developers at $50–100/h.
A benchmark of what people charge
The same query without a badge filter, sort: "rate", 500 rows, then a pivot on country and member_since in the sheet. Rates are the listed rates; total_earnings and hours say who actually works at them.
A weekly refresh of a list you already have
Save the run as a task with changedSince: "7d" and includeStale: true, schedule it weekly: only freelancers whose rate, title, JSS, badge, hours, jobs, skills or availability moved come back, each with a changes list — nothing to diff. Ready-made: What changed this week.
What it costs
$4.00 per 1,000 stored rows, so a 500-row export is $2.00 and a 5,000-row one is $20.00. There is no start fee and a run that returns nothing costs nothing. liveSearch rows are $5.00 per 1,000; a fullProfiles read (the profile now, every contract, all the sections) is $20.00 per 1,000 profiles.
Run the actor with your filters, then export the dataset in the format your sheet or pipeline wants.
$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
- Can I export Upwork freelancers to Excel?
- Yes. The dataset's Export menu has Excel (xlsx) next to CSV and JSON, and the API takes
format=xlsx. Arrays such asskillsandcontractscome through as JSON text in a cell. - Does the export include the freelancer's earnings?
- Where Upwork exposes the figure, yes —
total_earningswithearnings_precision: exact; where only a rounded band is shown, the band's lower bound withband; when hidden, null withearnings_hidden: true. A figure is on 47.7% of stored rows today. - How do I export a specific list of profiles rather than a search?
- Pass
profileUrls(profile URLs or~01…ids, up to 5,000). Profiles that went private come back asstatus: privatewith the date; ids the census has not seen are listed in the run's status message. - Can the export include each freelancer's contracts?
- Set
include: ["contracts"]on any search or lookup and each row carries its completed contracts — title, type, dates, hours, charges, client name, the client's feedback with its six detail scores, and the freelancer's feedback about the client. For a complete, freshly read history usefullProfiles: true. - Is there a limit on how many rows I can export?
maxItemsgoes up to 5,000 per run; a stored search returns 500 rows per call and pages through the rest. Run it again with a different query or filters for more.