How to use it: 3 steps
- Make a free Apify accountApify is the cloud platform where our tools run. The free plan gives you $5 of usage every month, no credit card needed. You pay Apify, not us.
- Paste your input and press StartNo code needed: you fill in a form (the input). It already has a working example. For example:
web scrapingin Search phrases. Each start is one run. - Download the resultsWhen the run ends, the results are in a table (the dataset). Open Output, press Export and pick Excel or CSV. JSON and the API are there too.
This tool is an Apify Actor: a small program that runs on Apify. You can also run it on a schedule, for example every Monday. New to it? Read how it works, step by step and the 8 words you need first.
What it does
Use this Upwork jobs scraper to get public Upwork job posts by search phrase, search link, job link or job ID. Find clients, track freelance demand or get new job alerts. Each row has pay, skills, applicants and public client data such as country, spend and rating. No Upwork account or cookies needed.
Good for
- Find new clients and leads for a freelance team or agency.
- Track demand, pay and skills in a job category.
- Get an alert when a new job matches your search.
- Feed job rows to a sheet, database, Slack, Notion or an AI agent.
Who uses it
Freelancers
Get an alert when a new job matches your search.
Agencies
Find new clients and leads.
Market analysts
Track demand, pay and skills in a job category.
Price
Pay per event: you pay for each result the tool saves, plus a small start fee for each run. The price includes Apify platform costs. Apify bills you, not us. Prices below are for the Apify free plan.
| What you pay for | Price | When |
|---|---|---|
| Start fee | $0.001 | Charged once per run. This tool uses 1 GB of memory or less by default; more memory costs more. |
| Source request | $0.0001 | One public source request started, including empty results and jobs that do not match filters. Redirects and retries are included. |
| Saved job | $0.0009 (from $0.00063 on paid Apify plans) | One job saved in the dataset. |
Examples
- One result: about $0.0019.
- 1,000 results: about $0.90.
- Every day 100 results, for 30 days: about $2.73 a month.
Free to try: the Apify free plan gives you $5 of usage every month, no credit card needed. That is enough for about 5,500 results.
Prices checked on 8 November 2026. See the current price on Apify.
Questions
Do I need an Upwork account or cookies?
No. The Actor reads only what Upwork shows to visitors. Do not give it your login.
Why is clientRating null?
The client has no public reviews yet. Null means unknown or hidden. It is not the same as 0.
Can this Actor apply for jobs or contact clients?
No. It only reads public job posts.
Can I scrape Upwork jobs by a search link?
Yes. Run your search on Upwork, copy the link and paste it in startUrls. Filters in the link are used.
How do I get only new jobs?
Set onlyNew: true and run the Actor on an Apify Schedule. The first run saves all matches up to maxItems as a starting point. Later runs save only jobs not saved before.
Why do I pay for source requests when no job is saved?
The Actor must read the source to find out if a job matches. So each source request is charged, even if your filters remove all jobs. Make filters part of the search when you can, for example jobType or experienceLevel.
How fresh is the data?
Each row is read during the run, and fetchedAt shows the time. Rows are not updated later. Run again or use a schedule for fresh data.
Is this an official Upwork product?
No. This Actor is not affiliated with or endorsed by Upwork.
Details
Step by step on Apify
- Open the Input tab. Keep
web scrapingin Search phrases, or type your own phrase (box 1). - Keep
10in Maximum results for a first test (box 2). Filters are optional, see Input. - Click Start.
- When the run ends, open the Output tab. Each row is one job (box 4). Check the job title, budget, client spend and applicants.
Use cases
| Task | Input | You get | Key fields | Next step |
|---|---|---|---|---|
| Find clients who pay well | queries, minClientTotalSpent, paymentVerified: true | One job per row | title, clientCountry, clientTotalSpent, clientRating, url | CRM or a sheet |
| Get new job alerts | queries, onlyNew: true, Apify Schedule | Only jobs not saved before | title, budget, hourlyRange, postedAt, url | Slack or Notion with deliveryConnector |
| Track market demand and pay | queries or categories, maxItems: 1000 | One job per row | skills, hourlyBudgetMin, hourlyBudgetMax, budget, category | Sheet or BI tool |
| Copy a search you made on Upwork | startUrls with an Upwork search link | One job per row | title, jobType, experienceLevel, postedAt, url | Dataset API |
| Check known jobs | jobIds or job links in startUrls | One row per public job | jobStatus, totalApplicants, hired, clientLastActivity, detailsStatus | Your own job tracker |
Tips for better results
- Keep 10 in Maximum results for a first test.
- Paste a search link from Upwork in startUrls. The filters in the link are used.
- Set onlyNew to true and use an Apify Schedule to get only new jobs.
Limits and good to know
- Only public data. There is no login, so private and invite-only jobs are not available
- Some jobs show details only to members. In our 6,000-job test, 1,055 jobs had no public details. These rows keep the search fields and have
detailsStatus: "members_only" clientAvgHourlyRateandclientHireRatePercentare hidden from visitors, so they stay null- The largest tested run saved 6,000 jobs in about 20 minutes. The default timeout is 300 seconds. Raise it for runs over about 1,000 jobs
- A big search is split by category, type and experience level to get past the source limit of about 5,000 results per search. So a big result has no single global order
- If the source still holds back part of a search, the summary says
SOURCE_CAPandsourceCapPartitionscounts the affected parts skipRepostsskips only exact repeats of the cleaned title and description. Reworded reposts are saved- A monitor history keeps up to 100,000 jobs. Closed and then the oldest jobs are dropped first
For developers
Sample result
One result from a real test run, in JSON. Real values change from run to run. In Excel or CSV each field is a column.
{
"jobId": "2117702916010329632",
"title": "Social Media automated data collection (API) and Website Data Collection",
"jobType": "hourly",
"hourlyRange": {
"min": 6,
"max": 25
},
"budget": null,
"experienceLevel": "intermediate",
"skills": [
"Data Scraping",
"Web Scraping",
"API Integration",
"Social Media Marketing"
],
"duration": "1 to 3 months",
"postedAt": "2026-11-03T19:38:23.701Z",
"clientCountry": "United States",
"clientPaymentVerified": true,
"clientTotalSpent": 599.1,
"clientSpentCurrency": "USD",
"clientRating": 5,
"clientReviewCount": 2,
"clientTotalHires": 5,
"totalApplicants": 37,
"jobStatus": "open",
"detailsStatus": "available",
"url": "https://www.upwork.com/jobs/~022117702916010329632",
"fetchedAt": "2026-11-04T12:08:00.362Z"
}Use it from code
Actor ID: cliqtomedia/upwork-jobs-scraper. You need your Apify API token from Apify Console → Settings → API & Integrations.
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("cliqtomedia/upwork-jobs-scraper").call(run_input={
"queries": [
"web scraping"
],
"maxItems": 10
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item)curl -X POST "https://api.apify.com/v2/acts/cliqtomedia~upwork-jobs-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"queries": ["web scraping"], "maxItems": 10}'# pip install langchain-apify
# set APIFY_TOKEN in your environment
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("cliqtomedia/upwork-jobs-scraper")
result = tool.invoke({"run_input": {"queries": ["web scraping"], "maxItems": 10}})
print(result)The cURL call waits for the results, up to 300 seconds. For longer runs, start a run (/runs) and get the results with a webhook or by checking the run. Apify API docs. LlamaIndex, MCP for AI agents and the JavaScript client: AI agents & MCP.
Data fields (40)
| Field | Type | Meaning |
|---|---|---|
jobId | string | Upwork job ID. |
id | string | The same ID as jobId, for imports. |
ciphertext | string | Upwork ID used in the job link. |
title | string | Job title, with contact details removed. |
description | string | Full public job text, with email addresses and phone-like numbers removed. |
budget | number | Fixed-price budget. Null for hourly jobs or an undisclosed budget. |
budgetCurrency | string | Currency code of the fixed budget. |
hourlyRange | object | Known minimum and maximum hourly rates. Null limits mean undisclosed. |
hourlyBudgetMin | number | Known minimum hourly rate. |
hourlyBudgetMax | number | Known maximum hourly rate. |
weeklyRetainerBudget | number | Weekly retainer budget, when public. |
jobType | string | hourly, fixed or weekly_retainer. |
experienceLevel | string | entry, intermediate or expert. |
skills | array | Public skill names. |
skillIds | array | Public skill IDs. |
duration | string | Project duration label. |
durationWeeks | number | Project duration in weeks. |
workload | string | Weekly work requirement. |
postedAt | string | Publication time reported by Upwork. |
absoluteDate | string | The same publication time as postedAt. |
createdAt | string | Time the job was created. |
renewedAt | string | Source renewal or sourcing time, if given. |
clientCountry | string | Client country name. Source country codes are converted to country names. Null when hidden. |
clientCountryCode | string | Two-letter ISO country code from the public client country name. Null when the name cannot be matched. |
clientCity | string | Public client city, when visible. |
clientTimezone | string | Public client timezone label. |
clientPaymentVerified | boolean | Whether the public page shows a verified payment method. |
paymentVerified | boolean | The same value as clientPaymentVerified. |
clientTotalSpent | number | Public lifetime client spend. A hidden amount stays null. |
clientSpentCurrency | string | Currency of the public client spend. |
clientRating | number | Public client rating. Null when the client has no reviews. |
clientReviewCount | number | Public review count. |
clientTotalHires | number | Public total client assignments. |
clientActiveHires | number | Public active assignments. |
clientTotalHours | number | Public hours billed. |
clientMemberSince | string | Public client account creation date. |
clientIndustry | string | Public client industry. Null when empty. |
clientCompanySize | number | Company size group reported by Upwork. The group code is not a staff count. |
clientHireRatePercent | number | Null when this value is hidden from visitors. |
clientAvgHourlyRate | number | Null when this value is hidden from visitors. |
Input settings (25)
The main fields of the input form. With the API you send them as JSON.
| Setting | Name in the API | Type | Example value |
|---|---|---|---|
| Search phrases | queries | array | ["web scraping"] |
| Search or job URLs | startUrls | array | |
| Job IDs | jobIds | array | |
| Maximum results | maxItems | integer | 10 |
| Read public job details | includeDetails | boolean | true |
| Run mode | mode | string | "search" |
| Payment types | jobType | array | |
| Experience levels | experienceLevel | array | |
| Categories | categories | array | |
| Minimum fixed budget | minBudget | number | |
| Maximum fixed budget | maxBudget | number | |
| Minimum hourly rate | minHourlyRate | number | |
| Maximum hourly rate | maxHourlyRate | number | |
| Weekly workload | workload | array | |
| Project duration | duration | array | |
| Contract-to-hire only | contractToHire | boolean | false |
| Required words | includeKeywords | array | |
| Excluded words | excludeKeywords | array | |
| Required skills | requiredSkills | array | |
| Words in title | titleContains | string | |
| Maximum job age in minutes | maxAgeMinutes | number | |
| Job age | maxJobAge | object | |
| Published from | fromDate | string | |
| Published through | toDate | string | |
| Proposal ranges | proposals | array |


