# Upwork Jobs Scraper: Up to 5,000 per Search (`luzivanlt/upwork-jobs-scraper`) Actor

Upwork job posts for any search and filters, up to 5,000 a search, no login. $0.50 per 1,000 jobs. Budget, rate, skills, level, dates.

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

## Pricing

from $0.35 / 1,000 jobs

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 Jobs Scraper: Up to 5,000 per Search

Get Upwork job posts for any search, up to 5,000 jobs a search, from every
client country, each with its full description, job type, budget or hourly
rate, experience level, project length, hours per week, skills and dates. One
row per job. No Upwork account or cookies needed.

Tested daily. Latest check: 4,049 of 4,049 jobs from two whole searches
("python" and "logo design"), every job Upwork counted for each, in 5 minutes.

### What does this Actor do?

You give it search terms and Upwork's filters, or links to Upwork job
searches. For each search it reads Upwork's results, 50 jobs at a time, and
saves one row per job until it reaches your limit, the search has no more
jobs, or Upwork's 5,000-job limit for one search.

Each job comes with:

- its title, Upwork link and full description
- whether it is hourly or fixed price, with the fixed budget or the hourly
  rate range when the client set one
- the experience level asked for, the project length and the hours per week
- its skills, by name and by Upwork's id
- when it was created, published and renewed
- where it ranked in the search, the search term, the search link and how
  many jobs Upwork counts for the search

### Why use it?

- **Every job a search lists, up to Upwork's 5,000.** Each row carries
  Upwork's own count for its search, and the run's status says whether every
  job was read.
- **Jobs from clients anywhere.** Upwork shows some visitors only jobs from
  their own country; this Actor reads the full list.
- **Upwork's filters, or a pasted link.** Job type, experience level, budget,
  hourly rate, client history, client location, project length, hours per
  week, contract-to-hire and category.
- **Use the data anywhere.** Download as JSON, CSV or Excel, or send it to
  your own tools through Apify's API and integrations.

### How to use it

1. Type one or more **Search terms**, or paste **Search links**, or both.
2. Optionally, pick filters: **Job type**, **Experience level**, a fixed
   price or hourly rate range, **Client history**, **Client locations**,
   **Project length**, **Hours per week**, **Contract-to-hire only**,
   **Categories**, **Sort by** and **Max jobs per search**.
3. Click **Start**. When the run ends, open the **Output** tab to view the
   jobs or download them.

Run it with no input to see a sample: up to 100 "python" jobs, newest first,
charged as usual.

#### Links that work

An Upwork job search, such as
`https://www.upwork.com/nx/search/jobs/?q=python&t=1&contractor_tier=3`. Its
search words, job type, experience level, budget, hourly rate, client
history, client location, time zone, project length, hours per week,
contract-to-hire, category, subcategory and sort are used. A link with a
filter Upwork keeps to signed-in members (number of proposals, payment
verified, previous clients, my location), or with a filter this Actor does
not read, is refused before anything is read, naming the link, as are other
Upwork pages and other sites.

### Input

| Field                                                           | What it does                                                                | Default  |
| --------------------------------------------------------------- | --------------------------------------------------------------------------- | -------- |
| **Search terms** (`searchTerms`)                                | Words to search job posts for, one search each                              | —        |
| **Job type** (`jobType`)                                        | `any`, `hourly` or `fixed`                                                  | `any`    |
| **Experience level** (`experienceLevel`)                        | `entry`, `intermediate`, `expert`                                           | all      |
| **Fixed price from / up to** (`fixedPriceMin`, `fixedPriceMax`) | A fixed-price budget range in US dollars; searches fixed-price jobs only    | —        |
| **Hourly rate from / up to** (`hourlyRateMin`, `hourlyRateMax`) | An hourly rate range in US dollars; searches hourly jobs only               | —        |
| **Client history** (`clientHires`)                              | `none`, `1-9`, `10+` freelancers hired before                               | all      |
| **Client locations** (`clientLocations`)                        | Countries or regions, as Upwork names them                                  | anywhere |
| **Project length** (`projectLength`)                            | `less-than-1-month`, `1-to-3-months`, `3-to-6-months`, `more-than-6-months` | any      |
| **Hours per week** (`hoursPerWeek`)                             | `less-than-30`, `more-than-30`                                              | any      |
| **Contract-to-hire only** (`contractToHire`)                    | Only jobs that may become a full-time hire                                  | off      |
| **Categories** (`categories`)                                   | Upwork's twelve categories, such as `Web, Mobile & Software Dev`            | all      |
| **Sort by** (`sortBy`)                                          | `newest`, `relevance`, `client_spend`, `client_rating`                      | `newest` |
| **Search links** (`startUrls`)                                  | Upwork job search links                                                     | —        |
| **Max jobs per search** (`maxJobsPerSearch`)                    | Stop each term or link after this many jobs, 1 to 5,000                     | `100`    |

