Upwork Jobs Scraper - New Job Alerts, Budgets & Hourly Rates
Pricing
from $1.50 / 1,000 job postings
Upwork Jobs Scraper - New Job Alerts, Budgets & Hourly Rates
Scrape new Upwork jobs by keyword or search URL. Get title, full description, fixed budget or hourly rate, experience level, skills and posting time for each job. Built for freelancers, agencies and lead tools that want Upwork job alerts.
Pricing
from $1.50 / 1,000 job postings
Rating
0.0
(0)
Developer
SR
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Upwork Scraper: Upwork Jobs Scraper for New Job Alerts
This Upwork scraper finds new public Upwork jobs by search phrase or an Upwork job search URL and exports them as clean rows: job title, full public description, fixed budget or hourly rate, experience level, skills and the time the job was posted. Use it to build your own Upwork job alerts, feed new projects into a CRM or chat channel, or study what clients are hiring for.
Freelancers can monitor new opportunities in their specialism. Agencies can follow several skill combinations and identify work suitable for their teams. Analysts can study the mix of fixed projects and hourly contracts, while developers can use the stable job identifier to maintain their own history of opportunities. Each run retrieves the postings currently shown in public search results.
What the Upwork jobs scraper returns
One dataset row per unique job posting, with:
job_id,ciphertextandurl: stable identifiers and the link to the original postingtitleanddescription: the full public text, with line breaks keptjob_type:fixedorhourlybudgetfor fixed projects, orsalary_min/salary_maxper hour for hourly contractsexperience_level,workload,durationandskillsposted_at,created_atandrenewed_atin UTC
Only fields that any logged-out visitor can see are collected. Client names, client spending history and other client details are not part of the output.
How to scrape Upwork jobs
- Open the actor and enter one or more search phrases, for example
pythonorshopify developer, or paste an Upwork job search URL. - Keep
sortonrecencyto get the newest jobs first, and setmax_items. - Optionally set
posted_within_hoursto collect only jobs from the last hours. - Start the run and download the dataset as JSON, CSV or Excel, or read it through the Apify API.
- Schedule the run every few minutes or hours to turn it into an Upwork job feed.
Upwork Jobs Scraper input
Provide search_terms or search_urls. Choose exactly one of these lists and include at least one non-empty entry. A list can contain up to ten entries. Each search phrase is a separate search, so a phrase with several words is treated as one query. Upwork's search syntax, including quoted phrases and boolean expressions, can be used in a search term.
For example, this input searches for Python opportunities:
{"search_terms": ["python"], "max_items": 50, "sort": "recency"}
The default limit is fifty unique jobs per search. Set max_items between one and five thousand. Jobs appearing in more than one search are exported once; the first search that finds a job supplies its search_query. This means a later overlapping search can return fewer additional jobs than its limit. Whitespace-only entries are ignored, and repeated identical search entries are processed once.
Use job_type to select hourly, fixed or any. Use experience_level to select entry, intermediate, expert or any. These two fields apply to search phrases. When using search URLs, the filters already present in the URLs determine the searches. Only HTTPS URLs pointing to Upwork's /nx/search/jobs/ page are accepted. Page number and page size in an input URL are replaced automatically during collection.
Monitoring recent jobs (Upwork job alerts)
The default sort is recency, which retrieves the newest postings first. Choose relevance to use Upwork's relevance order. A sort parameter explicitly supplied in a search URL takes precedence over the input sort field.
Set posted_within_hours between one and seven hundred twenty to collect only jobs published within that window. This filter requires recency order for every search. The time window is anchored to the beginning of collection, so a long collection uses one consistent cutoff. Collection stops when it reaches an older posting. A search can therefore return fewer rows than its limit, or no matching recent jobs.
For repeat monitoring, schedule runs in Apify and compare job_id with identifiers you saved from earlier runs. The actor removes duplicates within a collection. Your application is responsible for maintaining history between separate runs. created_at, posted_at and renewed_at help you distinguish original creation from subsequent publication or renewal. Connect the dataset to a webhook, Make, Zapier or n8n to send each new job to email, Slack or Telegram; this works as an Upwork RSS feed alternative.
Output
The default dataset contains one row per unique public posting. Every row includes job_id, ciphertext, url, title, description, posted_at, created_at, renewed_at, fetched_at, job_type, experience_level, skills, workload, duration, position and search_query. Rows also carry source, platform and employment_type (always CONTRACTOR).
job_id is Upwork's numeric identifier represented as a string. ciphertext is the identifier used in the job URL. Both are provided so integrations can join by a stable identifier and still open the original posting directly. Search highlighting is removed from titles and descriptions, and description line breaks are preserved.
For fixed projects, budget contains the total project amount. For hourly contracts, salary_min and salary_max contain the published hourly range, with salary_period set to HOUR and salary_currency to USD. An hourly posting without a published range has null salary fields. Fixed budgets also have null salary fields because a total project budget is not an hourly wage. currency is USD for both job types.
Output example
Two real rows from a python search on 5 October 2026, a fixed-price project and an hourly contract:
[{"source": "upwork-jobs-scraper","platform": "upwork","employment_type": "CONTRACTOR","fetched_at": "2026-10-05T19:34:00.000Z","job_id": "2107126667072165637","ciphertext": "~022107126667072165637","url": "https://www.upwork.com/jobs/~022107126667072165637","title": "AI Backend Engineer Needed","description": "We need a backend engineer to build and maintain the server-side infrastructure for an AI-powered application. The role includes developing APIs, integrating AI models, and supporting database operations. You will work on improving system performance, reliability, and scalability while collaborating with the team to deliver a stable backend solution. Experience with Python, Django, and PostgreSQL is important, along with a strong understanding of backend architecture and deployment workflows.","posted_at": "2026-10-05T15:12:32.865Z","created_at": "2026-10-05T15:12:01.035Z","renewed_at": null,"job_type": "fixed","budget": 10,"currency": "USD","salary_min": null,"salary_max": null,"salary_currency": null,"salary_period": null,"experience_level": "intermediate","workload": null,"duration": "1 to 3 months","skills": ["PHP", "JavaScript", "Reverse Engineering", "Embedded C"],"position": 26,"search_query": "python"},{"source": "upwork-jobs-scraper","platform": "upwork","employment_type": "CONTRACTOR","fetched_at": "2026-10-05T19:34:00.000Z","job_id": "2107170088531208224","ciphertext": "~022107170088531208224","url": "https://www.upwork.com/jobs/~022107170088531208224","title": "Send an AI Agent to a specific URL","description": "Hi there\n\nI would like to see what we can measure when an \"AI Agent\" visits our website. We have the measurement tools - we need you to launch a visit using an AI Agent.\n\nPlease state in your bid which AI agent you will use. \n\nWe will pay $35 per agent. \n\nThanks\n.","posted_at": "2026-10-05T18:06:14.975Z","created_at": "2026-10-05T18:04:33.514Z","renewed_at": null,"job_type": "hourly","budget": null,"currency": "USD","salary_min": 35,"salary_max": 35,"salary_currency": "USD","salary_period": "HOUR","experience_level": "expert","workload": "not_sure","duration": "Less than 1 month","skills": ["AI Agent Development", "AI Agents", "Cybersecurity Tool"],"position": 8,"search_query": "python"}]
The OUTPUT record includes searches, with the latest source total and the cumulative number returned per search. A search marked partial has additional source results beyond what was delivered. The overall partial flag indicates unfinished collection or a source interruption. Read warnings when a run is incomplete. Source counts can change while jobs are added or removed, and public result availability can vary. For the search above it reported:
{"query": "python", "url": "https://www.upwork.com/nx/search/jobs/?q=python&sort=recency", "total_results": 1883, "returned": 50, "partial": true}
Use cases
- Freelancers: a personal Upwork job alert for your skills that fires before the posting has dozens of proposals.
- Agencies: follow several skill searches at once and route matching jobs to the right team.
- Lead generation tools: feed new Upwork jobs into a CRM, a scoring model or an AI proposal assistant.
- Market research: track demand for skills, the share of fixed and hourly work and published budgets over time.
- Recruiting and training: see which technologies clients ask for this week.
Upwork scraper compared with other options
| Option | What you get | Limits |
|---|---|---|
| Upwork's own job alerts and saved searches | Notifications inside your account | Needs a freelancer account, no export, no API access to the data |
| Upwork API | Official GraphQL access | Requires an approved API key and OAuth; aimed at apps working on behalf of a user |
| Browser extensions | Alerts while your browser is open | Run on your own machine and account, no scheduled export |
| Writing your own scraper | Full control | You maintain parsing, paging and deduplication yourself |
| Other Upwork scrapers in the Apify Store | Similar job data | Prices run from about $0.001 to $0.01 per job; field sets and client data differ |
| This actor | Clean job rows, fixed and hourly pay split into separate fields, deduplication, recency window | Public, logged-out fields only |
Pricing
The proposed launch model is $0.0015 per delivered job and $0.0005 per valid run. Confirm the active event prices in the actor's Pricing tab before running; that tab is authoritative. A run returning no jobs incurs no job-result charges. Invalid input is rejected before the run event is charged. A valid search that returns no matching jobs retains its run event.
Users without a paid Apify plan receive at most ten dataset rows per run. Result charges apply only to the rows delivered after that cap. Paying users can use their requested limits. Larger collections are continued automatically, and each delivered job is counted once rather than once per page.
Public search limits
The actor collects fields available to a logged-out visitor. It does not request account cookies, client profiles or private hiring information. Budget-range, hourly-rate-range, payment-verification and proposal-count URL filters require login and are rejected. Other supported public URL filters include job type, experience tier, workload, duration, location and category identifiers.
Public search exposes at most the first five thousand positions per query. New postings can shift page boundaries during collection. Duplicate identifiers are removed, but a posting can move past a boundary while pages are being fetched. Regular overlapping monitoring runs help cover that movement. A posting may also close after it was retrieved; open its original URL to check its current availability.
FAQ
Can I retrieve client contact information?
This actor exports public job postings. It does not provide structured client names, contacts, spending history or payment-verification fields. Descriptions retain the text published in the job search result.
Why are some hourly rates empty?
Some hourly jobs do not publish a rate range. Their salary fields are null. This means the rate is unspecified and does not mean the work is unpaid.
Can I supply an existing Upwork search URL?
Yes. Copy an HTTPS job search URL into search_urls. Supported public filters are preserved. Do not also supply search phrases, and remove filters that require an account login.
Why did a run return fewer jobs than requested?
The source may contain fewer matches, your publication window may exclude older postings, searches may overlap, or the free usage cap may apply. Check the search summaries and warnings for source limits or incomplete collection.
Do I need an Upwork account or API key?
No. The actor reads public job search results. You do not log in, and you do not need an Upwork API key.
How do I get only new jobs on every run?
Keep sort on recency, set posted_within_hours slightly longer than your schedule interval, and skip any job_id you already stored. The overlap makes sure no posting falls between two runs.
Can I use this as a replacement for the Upwork RSS feed?
Yes. Schedule the actor with your search phrases or search URL and send the dataset to a webhook or integration. Each row contains the job link, so the result works like a job feed you control.