Using the Upwork API without getting blocked
blackfalcondataBuilding against an Upwork API rarely fails at the parsing stage. The harder part is staying in: requests work, then responses arrive empty or truncated—or return a challenge page the parser cannot handle.
Here is what our own Upwork Actor handles, what each run costs, and where the Actor stops.
Doing it yourself
The DIY route makes sense for a single snapshot, or when the data is simple enough that a failed run has no cost. The work involved is less simple. These specifics come directly from the safeguards built into our own scraper.
The front door. Upwork's protection is not deterministic. Across 3 plain requests on 2026-08-22, 1 got a page and 2 were refused with 403 behind Cloudflare, actively challenging. That inconsistency is difficult to build around: a test passes, then production volume fails.
Getting past the gate. A 403 from Upwork does not always mean refusal. It often points to a stale session cookie. Obtaining a new cookie and repeating the request can fix it; backing off will not.
Telling a challenge from a block. Upwork uses the same status for "prove you are a browser" and "go away". The body reveals which response you received. A client that ignores it wastes its retry budget on the second case.
Rate limits. Upwork rate-limits per-source rather than per-account. Exponential backoff slows the run. Without it, the run fails.
Proxies. A thousand Upwork page requests from one IP form a pattern, not ordinary traffic. Rotation makes that volume unremarkable—and becomes the largest line item on the bill.
Pagination. An Upwork pagination loop needs to tell "no more results" apart from "we stopped being served results". Both conditions can produce an empty page.
Silent breakage. Upwork redesigns rarely produce loud scraper failures. A selector breaks, a field returns empty, and the run still reports success. The first warning is often a report that looks thin.
The real cost is upkeep. The first version takes an afternoon. Keeping it functional takes an hour every few weeks, forever. Failures stay quiet: an empty report exposes the problem, not a scraper error.
These figures come from a measured run, not an estimate:
- 25 records in 5.1 seconds
- cost: $0.00028 — about $0.01 per 1,000 records
The shortcut
If you do not want to maintain that machinery, one call returns the same result:
```bash curl -X POST "https://api.apify.com/v2/acts/blackfalcondata~upwork-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"query": "..."}' ```
The Python equivalent:
```python from apify_client import ApifyClient
client = ApifyClient("YOUR_TOKEN") run = client.actor("blackfalcondata~upwork-scraper").call(run_input={"query": "..."})
for item in client.dataset(run["defaultDatasetId"]).iterate_items(): print(item) ```
What comes back
Every row contains 55 fields, organized into several groups:
- client — clientCountry, clientCountryCode, clientTotalSpent, clientSpentCurrency, clientPaymentVerified, clientRating, +2 more
- salary — salaryMin, salaryMax, salaryCurrency, salaryType
- description — description, descriptionHtml, descriptionMarkdown
What people use it for
- Benchmarking. Pricing and salary fields allow comparisons across the entire set instead of relying on a page of results.
- Reputation monitoring. Changes in ratings and review text over time reveal movement that one page view cannot show.
- Geographic analysis. Location fields provide market-by-market comparisons without requiring another data source.
Limits
- Nothing here bypasses a Upwork login. Public pages only, regardless of who writes the scraper.
- A scraper that works today may not work in six weeks. Failure usually arrives as silence, not an exception.
- Proxy cost rises with volume. It is also the expense people tend to omit from DIY estimates.
Questions people ask
Is scraping Upwork legal?
Reading publicly visible pages is generally treated differently from accessing data behind a login, and courts in the US have repeatedly declined to treat public scraping as unauthorised access. That is not legal advice, and a site's terms of service remain separate from the law. Anything behind a login is out of scope either way.
Why am I getting 403s when the page loads fine in my browser?
The check concerns more than the URL. On 2026-08-22, cloudflare answered a plain request to Upwork from our probe and actively challenged it; 2 of 3 attempts were refused. A browser passes because it supplies a TLS fingerprint, a cookie and a header set that a bare HTTP client lacks.
Do I need proxies?
Yes, for anything larger than a small sample. Our own input exposes `proxyConfiguration` because a single origin IP is exceptionally easy to rate-limit.
How often will it break?
Plan to touch the scraper whenever Upwork releases a redesign. You may not notice immediately: extraction fails quietly, producing empty fields instead of errors. Budget an hour every few weeks, not a fix-and-forget afternoon.
Is it cheaper to build it myself?
Only when your time is free. The measured run below cost $0.00028 for 25 records. A DIY version adds proxy spend and a recurring maintenance hour.
Try it
To avoid owning the upkeep, use the Upwork API endpoint we maintain. It already handles everything described above. New accounts receive $5 of free platform credit each month, enough to cover a real run of this size several times over.
Disclosure: we build and maintain this Actor, and the link above is an affiliate link.
Further reading
- hiQ Labs v. LinkedIn — the appeals decision on scraping public pages
- Apify's API reference — the endpoints used above
- dataset storage — how results are stored and exported
- Stepstone API — another scraper we build and document
- how the Autoscout24 API responds — another scraper we build and document
- our Trustpilot API guide — another scraper we build and document
We also publish the Upwork API endpoint and what it returns on blackfalcondata.com — the request, the response, and what a run costs.