Upwork Jobs Scraper
Pricing
from $2.25 / 1,000 results
Upwork Jobs Scraper
Collect Upwork job posts - budget, hourly range, skills - by keyword search.
Upwork Jobs Scraper — budget, hourly rate, skills
The Upwork Jobs Scraper collects freelance job posts from Upwork search. Give it keywords, and it returns the newest matching posts with the job's description, whether it is fixed-price or hourly, the fixed budget or the hourly range as numbers, the required experience level, Upwork's own skill tags and the posted timestamp.
To scrape Upwork jobs, put one or more keywords in queries — "react developer",
"shopify", "technical writer". Every search is sorted by recency, so the newest posts come
first. No Upwork account, login or subscription is used; this Actor reads what an anonymous visitor
can search. Around 37 jobs per keyword.
What it returns
| Field | Type | Notes |
|---|---|---|
jobId | string | Upwork's own job ID — stable, use it to de-duplicate |
title | string | |
description | string | The job post's description text, as Upwork's own search returns it |
jobType | string | "FIXED" or "HOURLY" |
budget | number | The fixed-price total, e.g. 40. Populated only when jobType is "FIXED" |
hourlyMin, hourlyMax | number | The hourly range, e.g. 15 and 40. Populated only when jobType is "HOURLY" |
currency | string | ISO code of the fixed-price budget, e.g. "USD" |
experienceLevel | string | The tier the client asked for, e.g. "IntermediateLevel", "ExpertLevel" |
skills | string[] | Upwork's own skill labels, e.g. ["Data Scraping", "Python"] |
postedAt | string | ISO 8601 timestamp of when the post was published |
jobUrl | string | Direct link to the Upwork job post |
query, sourceUrl, collectedAt | string | Provenance for every row |
A job is priced one way or the other, so budget and the hourly range are never both filled. Each
is gated on the jobType Upwork assigned, rather than carrying a value across and inventing a
budget the client never set.
Input
{ "queries": ["react developer", "shopify", "technical writer"] }
| Field | Description |
|---|---|
queries | Keywords to search Upwork for. Required, 1–50. Duplicates collapse to one fetch. |
maxItems | Cap on dataset items. Default 1000. Free plans stop at 250 requests and 250 results — see below. |
concurrency | Searches run in parallel. Default 3, maximum 5. |
There is no location input: the Upwork Jobs Scraper searches Upwork's global marketplace, and
queries is the only filter.
Use cases
- Freelance rate benchmarking — what clients actually pay for a skill, fixed and hourly
- Demand tracking for a skill or stack over time, by re-running on a schedule
- Lead lists of open projects for an agency or freelancer
- Sizing a service market from
skills,budgetandexperienceLevel - Feeding a job-alert product with the newest Upwork posts, joined on
jobId
Reliability
The Upwork Jobs Scraper calls the same search endpoint Upwork's own site calls, so the response is typed JSON: budgets as numbers, skills as labels, an explicit job type and a real publish timestamp. The rendered search page is not used — its state blob is a minified bundle that reads back as no usable structure, and the tiles it renders carry less than the search response does.
Reaching that endpoint anonymously needs Upwork's visitor token, which the search page hands out as a cookie. Each run mints one token up front, which costs one extra request per run and no account of any kind.
A keyword search that cannot be read is recorded in the run's SUMMARY under failures, together
with Upwork's own explanation where it gave one, and a run where every keyword failed exits with an
error.
Frequently asked questions
Do I need an Upwork account, login or Freelancer Plus plan? No. The Upwork Jobs Scraper uses no account and no login — it searches as an anonymous visitor, using the visitor token Upwork's own search page issues.
Does it return the client's country, total spend or hire rate? No. Client identity and history sit behind a scope Upwork's anonymous visitor token does not hold, so those fields are deliberately not returned rather than returned empty.
How many Upwork jobs does one keyword return? One request per keyword, asking Upwork for its 50 newest matches; the measured average is around 37 jobs per keyword. Ten keywords therefore return roughly 370 jobs.
Are the results the newest posts? Yes. Every search is sorted by recency, and postedAt carries
the publish timestamp so you can filter further.
Is the budget a number? Yes. budget is the fixed-price total as a number and hourlyMin /
hourlyMax are the hourly bounds, so nothing has to be parsed out of a display string.
Can I filter by client location or budget? No. queries is the only filter this Actor takes;
filter the returned rows on budget, hourlyMin, experienceLevel or skills afterwards.
What happens on a free Apify plan? The run stops at 250 requests and 250 results and reports that it hit the limit. Any paid plan runs the full input.
Limitations
The Upwork Jobs Scraper collects one page of results per keyword, so it captures the newest posts rather than a full crawl of the marketplace; run several narrower keywords to widen coverage. Client country, client total spend, hire rate, proposal and applicant counts, and freelancer profiles are out of scope, and there is no location or budget filter on the input.
Free plan limit
Runs started from an Apify free plan stop at 250 requests and 250 results, and the run
reports that it reached the limit. Any paid plan runs the full input and maxItems you set.
The limit exists because this Actor fetches through our own infrastructure, which Apify does not cover for free-plan runs. It binds on requests as well as results so that a large input list cannot spend those fetches for rows the run will not return.