Give at least one search term, a filter, or one link. The filters apply to
the search terms; with no search term and no link, the filters alone are one
search, of every job they match. A link keeps its own filters. A fixed price
and an hourly rate cannot be used together. Example input:

```json
{
  "searchTerms": ["react developer", "next.js"],
  "jobType": "hourly",
  "experienceLevel": ["intermediate", "expert"],
  "clientHires": ["1-9", "10+"],
  "hourlyRateMin": 30,
  "sortBy": "newest",
  "maxJobsPerSearch": 1000
}
```

### Output

One row per job. An example, with made-up values and the description cut:

```json
{
  "job_id": "2112181236302511171",
  "url": "https://www.upwork.com/jobs/~022112181236302511171",
  "title": "React developer for a booking dashboard",
  "description": "We need a React developer to build…",
  "job_type": "hourly",
  "fixed_budget": null,
  "hourly_rate_min": 30,
  "hourly_rate_max": 55,
  "experience_level": "intermediate",
  "duration": "1 to 3 months",
  "workload": "part_time",
  "skills": ["React", "TypeScript", "Next.js"],
  "skill_ids": ["1031626788584898560", "1031626796981895168", "1110580752293548032"],
  "created_at": "2026-10-19T13:57:04.268Z",
  "published_at": "2026-10-19T14:16:56.680Z",
  "renewed_at": null,
  "is_premium": false,
  "search_rank": 1,
  "search_query": "react developer",
  "search_url": "https://www.upwork.com/nx/search/jobs/?q=react%20developer&t=0&hourly_rate=30-&sort=recency",
  "search_total": 642
}
```

| Field              | What it holds                                                                                         |
| ------------------ | ----------------------------------------------------------------------------------------------------- |
| `job_id`           | Upwork's id for the job                                                                               |
| `url`              | The job's page on Upwork                                                                              |
| `title`            | The job's title                                                                                       |
| `description`      | The full description, as plain text                                                                   |
| `job_type`         | `hourly` or `fixed`                                                                                   |
| `fixed_budget`     | A fixed-price job's budget in US dollars, when the client set one                                     |
| `hourly_rate_min`  | An hourly job's lowest rate in US dollars, when the client set one                                    |
| `hourly_rate_max`  | Its highest rate                                                                                      |
| `experience_level` | `entry`, `intermediate` or `expert`                                                                   |
| `duration`         | The project length ("1 to 3 months")                                                                  |
| `workload`         | An hourly job's hours: `part_time` (less than 30 a week), `full_time` (more), `as_needed`, `not_sure` |
| `skills`           | The skills the job asks for                                                                           |
| `skill_ids`        | Upwork's ids for those skills                                                                         |
| `created_at`       | When the job was created                                                                              |
| `published_at`     | When it was published                                                                                 |
| `renewed_at`       | When it was last renewed, if ever                                                                     |
| `is_premium`       | `true` for a premium job post                                                                         |
| `search_rank`      | Where the job stood in the search, from 1                                                             |
| `search_query`     | The search term it was found under                                                                    |
| `search_url`       | The search on Upwork                                                                                  |
| `search_total`     | How many jobs Upwork counts for the search                                                            |

