Upwork Jobs Universal Scraper avatar

Upwork Jobs Universal Scraper

Pricing

from $1.02 / 1,000 results

Go to Apify Store
Upwork Jobs Universal Scraper

Upwork Jobs Universal Scraper

Stay on top of new Upwork jobs that match your search. Keyword, type, rate, skills and country filters, full description, budget and a direct job URL. No login. Pay per job.

Pricing

from $1.02 / 1,000 results

Rating

5.0

(1)

Developer

Scrapifier

Scrapifier

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

4 days ago

Last modified

Share

Upwork Jobs Scraper

Stay on top of new Upwork jobs that match what you already search for. Type the same keywords you use on Upwork, add filters, or paste a search URL, and export every matching posting as JSON, CSV or Excel — or pull them from the API on a schedule.

⚡ For every job you get the title, the full description, hourly range or fixed budget, experience level, engagement length, required skills, posting time and a direct job URL. No Upwork login. You pay per job.

Apify Actor

🎯 Why scrape Upwork jobs?

  • Job alerts: sort by most recent, turn on “Only new jobs since last run”, schedule the Actor every 5–15 minutes, and feed Slack, email or your own board.
  • Freelance market research: measure demand, rates and required skills for a query across countries.
  • Lead lists: every new posting that matches your niche is an opportunity, with budget and description attached.
  • AI / matching datasets: full plain-text descriptions at scale for classification or ranking models.

📊 What data does Upwork Jobs Scraper extract?

