# Freelancer Profile Scraper (`maximedupre/freelancer-profile-scraper`) Actor

Search Contra, Upwork, or PeoplePerHour for public freelancer profiles by skill, role, or supported source URL. Save source links and available details, such as skills, location, rates, and earnings, in a dataset.

- **URL**: https://apify.com/maximedupre/freelancer-profile-scraper.md
- **Developed by:** [Maxime Dupré](https://apify.com/maximedupre) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 29.4% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.70 / 1,000 freelancer profiles

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

### 🧭 Build a public freelancer profile list

Recruiters, talent teams, and researchers can search Contra, Upwork, or PeoplePerHour by skill, role, or supported source URL. Each saved profile includes its marketplace link and the professional details that source makes public, so you can review skills, rates, and locations together in one dataset.

- Find profiles for graphic designers with **[Contra Graphic Designer Profiles](https://apify.com/maximedupre/freelancer-profile-scraper/examples/contra-graphic-designer-profiles)**.
- Search by rate with **[Upwork Freelancers by Hourly Rate](https://apify.com/maximedupre/freelancer-profile-scraper/examples/upwork-freelancers-by-hourly-rate)**.
- Use a badge filter with **[Upwork Top Rated Freelancers](https://apify.com/maximedupre/freelancer-profile-scraper/examples/upwork-top-rated-freelancers)**.
- Limit a run to one country with **[Upwork Freelancers in Canada](https://apify.com/maximedupre/freelancer-profile-scraper/examples/upwork-freelancers-in-canada)**.
- Start from a talent search link with **[Upwork Talent Search URL Scraper](https://apify.com/maximedupre/freelancer-profile-scraper/examples/upwork-talent-search-url-scraper)**.

#### 📦 Public profile data in one dataset

The Actor saves one row for each collected public freelancer profile. The `marketplace` field shows whether it came from Contra, Upwork, or PeoplePerHour. Each row has a source profile link. Other fields depend on the marketplace and what it makes public.

Contra rows can include skills, rates, portfolios, testimonials, follower counts, and linked social profiles. Upwork rows can include earnings, billed hours, job totals, badges, verification details, and agency information. PeoplePerHour rows can include rates, ratings, reviews, and completed-job totals. Optional fields may be missing when a source does not show them.

#### 🚀 Run one marketplace search

Choose one marketplace for each run. Add skills or roles, or provide URLs supported by that marketplace. All keywords in the same run use the same filters.

1. Choose Contra, Upwork, or PeoplePerHour.
2. Enter one or more skills or roles, or add supported source URLs.
3. Set filters that apply to the chosen marketplace.
4. Set a profile limit, run the Actor, and open the dataset from the output.

#### ⚙️ Input

**Input fields**

| Field | Type | What it does |
| --- | --- | --- |
| `marketplace` | String (select) | Choose Contra, Upwork, or PeoplePerHour. Contra is prefilled. Only the selected marketplace's options apply. |
| `specialization` | String | Set a Contra category or specialization, such as Graphic Designer. |
| `country` | String | Find Upwork freelancers in a country, such as Canada. |
| `region` | String | Find Upwork freelancers in a continent or supported sub-region, such as Europe. |
| `earnings` | String (select) | Filter Upwork profiles by public earnings in USD: confirmed $0, $1 to under $100, $100 to under $1,000, $1,000 to under $10,000, or $10,000 or more. Hidden or unknown amounts are not treated as zero. |
| `minBilledHours` | Integer | Set the minimum billed hours for Upwork profiles. |
| `minJobSuccess` | Integer | Set the minimum Upwork Job Success Score, from 0 to 100. |
| `talentBadge` | String (select) | Find Upwork profiles with Top Rated, Top Rated Plus, or Rising Talent status. |
| `minRating` | Number | Set the minimum PeoplePerHour rating, from 0 to 5 stars. |
| `keywords` | Array of strings | Enter skills or roles to search. All keywords use the same filters. “graphic designer” is prefilled. |
| `sourceUrls` | Array of URL objects | Add Contra directory, hire, category, or profile URLs, or Upwork talent search URLs. This field does not apply to PeoplePerHour. |
| `location` | String | Find Contra or PeoplePerHour freelancers in a city or region. It does not apply to Upwork. |
| `minHourlyRate` | Number | Set a minimum hourly rate in USD for Contra or Upwork. It does not apply to PeoplePerHour. |
| `maxHourlyRate` | Number | Set a maximum hourly rate in USD for Contra or Upwork. It does not apply to PeoplePerHour. |
| `maxItems` | Integer | Stop after saving this many profiles across the run. The field is prefilled with 8 and has a minimum of 1, with no schema maximum. Leave it empty to return all available results until the source is exhausted. |

**Example input**

This example matches the public input from a successful hosted run with the prefilled marketplace, keyword, and profile limit.

```json
{
  "marketplace": "contra",
  "keywords": [
    "graphic designer"
  ],
  "maxItems": 8
}
```

#### 🧾 Output

The run output has a `profiles` link that opens the default dataset view. Each dataset row is a flat profile object. Its fields depend on the marketplace and the public details available for that profile.

**Run output**

| Field | Type | What it does |
| --- | --- | --- |
| `profiles` | String (link) | Opens the collected freelancer profiles in the default dataset view. |

**Dataset profile fields**

| Field | Type | What it does |
| --- | --- | --- |
| `marketplace` | String | Marketplace name: `contra`, `upwork`, or `peopleperhour`. |
| `profileUrl` | String (URL) | Link to the public freelancer profile. This field is required. |
| `name` | String | Name shown on the profile. |
| `username` | String | Public marketplace username. |
| `profileId` | String | Source profile ID for matching records from the same marketplace. |
| `headline` | String | Professional headline shown by the source. |
| `biography` | String | Biography shown by the source. |
| `timezone` | String | Timezone listed by Upwork. |
| `photoUrl` | String (URL) | Link to the profile photo. |
| `websiteUrl` | String (URL) | Personal website linked on Contra. |
| `introVideoUrl` | String (URL) | Introduction video linked on Upwork. |
| `skills` | Array of strings | Skills listed on the profile. |
| `hourlyRate` | Object | Hourly rate reported by the source. A fixed rate uses an amount and currency. A range uses text. |
| `hourlyRate.amount` | Number | Fixed hourly amount reported by the source. |
| `hourlyRate.currency` | String | Currency for the hourly rate. |
| `hourlyRate.text` | String | Rate range shown by the source, including its currency and hourly unit. |
| `location` | Object | Location shared on the profile. |
| `location.text` | String | Location label shown by the source. |
| `location.city` | String | City shown by the source. |
| `location.region` | String | State or region shown by the source. |
| `location.country` | String | Country shown by the source. |
| `earnings` | Object | Public Upwork earnings. A missing amount is unknown, not zero. |
| `earnings.amount` | Number | Reported earnings amount. Zero means the source confirms zero earnings. |
| `earnings.currency` | String | Currency for the reported earnings. |
| `earnings.text` | String | Earnings label shown by the source, including a range or lower bound. |
| `jobCount` | Integer | Job total reported by the marketplace. |
| `completedJobCount` | Integer | Completed-job total reported by PeoplePerHour. |
| `reviewCount` | Integer | Review total reported by the marketplace. |
| `followerCount` | Integer | Follower total reported by Contra. |
| `billedHours` | Number | Billed hours reported by Upwork. |
| `jobSuccessScore` | Number | Upwork Job Success Score as a percent. |
| `rating` | Number | PeoplePerHour star rating, out of 5. |
| `badges` | Array of strings | Professional or talent badges shown by the marketplace. |
| `isVetted` | Boolean | Whether Upwork reports that the freelancer is vetted. |
| `isPhoneVerified` | Boolean | Whether Upwork reports that the phone is verified. |
| `isOpenToWork` | Boolean | Whether the source reports that the freelancer is open to work. |
| `portfolioProjects` | Array of objects | Portfolio projects shared on Contra. |
| `portfolioProjects[].title` | String | Portfolio project title. |
| `portfolioProjects[].url` | String (URL) | Link to the source project page. |
| `portfolioProjects[].description` | String | Portfolio project description. |
| `portfolioProjects[].imageUrl` | String (URL) | Link to the project image. |
| `socialLinks` | Array of objects | Public social profiles linked on Contra. |
| `socialLinks[].platform` | String | Social platform named by the source. |
| `socialLinks[].url` | String (URL) | Link to the social profile. |
| `testimonials` | Array of objects | Public testimonials and review text shared on Contra. |
| `testimonials[].text` | String | Testimonial or review text. |
| `testimonials[].authorName` | String | Name of the testimonial author when shown. |
| `agencies` | Array of objects | Agency affiliations shown by Upwork. |
| `agencies[].id` | String | Source agency ID. |
| `agencies[].name` | String | Agency name. |
| `agencies[].url` | String (URL) | Link to the public agency page. |
| `agencies[].description` | String | Agency description shown by Upwork. |
| `agencies[].logoUrl` | String (URL) | Link to the source agency logo. |
| `portfolioCount` | Integer | Contra portfolio project total. It may include projects not listed in the row. |
| `testimonialCount` | Integer | Contra testimonial total. It may include testimonials not listed in the row. |
| `hourlyJobCount` | Integer | Hourly-job total reported by Upwork. |
| `fixedPriceJobCount` | Integer | Fixed-price job total reported by Upwork. |

All profile fields except `marketplace` and `profileUrl` are optional. The rows below come from successful runs on the current beta build. The Contra and Upwork examples are shortened; `"..."` marks omitted data.

**Contra profile row, shortened**

```json
{
  "marketplace": "contra",
  "profileId": "WyJVc2VyUHJvZmlsZSIsMzUyODgyNDdd",
  "profileUrl": "https://contra.com/onyourtiptoes",
  "name": "Cara Ellis",
  "headline": "Designing for connection ⋆˚꩜｡ ",
  "biography": "...",
  "location": {
    "text": "London, UK"
  },
  "skills": [
    "Brand Designer",
    "Logo Designer",
    "Digital illustrator"
  ],
  "hourlyRate": {
    "text": "$100 - $150/hr"
  },
  "followerCount": 1712,
  "isOpenToWork": true,
  "reviewCount": 25,
  "portfolioCount": 24,
  "portfolioProjects": [
    {
      "title": "Guerilla Marketing Shirt Artworks and Design for Conduct AI",
      "url": "https://contra.com/p/LAmsBcOl-guerilla-marketing-shirt-artworks-and-design-for-conduct-ai",
      "description": "...",
      "imageUrl": "..."
    }
  ],
  "socialLinks": "...",
  "testimonials": "...",
  "testimonialCount": 21
}
```

**Upwork profile row, shortened**

```json
{
  "marketplace": "upwork",
  "profileId": "~01f7f788f7fcd6abae",
  "profileUrl": "https://upwork.com/freelancers/dmytro1serebrych1udata",
  "name": "Dmytro S.",
  "headline": "Python Full stack developer | Python Web Scraping Automation AI LLM",
  "biography": "...",
  "timezone": "UTC+02:00 Israel",
  "location": {
    "city": "Kyiv",
    "region": "KYIV CITY",
    "country": "Ukraine"
  },
  "hourlyRate": {
    "amount": 30,
    "currency": "USD"
  },
  "skills": [
    "Python",
    "Python Script",
    "Django",
    "Flask",
    "..."
  ],
  "billedHours": 3349,
  "hourlyJobCount": 28,
  "fixedPriceJobCount": 17,
  "jobCount": 1,
  "earnings": {
    "amount": 142231.66,
    "currency": "USD",
    "text": "$100K+ earned"
  },
  "jobSuccessScore": 100,
  "badges": [
    "Top Rated Plus",
    "Available now"
  ],
  "isPhoneVerified": true,
  "agencies": [
    {
      "id": "~01a9ca7867c57aca25",
      "name": "UData",
      "logoUrl": "...",
      "url": "https://www.upwork.com/agencies/1727373285633892352/",
      "description": "..."
    }
  ],
  "isVetted": false
}
```

**PeoplePerHour profile row**

This complete row is unchanged except for whitespace from a successful current beta run.

```json
{
  "marketplace": "peopleperhour",
  "profileId": "3653562",
  "profileUrl": "https://www.peopleperhour.com/freelancer/technology-programming/george-ogden-software-developer-problem-solver-xwqxqwy",
  "name": "George O.",
  "photoUrl": "https://dw3i9sxi97owk.cloudfront.net/uploads/thumbs/3ae49abfe1115138b12d2dac6da93816_150x150.jpg",
  "skills": [
    "Amazon web services",
    "Linux",
    "Git",
    "C++ programming language",
    "Julia programming language",
    "Problem solving",
    "Python programming language",
    "Rust programming language",
    "Simulation software",
    "Software development"
  ],
  "location": {
    "country": "United Kingdom",
    "city": "Croydon"
  },
  "headline": "Software Developer/Problem Solver",
  "rating": 5,
  "reviewCount": 114,
  "completedJobCount": 98,
  "hourlyRate": {
    "amount": 67.10644712701436,
    "currency": "USD"
  }
}
```

#### 💳 Pricing

This Actor uses pay-per-event pricing. A charged primary event represents one public freelancer profile successfully collected and delivered to the dataset. The event price is $0.0027 per profile.

#### 🔌 Integrations

Open the `profiles` output link to view the dataset on Apify. For an Apify walkthrough, watch:

https://www.youtube.com/watch?v=bNACk1_S_6w\&list=PLObrtcm1Kw6MUrlLNDbK9QRg8VDJg0gOW\&index=4

#### ❓ FAQ

##### Can one run search more than one marketplace?

No. Choose Contra, Upwork, or PeoplePerHour for each run. All keywords in that run use the same filters.

##### What happens if Maximum profiles is empty?

Leave it empty to return all available results until the source is exhausted. The Actor stops when the source has no more available results.

##### Can I search Fiverr or GitHub?

No. This Actor searches Contra, Upwork, and PeoplePerHour.

##### Why are some profile fields missing?

Each marketplace shows different fields, and some details are optional. The Actor includes optional values only when they are available. Hidden or unknown Upwork earnings are not treated as zero.

##### Which source URLs can I use?

For Contra, you can add directory, hire, category, or profile URLs. For Upwork, add a talent search URL. PeoplePerHour does not use the Source URLs field.

### 📝 Changelog

**v0.0** (08-10-2026)

- Initial release.

### 🆘 Support

For issues, questions, or feature requests, [file a ticket](https://console.apify.com/actors/maximedupre~freelancer-profile-scraper/issues) and I'll fix or implement it in less than 24h 🫡

### 🔗 Related Actors

- [Freelancer Scraper](https://apify.com/maximedupre/freelancer-scraper) collects public Freelancer.com projects and freelancer profiles for a different marketplace.
- [Contra Freelancer Scraper - Profiles, Skills & Portfolio Data](https://apify.com/heliostech/contra-freelancer-scraper) focuses on Contra profiles, skills, rates, and portfolio details.
- [Upwork Freelancers Scraper - Hourly Rate & Earnings](https://apify.com/parseforge/upwork-freelancers-scraper) focuses on Upwork profiles with earnings and hourly rates.
- [PeoplePerHour Freelancers Scraper](https://apify.com/parseforge/peopleperhour-freelancers-scraper) adds profiles from the PeoplePerHour marketplace with ratings and completed-job totals.
- [Freelancermap Profile Scraper](https://apify.com/alkausari_mujahid/freelancermap-profile-scraper) extends profile searches to freelancermap.de.

**Made with ❤️ by Maxime Dupré**

# Actor input Schema

## `marketplace` (type: `string`):

Choose the marketplace to search. Only its own options apply.

## `specialization` (type: `string`):

Enter a Contra specialization, such as Graphic Designer.

## `country` (type: `string`):

Find Upwork freelancers in this country. Enter a country name, such as Canada.

## `region` (type: `string`):

Find Upwork freelancers in this region, such as Europe or Eastern Europe.

## `earnings` (type: `string`):

Filter by publicly reported total Upwork earnings in USD. Hidden or unknown earnings do not count as zero.

## `minBilledHours` (type: `integer`):

Find Upwork freelancers with at least this many billed hours.

## `minJobSuccess` (type: `integer`):

Find Upwork freelancers with a Job Success Score at or above this percent.

## `talentBadge` (type: `string`):

Find Upwork freelancers with the selected badge.

## `minRating` (type: `number`):

Find PeoplePerHour freelancers with a rating at or above this value, out of 5 stars.

## `keywords` (type: `array`):

Enter one or more skills or roles. All keywords use the same filters on the chosen marketplace.

## `sourceUrls` (type: `array`):

For Contra, enter directory, hire, category, or profile URLs. For Upwork, enter talent search URLs; their supported public search criteria apply. This field does not apply to PeoplePerHour.

## `location` (type: `string`):

Find Contra or PeoplePerHour freelancers in this city or region. This field does not apply to Upwork.

## `minHourlyRate` (type: `number`):

Find Contra or Upwork freelancers charging at least this amount per hour in USD. This field does not apply to PeoplePerHour.

## `maxHourlyRate` (type: `number`):

Find Contra or Upwork freelancers charging at most this amount per hour in USD. This field does not apply to PeoplePerHour.

## `maxItems` (type: `integer`):

Stop after saving this many profiles across the run. Leave empty to return all available results until the source is exhausted.

## Actor input object example

```json
{
  "marketplace": "contra",
  "keywords": [
    "graphic designer"
  ],
  "maxItems": 8
}
```

# Actor output Schema

## `profiles` (type: `string`):

View the collected freelancer profiles.

# 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 = {
    "marketplace": "contra",
    "keywords": [
        "graphic designer"
    ],
    "maxItems": 8
};

// Run the Actor and wait for it to finish
const run = await client.actor("maximedupre/freelancer-profile-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 = {
    "marketplace": "contra",
    "keywords": ["graphic designer"],
    "maxItems": 8,
}

# Run the Actor and wait for it to finish
run = client.actor("maximedupre/freelancer-profile-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 '{
  "marketplace": "contra",
  "keywords": [
    "graphic designer"
  ],
  "maxItems": 8
}' |
apify call maximedupre/freelancer-profile-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maximedupre/freelancer-profile-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/UMmEVgm6Z3A2uLaz9/builds/9J9gSG6PdhaVMWxrP/openapi.json