### How much does it cost?

No surcharges and no paid options; an item that fails is not charged.

You pay for what you get:

- **$0.50 per 1,000 jobs** ($0.0005 a job). Each job is charged once per run, even when two of your searches find it.
- No start fee, and nothing per search.

So 2,000 jobs cost $1. If you set a maximum cost for a run, the Actor stops when it reaches it and keeps every job saved so far.

### How long does a run take?

About 100 jobs in 20 seconds; 4,049 jobs from two searches in 5 minutes.

### Good to know

- **Upwork lists at most 5,000 jobs for one search.** For more, split it:
  one search per category, job type or experience level.
- **Newest first reads a search most completely.** Upwork's best-match order
  can move a job from one page to the next while a search is read; a job seen
  twice is saved once, and the run's status says when a search came up short
  of Upwork's count.
- **Client details are not included.** Upwork shows the client's country,
  spend, rating and payment status only to signed-in members, so this Actor
  does not fill them.
- **One job, one row.** A job found again in the same run, under the same or
  another search, is saved and charged once.
- **A search that cannot be read** is reported in the run's status; the other
  searches carry on. The run fails only when none could be read.
- **Running it daily?** Sort by newest, set a small limit, and remove repeats
  by `job_id`.

### More Actors from us

- [AliExpress Product Scraper: Search Results & Prices](https://apify.com/luzivanlt/aliexpress-products-scraper): Every product of an AliExpress search to its last page, with exact sold counts and ratings.
- [Amazon Product Scraper: Search Results & Prices](https://apify.com/luzivanlt/amazon-products-scraper): Every product on Amazon's search pages to the last page, sponsored marked, with monthly sales.
- [App Store Reviews Scraper: All Reviews, Not 500](https://apify.com/luzivanlt/app-store-reviews-scraper): Every written App Store review of an app, not just the newest 500.
- [Woolworths Coles ALDI Scraper: AU Grocery Prices](https://apify.com/luzivanlt/au-supermarkets-scraper): Woolworths, Coles and ALDI products for any search in one run, every results page to the end.
- [Bilibili Video Scraper: Search & Channel Videos](https://apify.com/luzivanlt/bilibili-videos-scraper): Bilibili videos from searches or whole channels, each with its full detail page's data.
- [Career Site Jobs Scraper: Workday, Greenhouse, Lever](https://apify.com/luzivanlt/career-site-jobs-scraper): Every job on Greenhouse, Lever, Ashby, SmartRecruiters and Workday boards, checked against each board's count.

### Use it from an AI agent or the API

One call starts a run and returns its items (Apify waits up to 300 seconds; for a
longer run, start it with `POST /v2/acts/…/runs` and read its dataset):

```text
POST https://api.apify.com/v2/acts/luzivanlt~upwork-jobs-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>
```

With the sample input as its JSON body:

```json
{
  "searchTerms": ["python"],
  "jobType": "any",
  "contractToHire": false,
  "sortBy": "newest",
  "maxJobsPerSearch": 100
}
```

Its inputs, in the order of the input form:

| Input                                     | What it takes                                                                                                                             | Default    |
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| `searchTerms` (Search terms)              | Words to search Upwork's job posts for, one search per term (e.g. "python" or "logo design").                                             | —          |
| `jobType` (Job type)                      | Hourly jobs, fixed-price jobs, or both, for the search terms above.                                                                       | `"any"`    |
| `experienceLevel` (Experience level)      | Only jobs asking for one of these experience levels, for the search terms above.                                                          | —          |
| `fixedPriceMin` (Fixed price from (USD))  | Only fixed-price jobs with a budget of at least this many US dollars, for the search terms above.                                         | —          |
| `fixedPriceMax` (Fixed price up to (USD)) | Only fixed-price jobs with a budget of at most this many US dollars, for the search terms above.                                          | —          |
| `hourlyRateMin` (Hourly rate from (USD))  | The low end of an hourly rate range in US dollars, for the search terms above: Upwork matches hourly jobs whose rate falls in the range.  | —          |
| `hourlyRateMax` (Hourly rate up to (USD)) | The high end of an hourly rate range in US dollars, for the search terms above: Upwork matches hourly jobs whose rate falls in the range. | —          |
| `clientHires` (Client history)            | Only jobs from clients who have hired this many freelancers on Upwork before, for the search terms above.                                 | —          |
| `clientLocations` (Client locations)      | Only jobs from clients in these countries or regions, named as Upwork names them, for the search terms above.                             | —          |
| `projectLength` (Project length)          | Only jobs the client expects to last this long, for the search terms above.                                                               | —          |
| `hoursPerWeek` (Hours per week)           | Only hourly jobs asking for this many hours a week, for the search terms above: less than 30, or more than 30.                            | —          |
| `contractToHire` (Contract-to-hire only)  | Only jobs the client may turn into a full-time hire after the contract, for the search terms above.                                       | `false`    |
| `categories` (Categories)                 | Only jobs in these Upwork categories, for the search terms above.                                                                         | —          |
| `sortBy` (Sort by)                        | The order the jobs are read in: newest first, Upwork's best match, the client's total spend, or the client's rating.                      | `"newest"` |
| `startUrls` (Search links)                | Links to Upwork job searches, e.g. https://www.upwork.com/nx/search/jobs/?q=python\&t=1\&contractor_tier=3.                                 | —          |
| `maxJobsPerSearch` (Max jobs per search)  | Stop each search term or link after this many jobs, from 1 to 5,000 (Upwork lists at most 5,000 jobs for one search).                     | `100`      |

Apify's MCP server, `https://mcp.apify.com`, lists it as `luzivanlt/upwork-jobs-scraper`. To give an
AI agent this Actor as a tool, add the server to the agent's MCP config:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=luzivanlt/upwork-jobs-scraper"
    }
  }
}
```

The client signs in with OAuth, or add `"headers": { "Authorization": "Bearer <APIFY_TOKEN>" }`.

Charged per job delivered; the sample input above costs at most $0.05.

### FAQ

**Do I need an Upwork account or cookies?**
No. The Actor reads what anyone can see on Upwork without signing in.

**Which filters need an account?**
Number of proposals, payment verified, previous clients and "my location"
are kept to signed-in members on Upwork, so they are not offered.

**Can I run it from my own code, on a schedule, or with other apps?**
Yes. Like any Apify Actor, you can start it through the Apify API, run it on a
schedule, and connect it to other apps with Apify's integrations and webhooks.

### Is it legal to scrape Upwork?

This Actor reads only public job posts. A job post can name a person or a
company; treat names and contact details in a description as personal data.
Check Upwork's terms and the laws that apply to you (such as the GDPR or the
CCPA) before you use the data. If you are unsure, ask a lawyer.

### Support

Found a problem or missing a feature? Open an issue on the **Issues** tab and
include the run's link.

***

This Actor is not affiliated with, endorsed by or sponsored by Upwork.

# Changelog

This Actor's version history is a separate document: https://apify.com/luzivanlt/upwork-jobs-scraper/changelog.md

# Actor input Schema

## `searchTerms` (type: `array`):

Words to search Upwork's job posts for, one search per term (e.g. "python" or "logo design"). Each term uses the filters below; paste Upwork links under Search links. Leave empty and pick filters to get every job they match. A job two searches both find is saved and charged once.

## `jobType` (type: `string`):

Hourly jobs, fixed-price jobs, or both, for the search terms above. A fixed price or hourly rate below picks its own job type. A search link keeps its own job type. Default: any. Example: fixed.

## `experienceLevel` (type: `array`):

Only jobs asking for one of these experience levels, for the search terms above. Pick one or more; leave empty for every level. A search link keeps its own level. Example: intermediate and expert.

## `fixedPriceMin` (type: `integer`):

Only fixed-price jobs with a budget of at least this many US dollars, for the search terms above. Setting it searches fixed-price jobs only, and cannot be combined with an hourly rate. Example: 100.

## `fixedPriceMax` (type: `integer`):

Only fixed-price jobs with a budget of at most this many US dollars, for the search terms above. Setting it searches fixed-price jobs only, and cannot be combined with an hourly rate. Example: 1000.

## `hourlyRateMin` (type: `integer`):

The low end of an hourly rate range in US dollars, for the search terms above: Upwork matches hourly jobs whose rate falls in the range. Setting it searches hourly jobs only. Example: 30.

## `hourlyRateMax` (type: `integer`):

The high end of an hourly rate range in US dollars, for the search terms above: Upwork matches hourly jobs whose rate falls in the range. Setting it searches hourly jobs only. Example: 80.

## `clientHires` (type: `array`):

Only jobs from clients who have hired this many freelancers on Upwork before, for the search terms above. Pick one or more; leave empty for every client. Example: 1 to 9 hires and 10+ hires.

## `clientLocations` (type: `array`):

Only jobs from clients in these countries or regions, named as Upwork names them, for the search terms above. Leave empty for clients anywhere. Example: "United States", "Europe" or "Australia and New Zealand".

## `projectLength` (type: `array`):

Only jobs the client expects to last this long, for the search terms above. Pick one or more; leave empty for any length. A search link keeps its own project length. Example: 3 to 6 months.

## `hoursPerWeek` (type: `array`):

Only hourly jobs asking for this many hours a week, for the search terms above: less than 30, or more than 30. Leave empty for any. A search link keeps its own choice. Example: more than 30.

## `contractToHire` (type: `boolean`):

Only jobs the client may turn into a full-time hire after the contract, for the search terms above. Leave off for every job. A search link keeps its own choice. Default: off.

## `categories` (type: `array`):

Only jobs in these Upwork categories, for the search terms above. Pick one or more of Upwork's twelve; leave empty for every category. For a subcategory, paste an Upwork search link. Example: Web, Mobile & Software Dev.

## `sortBy` (type: `string`):

The order the jobs are read in: newest first, Upwork's best match, the client's total spend, or the client's rating. With a limit, it decides which jobs you get. Newest first reads a search most completely, because the order does not shift between pages. A search link keeps its own sort. Default: newest. Example: client_spend.

## `startUrls` (type: `array`):

Links to Upwork job searches, e.g. https://www.upwork.com/nx/search/jobs/?q=python\&t=1\&contractor_tier=3. The link's search words, job type, experience level, budget, hourly rate, client history, client location, time zone, project length, hours per week, contract-to-hire, category, subcategory and sort are used. A link using a filter Upwork keeps to signed-in members (number of proposals, payment verified, previous clients, my location) or a filter this Actor does not read is refused, naming the link.

## `maxJobsPerSearch` (type: `integer`):

Stop each search term or link after this many jobs, from 1 to 5,000 (Upwork lists at most 5,000 jobs for one search). Default 100. Each job is charged once ($0.50 per 1,000 jobs), so this caps what one search costs: 1,000 jobs cost at most $0.50. Example: 1000.

## Actor input object example

```json
{
  "searchTerms": [
    "python"
  ],
  "jobType": "any",
  "contractToHire": false,
  "sortBy": "newest",
  "maxJobsPerSearch": 100
}
```

# Actor output Schema

## `jobs` (type: `string`):

Every job the run saved, one row per job.

## `allFields` (type: `string`):

The same rows with every field.

# 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 = {
    "searchTerms": [
        "python"
    ],
    "maxJobsPerSearch": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("luzivanlt/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 = {
    "searchTerms": ["python"],
    "maxJobsPerSearch": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("luzivanlt/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 '{
  "searchTerms": [
    "python"
  ],
  "maxJobsPerSearch": 100
}' |
apify call luzivanlt/upwork-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,luzivanlt/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/ZS65NFd7ksD7dyXnA/builds/DHMq9h0djq1yic6Tj/openapi.json
