# Upwork Scraper - Freelance Jobs, Budget & Skills (`thirdwatch/upwork-jobs-scraper`) Actor

Scrape Upwork freelance job listings: title, description, budget (fixed/hourly), required skills, client rating, client spend, proposals count, and posting date. World's largest freelance marketplace. No login needed.

- **URL**: https://apify.com/thirdwatch/upwork-jobs-scraper.md
- **Developed by:** [Thirdwatch](https://apify.com/thirdwatch) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 51 total users, 10 monthly users, 100.0% runs succeeded, 2 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Upwork Scraper

> **Thirdwatch portfolio:** 5K users across 88 public Actors, 2M+ records delivered, and >99% run success. [Explore all Thirdwatch Actors](https://apify.com/thirdwatch).

> Scrape Upwork freelance job listings — titles, descriptions, budgets, required skills, public client history, and proposal activity.

### What you get

Structured freelance job data from Upwork, the world's largest freelance marketplace. Search by keyword and get job titles, full descriptions, budgets (fixed or hourly), required skills, experience levels, plus the proposal range and client history that Upwork exposes publicly. No Upwork login needed.

### Output fields

| Field | Description |
|-------|-------------|
| `title` | Job title |
| `description` | Full job description |
| `budget_type` | `Fixed` or `Hourly` |
| `budget_min` | Minimum budget (fixed-price jobs) |
| `budget_max` | Maximum budget (fixed-price jobs) |
| `hourly_rate` | Hourly rate range (hourly jobs) |
| `skills` | Required skills / tags |
| `experience_level` | `Entry`, `Intermediate`, or `Expert` |
| `client_rating` | Client's overall rating on Upwork |
| `client_spend` | Client's total historical spend on Upwork |
| `client_location` | Client's city and country, when public |
| `client_hires` | Total number of hires by the client |
| `proposals_range` | Public proposal range bucket (e.g., "20 to 50") |
| `is_featured` | Whether the job is featured |
| `project_length` | Expected project duration |
| `posted_date` | When the job was posted |
| `country` | Client/job country |
| `client_member_since` | Date the client joined Upwork, when public detail enrichment is enabled |
| `client_total_hours` | Total client hours shown publicly, when available |
| `payment_verified` | Whether Upwork publicly marks the client's payment method verified |
| `url` | Upwork job URL |

### Example output

```json
{
    "title": "React Native Mobile App Developer",
    "description": "Looking for an experienced React Native developer to build a cross-platform marketplace app from scratch...",
    "budget_type": "Fixed",
    "budget_min": 5000,
    "budget_max": 10000,
    "skills": ["React Native", "JavaScript", "iOS", "Android"],
    "experience_level": "Expert",
    "client_rating": 4.8,
    "client_spend": "$150K total spent",
    "client_location": "Austin, United States",
    "client_hires": 28,
    "proposals_range": "20 to 50",
    "payment_verified": true,
    "project_length": "1 to 3 months",
    "posted_date": "2026-04-20",
    "url": "https://www.upwork.com/jobs/~01abcdef1234567890"
}
```

### Input parameters

| Parameter | Required | Description |
|-----------|----------|-------------|
| `queries` | Yes | Search queries (e.g., `["python developer", "react frontend"]`). Each query runs a separate Upwork search. |
| `maxResults` | No | Maximum total jobs to return across all queries. Upwork shows 10 jobs per page. Default `5`. |
| `includeJobDetails` | No | Default `true`. Enriches rows with public proposal and client history fields. Set to `false` for the fastest search-only run. |
| `proxyConfiguration` | No | Apify proxy settings. Leave default for best results. |

### Use cases

- **Freelancers**: Track new postings in your niche, compare budgets, and calibrate proposal pricing.
- **Agencies**: Monitor demand for specific skills and spot clients with large spend histories.
- **Market researchers**: Analyze freelance rates and project volumes by skill and region.
- **Recruiters**: Understand freelance compensation ranges when planning internal budgets.

### Pricing

Pay-per-result pricing. Tiered discounts apply automatically based on usage volume.

| Tier | Price per result |
|------|------------------|
| FREE | $0.008 |
| BRONZE | $0.006 |
| SILVER | $0.005 |
| GOLD | $0.004 |

### Limitations

- Upwork listings are time-sensitive and can close within hours of posting.
- Client and proposal fields reflect only what Upwork displays on the anonymous public job page; new or private clients may not show spend, hires, hours, rating, or payment status.
- Upwork does not expose the Connects required to anonymous visitors, so this no-login Actor does **not** return or estimate Connects. That value is visible only in Upwork's authenticated application flow and can change while a job is live.
- Budget ranges and proposal ranges are marketplace estimates, not final contract terms or exact applicant counts.
- Upwork has aggressive bot protection; very large parallel runs may slow down.

### Compared to alternatives

- **vs. neatrat/upwork-scraper** (~$0.0035 per result, 2.9K users): Their scraper is cheaper thanks to a cookie-pool trick. This actor is positioned as the reliable, no-setup alternative — you get the same fields without maintaining cookie pools, and it keeps working when their cookie pool gets burned.

Pairs well with [LinkedIn Profile Scraper](https://apify.com/thirdwatch/linkedin-profile-scraper?fpr=9m2cd6) for enriching client or freelancer research.

### FAQ

**Do I need an Upwork account?**
No. The actor only reads public search results.

**Can I filter by budget type or experience level?**
Not directly via input today — include terms in your `queries` (e.g., `"expert python developer"`) for keyword-level targeting.

**How many jobs can I pull per run?**
Up to 500 via `maxResults`. Bear in mind Upwork only returns 10 per page, so large runs walk through many pages.

**How fresh is the data?**
Pulled live at run time — as fresh as Upwork itself.

Last verified: 2026-07

More scrapers at [thirdwatch.dev](https://thirdwatch.dev).

# Actor input Schema

## `queries` (type: `array`):

Job search queries, e.g. 'python developer', 'react frontend'. Each query returns Upwork search results.

## `maxResults` (type: `integer`):

Maximum total jobs to return across all queries. Upwork shows 10 jobs per page.

## `includeJobDetails` (type: `boolean`):

Fetch each public job page to add proposal range, client location, spend, hires, hours, member-since date, rating, and payment verification when Upwork publishes them. Disable for the fastest search-only run.

## `proxyConfiguration` (type: `object`):

Proxy settings. Leave default for best results.

## Actor input object example

```json
{
  "queries": [
    "python developer"
  ],
  "maxResults": 5,
  "includeJobDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "queries": [
        "python developer"
    ],
    "maxResults": 5,
    "includeJobDetails": true,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("thirdwatch/upwork-jobs-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "queries": ["python developer"],
    "maxResults": 5,
    "includeJobDetails": True,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("thirdwatch/upwork-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "queries": [
    "python developer"
  ],
  "maxResults": 5,
  "includeJobDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call thirdwatch/upwork-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,thirdwatch/upwork-jobs-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/oRTET4hqgEpY9IU6p/builds/YY94mi5qIAcKu6wsc/openapi.json
