# 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, client location, proposals, experience level. No login needed.

- **URL**: https://apify.com/thirdwatch/upwork-jobs-scraper.md
- **Developed by:** [Thirdwatch](https://apify.com/thirdwatch) (community)
- **Categories:** Jobs, Lead generation
- **Features:** Limited permissions
- **Stats:** 58 total users, 2 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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Upwork Scraper

> **Thirdwatch portfolio:** 8,800+ users across 140+ public Actors, 2M+ records delivered, >95% 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.

### 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.
- Very large parallel runs may slow down; moderate concurrency is more reliable.

### Compared to alternatives

- **vs. neatrat/upwork-scraper** (~$0.0035 per result, 2.9K users): Their scraper costs less per result. This Actor is the no-setup alternative — you get the same fields without supplying any account login or cookies.

### 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 1,000 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/fjHxa5nIQWexMMjRs/openapi.json
