# Upwork Rate & Market Intelligence — Freelance Skill Rates (`bovi/upwork-market-intelligence`) Actor

Benchmark any freelance skill on Upwork: live demand (open jobs), hourly & fixed rate distribution (median, p25, p75), hourly-vs-fixed split, experience-tier mix, posting freshness and adjacent skills. One clean row per skill.

- **URL**: https://apify.com/bovi/upwork-market-intelligence.md
- **Developed by:** [Vitalii Bondarev](https://apify.com/bovi) (community)
- **Categories:** Jobs, Business, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $475.30 / 1,000 skill benchmarks

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 Rate & Market Intelligence

**Stop guessing what a freelance skill is worth.** Give this Actor a list of skills and it
returns one clean **benchmark row per skill** — live demand, the real rate distribution
(median, 25th and 75th percentile, full range), the hourly-vs-fixed split, the experience
level clients are actually hiring, how fresh the market is, typical engagement length, and
the skills each one is hired alongside.

It is built for people who need to *price and position*, not scroll job feeds: freelancers
setting their rate, agencies scoping a new service line, recruiters and talent teams
benchmarking contractor cost, analysts tracking the freelance economy, and AI agents that
need structured labor-market data on demand.

---

### What you get — one row per skill

Each skill you pass in produces a single, decision-ready record. No raw-posting dump to
clean up yourself — the Actor samples the live market and does the statistics for you.

| Field | What it tells you |
|---|---|
| `skill` | The skill / keyword you benchmarked |
| `demand_open_jobs` | **Live demand** — the total number of open jobs for this skill right now |
| `sample_size` | How many recent postings were sampled for the rate stats |
| `hourly_median_usd` / `fixed_median_usd` | Headline median rates, ready for a table |
| `hourly_rate_usd` | Full hourly distribution: `median`, `p25`, `p75`, `min`, `max`, `mean`, `count` |
| `hourly_min_usd` / `hourly_max_usd` | Distribution of the posted hourly band edges |
| `fixed_budget_usd` | Full fixed-price budget distribution (same stats) |
| `job_type_split` | Hourly vs fixed counts and shares — how this skill is usually contracted |
| `experience_mix` | Entry / intermediate / expert counts + `expert_share` (how senior the demand is) |
| `freshness` | Postings in the last 24h / 7d / 30d, newest/oldest age, and an estimated posts-per-day velocity |
| `engagement_weeks` | Typical project length distribution where stated |
| `adjacent_skills` | The skills most often requested **alongside** this one (with counts and shares) |
| `scraped_at` | ISO timestamp of the run |

#### Why the percentiles matter

A single "average rate" hides the market. The **p25–p75 band** tells you where the bulk of
real jobs sit, so a freelancer knows whether their rate is competitive or leaving money on
the table, and an agency knows what a project will actually cost to staff. The
`expert_share` and `experience_mix` tell you *who* the demand is for — a skill that's 70%
expert-level pays very differently from one that's mostly entry-level work.

#### Why the adjacency map matters

`adjacent_skills` is the quiet superpower: it shows what each skill is bundled with in real
postings. If you sell "React" and the market keeps pairing it with "TypeScript" and "Next.js",
that's your upsell and your positioning, straight from demand data.

---

### Input

```json
{
  "skills": ["python developer", "react", "copywriting"],
  "sampleSize": 100,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "US" }
}
````

| Input | Type | Default | Description |
|---|---|---|---|
| `skills` | array of strings | — | One or more skills/keywords to benchmark. Each runs independently and yields one row. |
| `sampleSize` | integer | `100` | Recent postings sampled per skill for the rate stats (10–500). Demand counts are always the full market total. |
| `proxyConfiguration` | object | RESIDENTIAL / US | Apify proxy used to reach the target. Billed to the run owner. |

**Tip:** start with a handful of skills and `sampleSize` 100 for a fast, cheap read. Bump
`sampleSize` toward 300–500 when you want tighter, more stable percentiles on a high-volume
skill.

***

### Example output (abridged)

```json
{
  "skill": "python developer",
  "demand_open_jobs": 1880,
  "sample_size": 100,
  "hourly_median_usd": 38.0,
  "fixed_median_usd": 750.0,
  "expert_share": 0.41,
  "hourly_rate_usd": { "median": 38.0, "p25": 25.0, "p75": 60.0, "min": 12.0, "max": 150.0, "count": 63 },
  "job_type_split": { "hourly": 63, "fixed": 37, "hourly_share": 0.63, "fixed_share": 0.37 },
  "experience_mix": { "entry": 18, "intermediate": 41, "expert": 41, "expert_share": 0.41 },
  "freshness": { "posted_24h": 22, "posted_7d": 71, "est_posts_per_day": 9.4 },
  "adjacent_skills": [ { "skill": "Django", "count": 31, "share": 0.31 }, { "skill": "AWS", "count": 24, "share": 0.24 } ]
}
```

***

### How it works

The Actor reaches Upwork's public job search through the site's own visitor API. Upwork is
a protected target — it requires a residential proxy for reliable access — so the Actor
routes every request through the Apify **RESIDENTIAL** proxy on a sticky session, obtains a
short-lived visitor token the same way the public site does, and then queries the public
job-search endpoint for each skill. It samples the most recent postings (so the freshness
and velocity numbers reflect the live market), computes the distributions, and writes one
row per skill.

Only **public job-posting data** is collected — titles, descriptions, skills, budgets,
experience tier, post time and the search-wide demand count. No client-account or applicant
data is requested.

***

### Pricing

This Actor is **pay-per-result**: you are charged per skill successfully benchmarked. A skill
that returns no live postings is not charged. Apify platform/proxy usage during the run is
billed to your own account by Apify, as with any Actor.

***

### Common uses

- **Set your freelance rate** against the real p25–p75 band for your skill.
- **Scope an agency service line** — see demand, senior-share and typical project budget before you staff it.
- **Benchmark contractor cost** for a hiring or finance team.
- **Track the freelance economy** — run the same skill list on a schedule and watch demand and rates move.
- **Feed an AI agent** structured, on-demand labor-market data via the Apify API or MCP.

***

### FAQ

**Does this need my Upwork login?** No. It uses only the public job search; you never provide
credentials.

**Why a residential proxy?** The target requires it for reliable access. It's the default and
billed to your run.

**Can I benchmark non-tech skills?** Yes — pass any skill or keyword (`copywriting`,
`video editing`, `bookkeeping`, `voice over`, …). The same benchmark is computed for all.

**How fresh is the data?** Every run is live. The `freshness` block tells you exactly how
recent the sampled postings are.

# Actor input Schema

## `skills` (type: `array`):

One or more skills or keywords to benchmark on Upwork. Each returns ONE benchmark row: live demand, hourly & fixed rate distribution, hourly-vs-fixed split, experience-tier mix, posting freshness, typical engagement length and the adjacent-skill map. Examples: "python developer", "react", "shopify", "copywriting", "video editing".

## `sampleSize` (type: `integer`):

How many recent postings to sample per skill when computing the rate distribution. Larger = more stable percentiles, slightly slower. The demand (open-job count) is always the full market total regardless of this. Range 10–500.

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

Apify proxy used to reach the target. Defaults to the Apify RESIDENTIAL group (US) for reliable access. Billed to the run owner.

## Actor input object example

```json
{
  "skills": [
    "python developer",
    "react",
    "copywriting"
  ],
  "sampleSize": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

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

Dataset of skill benchmark rows (skill, demand\_open\_jobs, hourly\_rate\_usd, fixed\_budget\_usd, job\_type\_split, experience\_mix, freshness, engagement\_weeks, adjacent\_skills).

# 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 = {
    "skills": [
        "python developer",
        "react",
        "copywriting"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("bovi/upwork-market-intelligence").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 = { "skills": [
        "python developer",
        "react",
        "copywriting",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("bovi/upwork-market-intelligence").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "skills": [
    "python developer",
    "react",
    "copywriting"
  ]
}' |
apify call bovi/upwork-market-intelligence --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=bovi/upwork-market-intelligence",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Upwork Rate & Market Intelligence — Freelance Skill Rates",
        "description": "Benchmark any freelance skill on Upwork: live demand (open jobs), hourly & fixed rate distribution (median, p25, p75), hourly-vs-fixed split, experience-tier mix, posting freshness and adjacent skills. One clean row per skill.",
        "version": "0.1",
        "x-build-id": "En6fZLxqfXWvUdWFM"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/bovi~upwork-market-intelligence/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-bovi-upwork-market-intelligence",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/bovi~upwork-market-intelligence/runs": {
            "post": {
                "operationId": "runs-sync-bovi-upwork-market-intelligence",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/bovi~upwork-market-intelligence/run-sync": {
            "post": {
                "operationId": "run-sync-bovi-upwork-market-intelligence",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "skills": {
                        "title": "Skills / keywords to benchmark",
                        "type": "array",
                        "description": "One or more skills or keywords to benchmark on Upwork. Each returns ONE benchmark row: live demand, hourly & fixed rate distribution, hourly-vs-fixed split, experience-tier mix, posting freshness, typical engagement length and the adjacent-skill map. Examples: \"python developer\", \"react\", \"shopify\", \"copywriting\", \"video editing\".",
                        "items": {
                            "type": "string"
                        }
                    },
                    "sampleSize": {
                        "title": "Sample size per skill",
                        "minimum": 10,
                        "maximum": 500,
                        "type": "integer",
                        "description": "How many recent postings to sample per skill when computing the rate distribution. Larger = more stable percentiles, slightly slower. The demand (open-job count) is always the full market total regardless of this. Range 10–500.",
                        "default": 100
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Apify proxy used to reach the target. Defaults to the Apify RESIDENTIAL group (US) for reliable access. Billed to the run owner.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ],
                            "apifyProxyCountry": "US"
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
