Upwork Jobs Scraper - Budget, Skills, Proposals, Client Country avatar

Upwork Jobs Scraper - Budget, Skills, Proposals, Client Country

Pricing

$0.99 / 1,000 jobs

Go to Apify Store
Upwork Jobs Scraper - Budget, Skills, Proposals, Client Country

Upwork Jobs Scraper - Budget, Skills, Proposals, Client Country

Search Upwork's public job board by keyword: full description, fixed budget or hourly range, experience level, skills, posted time, proposals, client country and payment verification. No login or cookies. Deduplicated across queries; incomplete rows are marked, never shown as empty.

Pricing

$0.99 / 1,000 jobs

Rating

0.0

(0)

Developer

Lantern Lab

Lantern Lab

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Share

Upwork Jobs Scraper

Search Upwork's public job board by keyword and get each job back with its full description, fixed budget or hourly range, experience level, skills, posted time, proposals count, and the client's country, payment verification, total spend and rating — public statistics only, never a client or company name. No Upwork login, no cookies of yours.

Price: $0.99 per 1,000 jobs. Partial job rows, search query status rows and the run summary are free, and so is a query that finds nothing.

Quick example

Input:

{
"searchQueries": ["react native", "shopify"],
"maxJobs": 50,
"sortBy": "recency"
}

One job row (recordType: "job", shortened):

{
"recordType": "job",
"jobId": "2107267731025843411",
"title": "Next.js Website Review & Bug Audit",
"description": "Summary\n\nWe're looking for an experienced Next.js developer to review an existing website ...",
"jobType": "fixed",
"budget": 100,
"hourlyRateMin": null,
"hourlyRateMax": null,
"currency": "USD",
"experienceLevel": "Expert",
"skills": ["React", "JavaScript", "Web Development"],
"category": "Web Development",
"projectLength": "Less than 1 month",
"proposalsText": "20 to 50",
"proposalsCount": 30,
"clientCountry": "United States",
"clientPaymentVerified": true,
"clientTotalSpent": 1017.5,
"clientRating": 5,
"clientReviewCount": 6,
"url": "https://www.upwork.com/jobs/~022107267731025843411",
"searchQuery": "react native",
"publishedAt": "2026-10-06T00:32:35.522Z",
"partial": false,
"collectedAt": "2026-10-23T21:50:20.034Z"
}

Limits

  • How many jobs a query reaches is up to Upwork's public search. It lists open jobs only, and the count it shows a visitor who is not signed in varies: on 2026-10-24 "python" listed 113 jobs in one run and 1,828 in another. This Actor does not sign in, so a query ends when Upwork's list ends, even below maxJobs. The query_status row gives the count Upwork listed (jobsAvailable).
  • Private listings: search fields only. Some listed jobs (about 1 in 10 in our tests) are private listings whose page opens only for signed-in users. They are still written, free, with what the search results show (title, description, type, budget or rate where shown, experience level, skills, posted time) and partial: true, partialReason: "private_listing". Their client country, payment verification and proposals are null.
  • About 2 seconds per job: every job's own page is read for the client and proposals fields, one at a time.
  • Public data only. Upwork does not show a visitor the client's name or company, and this Actor never collects them; the client's city is also left out.
  • Runs a real browser on Apify Proxy (datacenter), because Upwork refuses plain HTTP clients and requests without a proxy. When Upwork refuses a request, the Actor waits, then retries from a fresh IP.
  • No scheduling or monitoring built in; use Apify schedules.

What it does

  • Searches each keyword the way Upwork's own job search does, newest first or by best match, 50 jobs per results page.
  • Reads every new job's page for the fields the results page leaves out: client country, payment verification, total spend, rating, proposals, interviewing and invites, category and workload.
  • Deduplicates across the whole run: a job found by two queries is written and charged once, for the first query that found it.
  • Keeps Upwork's job ID (jobId), its publish time (publishedAt) and our collection time (collectedAt) as separate fields.
  • Says what happened to every query. A query with no job, a query that was cut short, and a job whose page could not be read are different records and are never confused: anything incomplete is marked partial: true with the reason.
  • Caps itself: maxUpstreamRequests is a hard ceiling on page requests to Upwork for the whole run, retries included, derived from your input when you leave it empty, so a run is never unbounded.

Input

FieldDefaultMeaning
searchQueries—Keywords, one per line, in any language. At least one, at most 100. Repeats (ignoring case) run once.
maxJobs50Upper bound on jobs per query, from the top of the results. Max 5,000.
sortByrecencyrecency (newest first) or relevance (Upwork's best match).
maxUpstreamRequestsderivedHard ceiling on page requests to Upwork for the whole run, retries included.
proxyConfigurationApify Proxy (datacenter)The proxy the browser goes through.

Output

One row per job, recordType: "job". Charged when partial is false:

FieldMeaning
jobId, ciphertextUpwork's job ID (the dedupe key) and the ID in the job's URL.
title, descriptionAs posted; the description is the full text.
jobTypefixed or hourly.
budgetFixed-price budget; null on hourly jobs and when the client hid it.
hourlyRateMin, hourlyRateMaxHourly range; null on fixed-price jobs and when the client set none.
currencyUSD.
experienceLevelEntry level, Intermediate or Expert.
skillsThe skills the job lists.
category, categoryGroup, projectLength, workloadAs the job's page shows them.
proposalsTextThe proposals range the job's page shows (Less than 5, 5 to 10, 10 to 15, 15 to 20, 20 to 50, 50+).
proposalsCount, interviewing, invitesSentThe counts behind the job's "Activity on this job" panel.
clientCountry, clientPaymentVerifiedThe client's country and whether their payment method is verified.
clientTotalSpent, clientRating, clientReviewCount, clientMemberSinceThe client's public history; clientRating is null until the client has a review.
urlThe job's Upwork page.
searchQueryThe query that found the job first in this run.
publishedAtWhen Upwork published the job.
partial, partialReasontrue with a reason when only the search-result fields could be read: private_listing, blocked, upstream_error, upstream_request_cap. Partial rows are free.
collectedAtOur own collection time.

One row per search query, recordType: "query_status", free: outcome is found, empty (no public job matches) or partial, with jobsAvailable (the count Upwork listed), jobsReturned, partialJobs, privateJobs, duplicatesSkipped, jobsGone (jobs closed between the search and their page), partialReason (blocked, upstream_error, upstream_request_cap, charge_limit_reached, not_collected) and statusText.

The last row is recordType: "RUN_SUMMARY" — what the queries came to, jobs collected and charged, partial jobs by reason, repeated jobs written once, requests sent, refusals and IP changes, and why collection stopped. The same object is also in the run's key-value store under RUN_SUMMARY.