# Freelancer.com Projects Scraper (`devilscrapes/freelancer-com-projects-scraper`) Actor

Scrape Freelancer.com project listings by skill/category — title, full description, skill tags, average bid, bid count, days left, and URL. Structured JSON/CSV output for freelance-market research, competitor pricing benchmarks, and lead-gen tooling. No login required. Freelance job and gig data.

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

## Pricing

Pay per event

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

<p align="center">
  <img src=".actor/icon.svg" width="160" alt="Freelancer.com Projects Scraper" />
</p>

## Freelancer.com Projects Scraper

**$4.20 / 1 000 results** ($0.20 per run + $0.004 / result) — pay only for results, no credit card to try.

Pull structured project rows straight off Freelancer.com's public project-search
pages, by skill or category — no login, no browser, no API key. We do the
dirty work so your dataset stays clean.

### 🔥 What this scrapes

Freelancer.com's `/jobs/<skill>` search pages list open projects for a given
skill or category — title, full description, skill tags, the current average
bid, bid count, and days left to bid. This Actor turns that into typed,
Pydantic-validated dataset rows you can export straight to JSON or CSV.

### ✨ Features

- 🎯 **Search by any skill or category** — `python`, `react`, `wordpress`,
  `logo-design`, anything that maps to `freelancer.com/jobs/<skill>`.
- 📄 **Multi-page, per-skill** — set how many pages to fetch per skill; server-side
  pagination confirmed live (`/jobs/<skill>/2` returns a fresh page of projects).
- 🧊 **Clean, typed rows** — Pydantic-validated, ISO-8601 timestamps, stable field names.
- 🛡️ **We rotate browser fingerprints** (curl-cffi impersonation — Chrome / Firefox /
  Safari) so the target sees real-browser TLS, not Python.
- 🔁 **We retry with exponential backoff** on `408 / 429 / 503 / 504` and honour
  `Retry-After`. Up to 5 attempts per page.
- 🌐 **Datacenter proxy pinned to a country** — Freelancer.com localises currency by
  exit IP, so we pin the exit and flag any row whose currency doesn't match.
- 🧱 **Per-skill fault isolation** — one bad or blocked skill never stops the others.
  A skill the site doesn't recognise finishes as a clean zero-row result, not a crash.
- 💰 **You pay only for results that land.** No data → no charge (only the small
  `actor-start` warm-up fee).

### 🎯 Use cases

- **Freelance-market researchers** benchmarking demand and pricing across skills.
- **Agencies** tracking what competitors are bidding on and for how much.
- **Lead-gen tooling** that needs active Freelancer.com project data at volume.
- **Rate-setting** — see what real clients are currently paying for a skill before
  you quote your own.

### ⚙️ How to use it

1. Click **Try for free** (or **Run**) on the Actor page.
2. Enter one or more `skills` — the path segment from
   `freelancer.com/jobs/<skill>`, e.g. `python`, `react`, `wordpress`.
3. Set `maxPagesPerSkill` (default 3) and, optionally, `countryCode` (default `US`).
4. Run it. Results stream to the dataset as they're scraped — export JSON or CSV
   when it finishes, or read incrementally via the API.

### 📥 Input

| Field              | Type    | Default | Description                                                                 |
|--------------------|---------|---------|-------------------------------------------------------------------------------|
| `skills`           | array   | —       | **Required.** One or more skill/category path segments.                     |
| `maxPagesPerSkill`  | integer | `3`     | Pages to fetch per skill (1-20).                                             |
| `countryCode`       | string  | `US`    | 2-letter ISO code pinning the datacenter proxy exit country.                 |
| `maxRuntimeSecs`     | integer | `300`   | Wall-clock deadline; the Actor stops requesting new pages once spent.        |
| `proxyConfiguration` | object  | Datacenter, pinned `US` | Apify Proxy spec. Datacenter is deliberate — see Limitations.  |

```json
{
  "skills": ["python", "react", "wordpress"],
  "maxPagesPerSkill": 2,
  "countryCode": "US",
  "maxRuntimeSecs": 180,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [],
    "apifyProxyCountry": "US"
  }
}
```

### 📤 Output

One dataset row per project:

```json
{
  "projectUrl": "https://www.freelancer.com/projects/data-analysis/binance-usdt-transaction-analysis",
  "projectPath": "/projects/data-analysis/binance-usdt-transaction-analysis",
  "title": "Binance USDT Transaction Analysis",
  "description": "I need a clear, data-driven picture of every USDT move in my Binance account...",
  "skills": ["API Integration", "Data Analysis", "Data Visualization", "MySQL", "Pandas", "Python"],
  "budgetType": "fixed",
  "averageBidAmount": 128,
  "currencySymbol": "$",
  "currencyLikelyUsd": true,
  "bidCount": 71,
  "daysLeft": 6,
  "paymentVerified": true,
  "featured": false,
  "sourceSkill": "python",
  "sourcePage": 1,
  "scrapedAt": "2026-09-16T12:00:00Z"
}
```