FieldDescription
id, ciphertextUpwork job id and the id used in the job URL
urlDirect job page (https://www.upwork.com/jobs/~02…)
titleJob title
descriptionFull plain-text description (fullDescription on by default)
jobTypeHOURLY or FIXED
experienceLevelEntryLevel, IntermediateLevel or ExpertLevel
hourlyRateMin, hourlyRateMaxHourly budget bounds
fixedBudgetFixed-price amount
durationWeeksEngagement length in weeks
hourlyEngagementTypeHourly engagement type when Upwork sets one
skills, skillUidsSkill labels and Upwork skill ids
publishedAtPublication time (ISO 8601)
searchInputThe search or pasted URL that produced this job

This Actor reads the public job card (the same data you see before opening a job as a visitor). Client spend, payment-verified flags and proposal counts are not on that card and are not returned.

With flatten enabled, skills and skillUids become comma-separated strings so every CSV column stays flat.

🚀 How to scrape Upwork jobs

  1. Type your Search keywords (python, react developer, logo design) and set Sort by to Most recent first for alerts.
  2. Optionally filter: job type, experience level, client country, hourly/fixed budget, client hires, duration, workload, timezone, contract-to-hire, posted-within.
  3. Or paste full Upwork search URLs. Each URL is scraped with its own filters, on top of the keyword search.
  4. Set Maximum jobs (0 = every unique job this search returns) and click Start.
  5. For a feed of new work only, enable Only new jobs since last run and put the Actor on a schedule.
  6. Open Storage to preview jobs and export JSON, CSV, Excel or XML, or read them from the dataset API.

📥 Input parameters

FieldKeyTypeDefaultDescription
Search keywordsquerystringpython (prefill)What you would type on Upwork. Empty = the whole feed with the other filters.
Sort bysortselectrecencyrecency (best for alerts) or relevance.
Job typejobTypeselectanyhourly or fixed.
Experience levelexperienceLevelselectanyentry, intermediate, expert.
Client countrylocationstringnoneFull country name (United States, France). Two-letter codes return nothing.
Min/max hourly ratehourlyRateMin / hourlyRateMaxintegernoneUSD bounds for hourly jobs.
Min/max fixed budgetfixedBudgetMin / fixedBudgetMaxintegernoneUSD bounds for fixed-price jobs.
Client hiresclientHiresselectanyNo hires / 1–9 / 10+.
Contract-to-hire onlycontractToHirebooleanfalseOnly contract-to-hire postings.
Project durationprojectDurationselectanyweek, month, semester, ongoing.
Workloadworkloadselectanyas_needed, part_time, full_time.
Client timezonetimezonestringnoneIANA name (America/New_York).
Skill / category idsskillUid, categoryUid, subcategoryUidstringnoneOptional ids from a previous result or from a search URL.
Posted withinpostedWithinselectany timeLast 24 hours to 30 days. Applied on publishedAt.
Upwork search URLsstartUrlsarray of URLsnoneFull search-result URLs, scraped with their own filters.
Maximum jobsmaxJobsinteger0Total cap (0 = every unique job this search returns).
Only new jobs since last runincrementalModebooleanfalseSkip job ids already returned for this search.
Fetch full descriptionsfullDescriptionbooleantrueInclude the full plain-text description.
Flatten outputflattenbooleanfalseLists become comma-separated strings.
Report input statusemitInputStatusbooleantrueWrite an input_status report to OUTPUT.
Proxy configurationproxyConfigurationobjectApify Proxy, residentialKeep Apify Proxy on for cloud runs.

Example input (alert feed):

{
"query": "python",
"sort": "recency",
"jobType": "hourly",
"hourlyRateMin": 30,
"postedWithin": "1",
"maxJobs": 50,
"incrementalMode": true
}

To reproduce an exact Upwork search, build it on the site and paste the results URL into startUrls.

📤 Output example

{
"id": "2095999094643674588",
"ciphertext": "~022095999094643674588",
"url": "https://www.upwork.com/jobs/~022095999094643674588",
"title": "Python developer for data pipeline",
"description": "We need a Python developer to build and maintain ETL jobs…",
"jobType": "HOURLY",
"experienceLevel": "IntermediateLevel",
"hourlyRateMin": 30,
"hourlyRateMax": 50,
"fixedBudget": null,
"durationWeeks": 12,
"hourlyEngagementType": "PART_TIME",
"skills": ["Python", "ETL", "PostgreSQL"],
"skillUids": ["1031626745410101248"],
"publishedAt": "2026-09-05T00:16:16.967Z",
"searchInput": "python | hourly"
}

The run's OUTPUT record also holds stats and, per search, an input_status entry with how many jobs Upwork announced, how many were collected, and why the search stopped.

💡 Ready-to-run examples

Hourly Python jobs, most recent first (alerts)

{ "query": "python", "sort": "recency", "jobType": "hourly", "maxJobs": 0, "incrementalMode": true }

Fixed-price design work in the United States

{ "query": "logo design", "jobType": "fixed", "location": "United States", "fixedBudgetMin": 100, "maxJobs": 100 }

From a pasted Upwork search URL

{ "startUrls": [{ "url": "https://www.upwork.com/nx/search/jobs/?q=react&sort=recency&t=0" }], "maxJobs": 0 }

Expert-level jobs posted today, flat CSV

{ "query": "machine learning", "experienceLevel": "expert", "postedWithin": "1", "sort": "recency", "maxJobs": 80, "flatten": true }

💰 Pricing: how much does it cost to scrape Upwork?

You pay only for the jobs you receive, with no subscription and no start fee. New Apify accounts get free monthly platform credits to try it. Cap volume with maxJobs, and narrow the set with filters before you pay for it.

⚙️ Performance, proxies and limits

  • Speed: results come 50 jobs per page until the search is exhausted or you hit maxJobs.
  • Completeness: maxJobs: 0 (the default) keeps going until every unique job for your filters is collected. Upwork serves about 5,050 jobs per raw search; when that is not enough the Actor continues with narrower slices (hourly vs fixed, client hires, experience, rate) and unions unique ids. Pages overlap slightly so a live feed that moved between requests does not drop listings.
  • Dedup: listings are unique on ciphertext. Incremental mode remembers that id across runs of the same search.
  • Full descriptions come with each listing. Turn fullDescription off only if you want smaller records.
  • Proxy: keep Apify Proxy on for cloud runs; a residential proxy is the reliable default.
  • Client panel (spend, verified payment, proposal count) is not part of the public job card this Actor returns.

🔌 Integrations and API

Run Upwork Jobs Scraper from the Apify API, the Python or JavaScript client, or on a schedule. Connect it to Make, Zapier, n8n, Google Sheets, Slack or any webhook through Apify integrations.

curl -X POST "https://api.apify.com/v2/acts/scrapifier~upwork-jobs-universal-scraper/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "query": "python", "sort": "recency", "maxJobs": 25 }'

❓ FAQ

Is it legal to scrape Upwork?

The Actor only reads job listings Upwork publishes to anyone without logging in. Descriptions can contain personal data, so process them in line with GDPR and other privacy laws, respect Upwork's terms of use, and stay responsible for how you use the data. This is not legal advice.

Do I need an Upwork account, login or cookies?

No. Nothing to log in to, and no cookies to paste.

How do I get only jobs posted since my last run?

Enable incrementalMode, keep sort on recency, and schedule the Actor. The dataset of each run then contains only new ciphertext values for that search.

How many jobs can one search return?

Set maxJobs to 0 (default) to collect every unique job for your filters, 50 per page. A single Upwork search stops around 5,050 results; the Actor then continues automatically with narrower slices and de-duplicates on ciphertext. Cap with maxJobs if you only want a sample.

Why is the client country empty when I did not set the location filter?

The public job card does not include the client's country. The location input filters the search to that country; it is not copied onto each row. Use searchInput to see which search produced the job.

Can I export to Excel or Google Sheets?

Yes. Every run's dataset downloads as CSV, XLSX, JSON or XML from the Storage tab. Turn on flatten for flat columns.

Does it get the full job description?

Yes. fullDescription is on by default.

💬 Support

Questions, bugs or a feature request? Open an issue in the Issues tab of this Actor. If Upwork Jobs Scraper saves you time, a rating on the Store helps others find it.