Upwork Jobs Scraper - New Job Alerts, Budgets & Hourly Rates avatar

Upwork Jobs Scraper - New Job Alerts, Budgets & Hourly Rates

Pricing

from $1.50 / 1,000 job postings

Go to Apify Store
Upwork Jobs Scraper - New Job Alerts, Budgets & Hourly Rates

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

SR

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

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, ciphertext and url: stable identifiers and the link to the original posting
  • title and description: the full public text, with line breaks kept
  • job_type: fixed or hourly
  • budget for fixed projects, or salary_min / salary_max per hour for hourly contracts
  • experience_level, workload, duration and skills
  • posted_at, created_at and renewed_at in 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

  1. Open the actor and enter one or more search phrases, for example python or shopify developer, or paste an Upwork job search URL.
  2. Keep sort on recency to get the newest jobs first, and set max_items.
  3. Optionally set posted_within_hours to collect only jobs from the last hours.
  4. Start the run and download the dataset as JSON, CSV or Excel, or read it through the Apify API.
  5. 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

OptionWhat you getLimits
Upwork's own job alerts and saved searchesNotifications inside your accountNeeds a freelancer account, no export, no API access to the data
Upwork APIOfficial GraphQL accessRequires an approved API key and OAuth; aimed at apps working on behalf of a user
Browser extensionsAlerts while your browser is openRun on your own machine and account, no scheduled export
Writing your own scraperFull controlYou maintain parsing, paging and deduplication yourself
Other Upwork scrapers in the Apify StoreSimilar job dataPrices run from about $0.001 to $0.01 per job; field sets and client data differ
This actorClean job rows, fixed and hourly pay split into separate fields, deduplication, recency windowPublic, 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.