### 💰 Pricing

Pay-per-event, no subscription:

| Event            | Price       |
|-------------------|-------------|
| Actor start        | $0.20 / run |
| Project result      | $0.004 / row |

For a typical run that returns 1,000 rows, that's **$4.20 total** ($0.20 start

- 1,000 x $0.004). A run that finds nothing (a skill the site has no matching
  projects for) only bills the `actor-start` fee — never a silent full-price
  charge for zero data.

### 🚧 Limitations

- **`averageBidAmount` is the current average bid shown on the search card —
  not the poster's original min/max budget range.** Freelancer.com's public
  search-results page only exposes the average bid; the min/max range the
  poster originally set lives behind a much heavier per-project detail page
  (an embedded Angular state blob), which this Actor does not fetch. If you
  need the exact posted range, treat `averageBidAmount` as a market-rate
  signal, not the listing price.
- **No absolute posting date.** The listing page shows "days left to bid," not
  a timestamp of when the project was posted — `daysLeft` is what we can give you.
- **Currency follows the proxy exit.** We pin `countryCode` (default `US`) and
  a US-based fetch renders `$`-prefixed USD amounts. Every row also carries
  `currencyLikelyUsd` — if it's ever `false` on a `US`-pinned run, the exit
  served an unexpected currency symbol; filter those rows out before trusting
  the amount.
- **A skill Freelancer.com doesn't recognise** returns a generic "Top Jobs"
  fallback listing, not an error — this Actor detects that fallback and skips
  it (zero rows for that skill, noted in the run's status message) rather than
  mislabeling unrelated projects under your requested skill.

### ❓ FAQ

**Does this need a Freelancer.com account?**
No — the project-search pages are public.

**Why datacenter proxy instead of residential?**
Freelancer.com's search pages returned clean 200s with no anti-bot challenge
during testing — datacenter is the cheapest tier that clears reach, so that's
what we use by default.

**Can I search a phrase instead of a single skill?**
Use the skill/category path segment as it appears in a Freelancer.com URL,
e.g. `logo-design` for `freelancer.com/jobs/logo-design`. Multi-word phrases
that aren't a real skill slug fall into the "not recognised" case above.

**What happens if a page is blocked?**
We retry with backoff and rotate the proxy session on a 403. If every
attempted page for the whole run comes back with no recognisable data at all,
the run fails loudly instead of silently returning an empty dataset.

### 💬 Your feedback

Found a bug, a layout change, or want a field we don't scrape yet? Open an
issue on the Actor's Apify Store page or reach out through
[apify.com/DevilScrapes](https://apify.com/DevilScrapes) — we read every report.

# Changelog

This Actor's version history is a separate document: https://apify.com/devilscrapes/freelancer-com-projects-scraper/changelog.md

# Actor input Schema

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

One or more Freelancer.com skill/category path segments, e.g. <code>python</code>, <code>react</code>, <code>wordpress</code>. Each maps to <code>freelancer.com/jobs/\<skill></code> and is scraped independently, up to <code>maxPagesPerSkill</code> pages.

## `maxPagesPerSkill` (type: `integer`):

Pages to fetch per skill via /jobs/\<skill>/\<page> (confirmed server-side pagination, ~50 projects/page).

## `countryCode` (type: `string`):

2-letter ISO country code pinning the datacenter proxy exit (e.g. <code>US</code>). Freelancer.com localises displayed currency by exit IP, so pinning prevents a geo-random exit from silently returning a different currency on a 200.

## `maxRuntimeSecs` (type: `integer`):

Wall-clock deadline. The Actor stops requesting new pages once this much time has elapsed and finishes with whatever rows were already collected.

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

Apify Proxy spec. Freelancer.com returned clean 200s with no anti-bot header during recon, so this Actor requests the DATACENTER pool (apifyProxyGroups explicitly empty, not omitted) pinned to a country — the cheapest tier that clears reach.

## Actor input object example

```json
{
  "skills": [
    "python",
    "react",
    "wordpress"
  ],
  "maxPagesPerSkill": 2,
  "countryCode": "US",
  "maxRuntimeSecs": 300,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

All dataset items as JSON.

## `datasetItemsCsv` (type: `string`):

Same data exported to CSV.

## `datasetView` (type: `string`):

Open the run dataset in the Console.

# 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",
        "react",
        "wordpress"
    ],
    "maxPagesPerSkill": 2,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("devilscrapes/freelancer-com-projects-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 = {
    "skills": [
        "python",
        "react",
        "wordpress",
    ],
    "maxPagesPerSkill": 2,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": [],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("devilscrapes/freelancer-com-projects-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 '{
  "skills": [
    "python",
    "react",
    "wordpress"
  ],
  "maxPagesPerSkill": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [],
    "apifyProxyCountry": "US"
  }
}' |
apify call devilscrapes/freelancer-com-projects-scraper --silent --output-dataset

```

## MCP server setup

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