Freelancer.com Scraper - Projects, Parsed Budgets & Skills avatar

Freelancer.com Scraper - Projects, Parsed Budgets & Skills

Pricing

from $0.50 / 1,000 results

Go to Apify Store
Freelancer.com Scraper - Projects, Parsed Budgets & Skills

Freelancer.com Scraper - Projects, Parsed Budgets & Skills

Scrape live Freelancer.com projects by keyword with budget, skills & poster info. Filter by budget, export to CSV/JSON/Excel, or deliver leads to Notion, Slack & Jira via MCP connectors.

Pricing

from $0.50 / 1,000 results

Rating

0.0

(0)

Developer

Techforce Global

Techforce Global

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Share

Freelancer.com Project Scraper - Public Projects by Keyword, with Parsed Budget Ranges, Skill Tags and Per-Row Keyword Attribution

Apify Actor MCP Ready Pricing Scope Output Keys

Keyword in, live gigs out — with the budget as a number, not a string. Searches active fixed-price projects on Freelancer.com and returns title, numeric budget range, currency symbol, tagged skills, posting time and project URL, one row per project, each tagged with the keyword that found it. No Freelancer account, no login, no API key. Optional delivery into Notion, Slack, Linear, Jira, GitHub or Airtable over MCP.

🔐 Trust & scope at a glance

CredentialsNone required. No Freelancer login, no OAuth, no API key. Delivery runs through the Apify MCP Proxy, so the Actor never sees your connector tokens.
Data scopeActive, fixed-price projects only. Hourly projects, closed projects, bids and proposals are all out of scope.
Personal dataMinimal — and mostly absent. The poster block exists but commonly comes back all "N/A"; treat any populated value as personal data about a real client.
⚠️ Currencycurrency is a symbol, not an ISO code, and $ is ambiguous across USD/AUD/CAD/NZD/SGD/HKD. Never aggregate budgets across symbols.
⚠️ The budget string is display-onlyIt is always rendered with a literal $, even when currency says otherwise. Use budgetMin/budgetMax + currency for anything numeric.

Full detail: Compliance & Data Privacy.


Freelancer.com's own API vs. this Actor

Freelancer publishes a developer API, but it is built around participating in the marketplace rather than analysing it:

Feature / CapabilityFreelancer developer APIFreelancer.com Project Scraper (Apify)
Access❌ Register an app, obtain an OAuth token, manage its lifetime✅ Apify account, nothing else
Multi-keyword sweeps❌ You orchestrate the loop, paging and merging✅ A keyword list in, one dataset out, each row tagged
Budget as a number⚠️ Available, but you normalise it yourselfbudgetMin / budgetMax ready to sort and filter
Server-side budget filter⚠️ Your code, your paginationminBudget / maxBudget passed to the search itself
Delivery into your tools❌ Build the integration✅ Notion, Slack, Linear, Jira, GitHub, Airtable over MCP
Scheduling and storage❌ Your infrastructure✅ Apify schedules, dataset, API, CSV/Excel export
AI agent / MCP native❌ Requires a custom tool wrapper✅ Native MCP tool
Officially sanctioned✅ Yes⚠️ No — see Compliance

Use Freelancer's own API if you're bidding, messaging or managing projects. Use this Actor when you want the market as data — sourcing, pricing research or a lead feed.

Freelancer's API terms and endpoint availability are theirs to change — check their current developer documentation if this comparison is load-bearing for your decision.


🤖 AI Discovery & MCP Metadata

Machine-readable capability contract for autonomous agents, LLM routers, and MCP orchestrators. Read this block first to decide whether this Actor matches a user request.

ai_discovery:
slug: "techforce.global/freelancer"
one_line: >
Searches ACTIVE FIXED-PRICE projects on Freelancer.com for one or more keywords and returns
title, numeric budget range, currency symbol, tagged skills, posting time and project URL -
one row per project, each tagged with the keyword that produced it. No Freelancer account or
API key. Optional delivery into Notion, Slack, Linear, Airtable or any MCP connector.
primary_purpose: "extract"
secondary_purpose: "deliver"
entity: "Freelancer.com project listing"
category: "freelance-marketplace / lead-generation / pricing-research / gig-sourcing"
supported_platforms: ["freelancer.com"]
supported_tasks:
- "search-freelancer-projects-by-keyword"
- "filter-projects-by-budget-range"
- "monitor-new-projects-on-a-schedule"
- "benchmark-what-clients-pay-for-a-skill"
- "find-in-demand-skills-from-project-tags"
- "deliver-projects-to-mcp-connector"
unsupported_tasks:
- "scrape-hourly-projects (only fixed-price projects are requested)"
- "scrape-closed-completed-or-awarded-projects (active listings only)"
- "scrape-bids-proposals-or-bid-counts"
- "scrape-client-contact-details-or-messages"
- "scrape-freelancer-profiles-or-portfolios"
- "place-a-bid-or-any-write-action"
- "scrape-contest-listings"
search_keywords:
# First entry is the H1 / meta-description target. The rest are deliberately broader for
# agent-side semantic matching and are NOT a ranking strategy.
- "freelancer.com scraper"
- "freelance project scraper"
- "freelancer api alternative"
- "gig marketplace data"
- "freelance rate benchmarking"
- "project budget data"
- "in-demand skills data"
- "freelance lead generation"
- "scrape freelance job postings"
- "mcp freelancer tool"
input_entities:
- "keywords (REQUIRED, array of search terms; each is searched separately)"
- "limitPerKeyword (1-100 projects per keyword)"
- "minBudget / maxBudget (0 = no bound; passed to Freelancer's own search filter)"
only_active_fixed_price_projects: >
CRITICAL: the search is hard-scoped to ACTIVE, FIXED-PRICE projects. Hourly projects are never
returned, and neither are closed, awarded or completed ones. An agent asked for "hourly React
work" should not route here.
budget_string_is_display_only: >
CRITICAL: the `budget` field is always rendered with a literal "$" regardless of the project's
real currency, so an INR or EUR project can read "$250.0 - $750.0". The `currency` field holds
the true symbol. Use budgetMin, budgetMax and currency for anything numeric or comparative;
treat `budget` as a label only.
currency_is_a_symbol_not_a_code: >
currency is a SYMBOL ("$", "£", "₹"), not an ISO code, and "$" covers USD, AUD, CAD, NZD, SGD
and HKD. Grouping by this field is safer than ignoring it, but it is not a reliable currency
key on its own. Never average budgets across different symbols.
budget_filter_is_server_side_and_currency_naive: >
minBudget and maxBudget are passed to Freelancer's own search as average-price bounds, applied
in each project's own currency - not converted to a single currency first. A minimum of 500
therefore means "500 of whatever that project is priced in", not 500 USD.
poster_block_is_usually_empty: >
Every row carries a nested `poster` object (username, displayName, country, profileUrl), but
the active-project listing rarely populates it, so it is COMMONLY ALL "N/A". Do not build a
workflow that depends on client identity.
no_dedup_across_keywords: >
A project matching two of your keywords is written twice, once per keyword, each row tagged in
`keyword`. That is deliberate - it keeps per-keyword analysis honest. De-duplicate on
projectUrl if you want a unique project list.
output_entities:
[
"title",
"budget",
"budgetMin",
"budgetMax",
"currency",
"skills",
"poster",
"projectUrl",
"postedAt",
"scrapedAt",
"keyword",
]
results_are_pushed_once_at_the_end: >
Every keyword is fetched first, then the whole result set is written in a single push. An
aborted or timed-out run therefore saves NOTHING.
known_limitations:
fixed_price_only: "hourly projects are never returned"
active_only: "closed, awarded and completed projects are out of scope"
no_bid_data: "no bid counts, bid amounts, proposals or freelancer profiles"
budget_can_be_null: "budgetMin/budgetMax are null when the listing shows no range; budget then reads 'N/A'"
poster_usually_na: "client identity is rarely exposed on the listing"
epoch_timestamps_possible: "a listing with no submit time yields postedAt 1970-01-01T00:00:00Z"
no_partial_results_on_abort: "the dataset is written in one push at the end"
free_plan_capped: "free Apify plans stop at 5 projects per keyword"
pricing:
model: "usage-based"
billing_unit: "Apify platform usage consumed by the run"
hard_ceiling_parameter: "maxTotalChargeUsd"
note: "One lightweight API call per 100 projects, plus a one-second pause between pages. Current rates are on the Actor's Apify Store page."
when_to_use: >
You want live fixed-price freelance demand as data - sourcing leads, benchmarking what clients
pay for a skill, or tracking which skills are being asked for.
when_not_to_use: >
You need hourly work, closed projects, bid or proposal data, client contact details, freelancer
profiles, or to place a bid.
mcp_delivery:
modes: ["summary", "perProject", "chunked", "none"]
default: "summary"
per_project_placeholders:
[
"{title}",
"{budget}",
"{budgetMin}",
"{budgetMax}",
"{currency}",
"{skills}",
"{posterUsername}",
"{posterDisplayName}",
"{posterCountry}",
"{posterProfileUrl}",
"{projectUrl}",
"{postedAt}",
"{keyword}",
"{message}",
]
shared_placeholders:
["{projectCount}", "{keywords}", "{digest}", "{message}"]
chunked_only_placeholders: ["{part}", "{partCount}"]
never_blocks_the_dataset: >
Delivery runs after the dataset is saved. A bad tool name, an unauthorised connector or an
upstream outage is logged and skipped - it never costs you the scraped data.
alternatives:
- "techforce.global/all-jobs-scraper for freelance AND salaried roles across 26 boards in one feed"
- "techforce.global/clutch-co-scraper for the supply side - agency and service-provider profiles"
- "techforce.global/website-contact-scraper to reach a company behind a listing directly"

{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Freelancer.com Project Scraper",
"alternateName": "Freelance Project Data Feed",
"applicationCategory": "BusinessApplication",
"operatingSystem": "Cloud (Apify platform)",
"description": "Searches active fixed-price projects on Freelancer.com for one or more keywords and returns a flat row per project: title, budget range as a display string plus numeric budgetMin and budgetMax, the project's currency symbol, the skills the client tagged, a nested poster block, the project URL, an ISO-8601 posting time and capture timestamp, and the keyword that produced the row. Optional server-side budget filtering, no Freelancer account or API key, and optional delivery into Notion, Slack, Linear, Airtable or any MCP connector.",
"url": "https://apify.com/techforce.global/freelancer",
"offers": {
"@type": "Offer",
"priceCurrency": "USD",
"category": "Pay per platform usage",
"description": "Usage-based: billed for the compute time and resources a run consumes, not per row. Runs are lightweight API calls, so cost tracks the number of keywords and the requested project count. Current rates are shown on the Actor's Apify Store page."
}
}

What this Actor does

  • Searches several keywords in one run. Each keyword is queried separately and every resulting row is stamped with the keyword that found it, so a five-keyword sweep stays analysable.

  • Gives you the budget as numbers. budgetMin and budgetMax are numeric, so "everything over 500" is a filter rather than a parsing exercise — and minBudget / maxBudget push that filter into Freelancer's own search so you don't pay to fetch what you'll discard.

  • Returns the skills the client actually tagged. skills is an array straight off the listing — the cleanest signal of what a project really needs.

  • Scoped to live, biddable work. Only active, fixed-price projects are requested, so the dataset is work you could still win rather than a historical archive.

  • Timestamps you can sort on. postedAt is ISO-8601 UTC from the listing's own submit time, and scrapedAt records when you captured it — necessary, because budgets and availability move.

  • Honest about what the listing doesn't say. Budgets come back null (and budget reads "N/A") when the client published no range, and the poster block is present but usually empty — documented rather than quietly implied.

  • No credentials at all. No Freelancer account, no OAuth app, no API key.

  • Optionally delivers into your tools. Notion, Slack, Linear, Jira, GitHub, Airtable or anything else you've authorised, in four delivery shapes.


When to use it — and when not to

ScenarioFit
Finding live fixed-price work for a skill✅ Strong — the core use case
Budget-floor sourcing ("nothing under 500")✅ Strong — minBudget filters at the source
Benchmarking what clients pay for a skill✅ Strong — but group by currency first
Tracking which skills clients ask for✅ Strong — aggregate the skills array
New-project alerts on a schedule✅ Strong — schedule it, de-duplicate on projectUrl
Comparing demand across several keywords✅ Strong — every row carries its keyword
Results in Notion / Slack / Airtable✅ Strong — native MCP delivery
A unique project list⚠️ Rows repeat across keywords by design — dedupe on projectUrl
Cross-currency budget comparison⚠️ currency is a symbol and $ is ambiguous
Knowing who posted a project⚠️ The poster block is usually all "N/A"
Hourly projects❌ Only fixed-price projects are requested
Closed, awarded or completed projects❌ Active listings only
Bids, proposals or bid counts❌ Not collected
Client contact details or messages❌ Never accessible
Freelancer profiles or portfolios❌ Out of scope
Contest listings❌ Not requested
Placing a bid or any write action❌ Read-only

⚡ Execution Rules (Avoid Common Agent Failures)

  1. keywords is required and is an array. Each entry is searched separately, so five keywords is five sweeps. Every output row carries the keyword that produced it.

  2. Only active, fixed-price projects are returned. Hourly work is never included — that is a hard scope decision in the search, not a filter you can switch off. An agent asked for hourly work should route elsewhere.

  3. Do not do arithmetic on budget. It is a display string and it is always rendered with a literal $, even when the project is priced in rupees or euros. budgetMin, budgetMax and currency are the fields to trust.

  4. currency is a symbol, not an ISO code. $ covers USD, AUD, CAD, NZD, SGD and HKD. Grouping by it is better than ignoring it, but it is not a reliable currency key — never average across symbols.

  5. minBudget / maxBudget are applied by Freelancer, in the project's own currency. They bound the project's average price at the source, so minBudget: 500 means "500 of whatever that project is priced in", not 500 USD. Both default to 0, meaning no bound.

  6. budgetMin / budgetMax can be null. When the listing publishes no range, both are null and budget reads "N/A". Null is not zero — exclude those rows from averages.

  7. The poster block is usually all "N/A". The listing endpoint rarely exposes client identity. Don't build a workflow that depends on it.

  8. Rows repeat across keywords, deliberately. A project matching two keywords appears twice, once per keyword. De-duplicate on projectUrl if you want a unique list.

  9. limitPerKeyword caps at 100. Larger values are rejected by the schema; the search pages through in batches with a one-second pause between them.

  10. A keyword that errors is skipped, not fatal. The failure is printed and the run moves on to the next keyword, still finishing successfully.

  11. postedAt can be the Unix epoch. A listing with no submit time yields 1970-01-01T00:00:00Z. Treat pre-2000 dates as missing, not as very old projects.

  12. Nothing is saved until the end. All keywords are fetched, then the whole set is written in one push — an aborted or timed-out run saves nothing.

  13. deliveryMode defaults to summary. perProject sends one connector call per project; a 300-project run is 300 calls.

  14. Free Apify plans stop at 5 projects per keyword. A smoke test, not a data pull.

dependencies:
- rule: "keywords is required and must contain at least one non-empty term"
on_violation: "nothing is searched and the run finishes with an empty dataset"
- rule: "budget is a display string with a hard-coded $ - budgetMin/budgetMax/currency are authoritative"
note: "the only field-level trap in this Actor"
- rule: "minBudget/maxBudget bound the average price in the project's own currency"
note: "they are not converted to a single currency first"
- rule: "delivery requires mcpConnector AND mcpTool"
on_violation: "delivery is skipped with a warning; every dataset row is still written"
- rule: "mcpArguments must reference {message} or {digest} for the rendered text to appear"
on_violation: "the tool is called with an empty body"
- rule: "mcpConnector only resolves when the Actor runs on the Apify platform"
on_violation: "local runs skip delivery; the dataset is unaffected"
authentication:
actor_input: none
platform: "Apify API token required for API / SDK / MCP invocation"
target_site: "no Freelancer.com account, OAuth app or API key required (public listings only)"

📥 Input Contract

.actor/input_schema.json is authoritative — if this page disagrees with the schema files, the schema files win.

ParameterTypeRequiredDefaultNotes
keywordsarray<string>Yes["python", "web scraping"]Each term is searched separately and stamped on its rows
limitPerKeywordinteger⬜ No201100 projects per keyword
minBudgetinteger⬜ No0Lower bound on the project's average price. 0 = no minimum
maxBudgetinteger⬜ No0Upper bound. 0 = no maximum

What the budget bounds really do. They are handed to Freelancer's own search as average-price limits and applied in each project's own currency — they are not converted to a common currency first. On a multi-currency result set, treat them as a coarse filter and do the precise work yourself on budgetMin / budgetMax + currency.

Delivery (optional)

ParameterTypeDefaultDescription
mcpConnectorstring""A connector you've authorised on your Apify account — Notion, Slack, Linear, Jira, GitHub, Airtable, or any MCP-compatible connector. Leave empty for dataset-only runs.
deliveryModestring (enum)"summary"summary (one digest) · perProject (one call per project) · chunked (digest split across calls) · none.
mcpToolstring""Tool to call — create-page, send-message, create_issue. Required when a connector is set.
mcpArgumentsobject{}Arguments for the tool. String values support {placeholder} tokens.
mcpMessageTemplatestring""Template rendered and exposed to mcpArguments as {message}.

Placeholders by mode:

ModePlaceholders
summary{projectCount} {keywords} {digest} (every project, formatted) {message}
chunkedthe same, plus {part} {partCount}{digest} holds one part
perProjectthe shared three, plus {title} {budget} {budgetMin} {budgetMax} {currency} {skills} {posterUsername} {posterDisplayName} {posterCountry} {posterProfileUrl} {projectUrl} {postedAt} {keyword} {message}

chunked groups the digest so no single call exceeds roughly 72,000 characters, with each project block packed to about 1,800 characters — which keeps Notion's block and timeout limits happy.


📤 Output Contract & Data Structure

One dataset row per project per keyword. Every row carries the same 11 keys.

FieldTypeNullableMeaning
titlestringyesProject title as posted. "N/A" when the listing exposed none
budgetstringyesDisplay only. Always formatted with a literal $, whatever the real currency. "N/A" when no range was published
budgetMinnumberyesLower bound, numeric. Use this for filtering and arithmetic
budgetMaxnumberyesUpper bound, numeric
currencystringyesThe project's currency symbol ($, £, ) — not an ISO code, and $ is ambiguous
skillsarraynoSkills the client tagged. [] when none were tagged
posterobjectno{username, displayName, country, profileUrl}commonly all "N/A"
projectUrlstringyesLink to the project page. The de-duplication key
postedAtstringyesISO-8601 UTC posting time. 1970-01-01T00:00:00Z when the listing had none
scrapedAtstringyesISO-8601 UTC capture time — budgets and availability move, so this is the row's shelf life
keywordstringyesWhich of your input keywords produced this row

The one trap worth repeating: budget is a label, budgetMin/budgetMax/currency are the data. A project priced at ₹20,000–₹50,000 will show budget: "$20000.0 - $50000.0" with currency: "₹". Sorting or averaging on the string will quietly mislead you.

Example output object

{
"title": "Build a Python scraper for a real-estate portal",
"budget": "$250.0 - $750.0",
"budgetMin": 250.0,
"budgetMax": 750.0,
"currency": "$",
"skills": ["Python", "Web Scraping", "Data Mining", "BeautifulSoup"],
"poster": {
"username": "N/A",
"displayName": "N/A",
"country": "N/A",
"profileUrl": "N/A"
},
"projectUrl": "https://www.freelancer.com/projects/python/build-python-scraper-real-estate",
"postedAt": "2026-08-31T14:07:12Z",
"scrapedAt": "2026-09-01T09:14:02Z",
"keyword": "web scraping"
}

Values illustrate shape and formatting — the project is invented. The all-"N/A" poster block is the normal case, not an error.

What a successful run looks like

  • Status: SUCCEEDED
  • Dataset: one row per project per keyword, up to limitPerKeyword for each
  • Log: a header echoing keywords, limit and budget bounds, then Searching: '<keyword>' and Fetched N/M projects... per keyword, then the push count
  • Zero results is also a success. A keyword with no live fixed-price matches, or budget bounds nothing satisfies, returns an empty dataset with SUCCEEDED. The log shows No more results for '<keyword>'.
  • A keyword that errored is skipped, logged as Request failed, and the run continues.
  • Fewer rows than keywords × limitPerKeyword is normal — most keywords simply don't have that many live projects.

Dataset views

ViewShows
ProjectsTitle, budget string and numeric range, currency, skills, keyword, posted time, link
BudgetsNumeric range, currency, budget string, title, skills, posted time, link
Keyword & CaptureKeyword, title, posted and captured timestamps, poster block, link

▶️ Invocation & Integration

Authenticate every call with Authorization: Bearer <APIFY_TOKEN>.

Apify Console

Open the Actor pageInput tab → add your keywords → set limitPerKeyword → optionally set a budget floor or ceiling → Start.

Model Context Protocol (MCP)

claude mcp add --transport http apify \
"https://mcp.apify.com?tools=techforce.global/freelancer"

Then ask your agent for "live Python scraping gigs paying over $500".

Python (apify-client)

import os
from collections import Counter, defaultdict
from statistics import median
from apify_client import ApifyClient
client = ApifyClient(os.getenv("APIFY_TOKEN"))
run = client.actor("techforce.global/freelancer").call(run_input={
"keywords": ["web scraping", "data engineering"],
"limitPerKeyword": 50,
"minBudget": 250,
"maxBudget": 0, # 0 = no ceiling
})
projects = list(client.dataset(run["defaultDatasetId"]).iterate_items())
if not projects:
raise SystemExit("Nothing matched — try broader keywords or a lower minBudget.")
# Which keyword is actually finding the good work?
print(Counter(p["keyword"] for p in projects))
# currency is a SYMBOL and "$" is ambiguous — never aggregate across symbols.
by_symbol = defaultdict(list)
for p in projects:
if p.get("budgetMin") is not None:
by_symbol[p.get("currency") or "?"].append(p["budgetMin"])
for symbol, values in by_symbol.items():
print(f"{symbol} n={len(values):>3} median floor {median(values):,.0f}")
# The same project can appear once per matching keyword — dedupe on projectUrl.
unique = {p["projectUrl"]: p for p in projects}
print(f"{len(unique)} unique projects out of {len(projects)} rows")
# What skills are clients actually asking for?
skills = Counter(s for p in unique.values() for s in (p.get("skills") or []))
print(skills.most_common(10))

JavaScript / TypeScript (apify-client)

import { ApifyClient } from "apify-client";
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor("techforce.global/freelancer").call({
keywords: ["react", "next.js"],
limitPerKeyword: 40,
minBudget: 500,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
// Never sort on `budget` — it is a display string with a hard-coded "$".
const priced = items.filter(
(p) => p.budgetMin !== null && p.budgetMax !== null,
);
priced.sort((a, b) => b.budgetMax - a.budgetMax);
for (const p of priced.slice(0, 10)) {
// Rebuild the label from the fields that are actually correct.
const label = `${p.currency}${p.budgetMin} - ${p.currency}${p.budgetMax}`;
console.log(
`${label.padEnd(22)} ${(p.skills ?? []).slice(0, 3).join(", ").padEnd(34)} ${p.title}`,
);
}
// postedAt can legitimately be the Unix epoch when the listing had no submit time.
const dated = items.filter((p) => p.postedAt && !p.postedAt.startsWith("1970"));
console.log(`${dated.length}/${items.length} rows have a usable postedAt`);

cURL — synchronous (waits, returns the dataset)

curl -X POST \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
-d '{ "keywords": ["python"], "limitPerKeyword": 20, "minBudget": 0, "maxBudget": 0 }' \
'https://api.apify.com/v2/acts/techforce.global~freelancer/run-sync-get-dataset-items'
# 1. Start with a hard spend limit
curl -X POST -H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
-d '{ "keywords": ["python","react","logo design","copywriting"], "limitPerKeyword": 100 }' \
'https://api.apify.com/v2/acts/techforce.global~freelancer/runs?maxTotalChargeUsd=5'
# 2. Poll, then 3. fetch the dataset when SUCCEEDED
curl -H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' 'https://api.apify.com/v2/actor-runs/<runId>'
curl -H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
'https://api.apify.com/v2/datasets/<DATASET_ID>/items?clean=true&format=json'

Budget-floor sourcing

{
"keywords": ["web scraping", "data extraction", "crawler"],
"limitPerKeyword": 100,
"minBudget": 500,
"maxBudget": 0
}

Pushing the floor into the search means you don't pay to fetch the £30 jobs and throw them away. Remember the bound is applied in each project's own currency — verify with budgetMin + currency afterwards if precision matters.

Skill-demand research

{
"keywords": ["machine learning"],
"limitPerKeyword": 100,
"minBudget": 0,
"maxBudget": 0
}

One broad keyword, no budget bounds, then aggregate the skills arrays downstream — that's the cleanest read on what clients are pairing with a skill right now.

With MCP delivery — new projects into Slack

{
"keywords": ["web scraping"],
"limitPerKeyword": 20,
"minBudget": 250,
"mcpConnector": "<your-authorized-slack-connector>",
"mcpTool": "send-message",
"deliveryMode": "summary",
"mcpMessageTemplate": "{projectCount} new Freelancer projects for {keywords}:\n\n{digest}",
"mcpArguments": { "channel": "#gig-alerts", "text": "{message}" }
}

Use summary for a digest and chunked when the list is long. perProject is one message per project — fine for 20, noisy for 300.

Scheduling for new-project alerts

Put a fixed input on a schedule, keep limitPerKeyword modest, and de-duplicate against your own store on projectUrl. Anything you haven't seen before is new work — and postedAt tells you how fresh it is.


⚠️ Autonomous Agent Error Handling & Resolution Matrix

Read this first: nothing about the listings fails the run. An empty keyword list, a failing request and a budget filter nothing satisfies all end SUCCEEDED while the log carries the reason. An agent that checks run status alone will read an empty dataset as success-with-data — check the row count and the log.

The CONDITION labels are documentation handles for observable states; this Actor writes no error code into the dataset.

ConditionWhat you observeCauseDeterministic agent action
NO_KEYWORDSEmpty dataset, no Searching: lines in the logkeywords emptyModify Input: supply at least one keyword.
NO_RESULTS_FOR_KEYWORDLog: No more results for '<keyword>'No live fixed-price projects matchExpected. Broaden the keyword or lower minBudget.
REQUEST_FAILEDLog: Request failed: …, that keyword contributes nothingFreelancer's endpoint errored or timed outRetry later. Other keywords are unaffected; the run still succeeds.
HOURLY_WORK_MISSINGNo hourly projects anywhere in the outputOnly fixed-price projects are requestedFix expectation. Route hourly enquiries elsewhere.
CLOSED_PROJECTS_MISSINGNo completed or awarded projectsActive listings onlyFix expectation. Historical data is out of scope.
BUDGET_STRING_WRONG_CURRENCYbudget shows $ but currency says The display string is hard-coded with $Fix consumer: rebuild the label from budgetMin/budgetMax/currency.
MIXED_CURRENCY_AGGREGATEBudget averages look impossible$ covers several currencies and symbols are mixedFix consumer: group by currency, and treat $ as ambiguous.
BUDGET_FILTER_SURPRISERows below your minBudget in another currencyThe bound is applied per project in its own currencyExpected. Re-filter on budgetMin + currency downstream.
NULL_BUDGETbudgetMin/budgetMax null, budget: "N/A"The listing published no rangeExpected. Exclude from averages; null ≠ zero.
POSTER_ALL_NAEvery poster field is "N/A"The listing endpoint rarely exposes client identityExpected. Don't depend on client identity.
DUPLICATE_PROJECTSThe same projectUrl appears twiceIt matched two keywords; each row is taggedExpected. Dedupe on projectUrl for a unique list.
EPOCH_POSTED_ATpostedAt is 1970-01-01T00:00:00ZThe listing had no submit timeFix consumer: treat pre-2000 dates as missing.
FEWER_ROWS_THAN_REQUESTEDRows < keywords × limitPerKeywordThat many live projects don't existExpected. Add keywords rather than raising the limit.
NO_DATA_AFTER_ABORTAn aborted run left an empty datasetResults are written in one push at the endExpected. Lower limitPerKeyword so the run completes.
FREE_PLAN_CAPPED5 projects per keyword; log says soFree Apify planUpgrade the plan.
CONNECTOR_CALL_STORMHundreds of connector callsperProject sends one call per projectModify Input: switch to summary or chunked.
CONNECTOR_TOOL_NOT_FOUNDLog: Tool 'x' is not available on this connector. Available tools: …Wrong mcpTool name (empty is logged separately)Modify Input: copy an exact name from that log line. Dataset unaffected.
CONNECTOR_UNREACHABLELog: Could not reach the connector: …Connector not authorised, or running locallyAuthorise it, or set deliveryMode: "none". Data already saved.
AUTH_INVALIDHTTP 401Missing or malformed APIFY_TOKENAbort & prompt user for a valid token.
RATE_LIMITED_APIFYHTTP 429Apify API rate / concurrency limitsRetry: exponential backoff (2s, 4s, 8s).
SYNC_TIMEOUTHTTP 408 on the sync endpointRun exceeded the synchronous ceilingReconfigure: async POST /runs + polling.

Provenance: every log line, status and dataset condition above is taken from this Actor's own source and verified against it. The three HTTP rows describe the Apify API transport layer, not this Actor — confirm them against the Apify API reference before wiring them into automated retry logic.


🗣️ Natural Language → Actor Mapping

A user says…IntentConstructed Actor input
"Find Python gigs on Freelancer"Core search{"keywords":["python"],"limitPerKeyword":20}
"Web scraping jobs paying over $500"Budget floor{"keywords":["web scraping"],"minBudget":500}
"Small jobs under $200"Budget ceiling{"keywords":["<skill>"],"maxBudget":200}
"Projects between $500 and $2000"Budget band{"keywords":["<skill>"],"minBudget":500,"maxBudget":2000}
"Compare demand for React vs Vue"Multi-keyword{"keywords":["react","vue"],"limitPerKeyword":100} then count by keyword
"What do clients pay for logo design?"Rate benchmarkingScrape, group by currency, aggregate budgetMin/budgetMax
"Which skills go with machine learning?"Skill co-occurrenceOne broad keyword, then aggregate the skills arrays
"Alert me to new scraping projects"MonitoringFixed input on a schedule; dedupe on projectUrl
"The biggest projects available"RankingScrape, then sort on budgetMax excluding nulls
"Just a quick sample"Cheap probe{"keywords":["<skill>"],"limitPerKeyword":5}
"Send new gigs to Slack"Scrape + deliverAbove, plus mcpConnector, mcpTool, deliveryMode: "summary"
"It returned nothing"Empty resultBroaden the keyword, lower minBudget, check the log
"Show me hourly contracts"Hourly work❌ Fixed-price only — out of scope
"Who posted this project?"Client identity⚠️ poster is usually "N/A"
"How many bids does it have?"Bid data❌ Not collected
"Bid on this for me"Write action❌ Read-only

Should NOT route here: hourly projects · closed, awarded or completed projects · bids, proposals or bid counts · client contact details or messages · freelancer profiles or portfolios · contest listings · placing a bid or any write action · other marketplaces — for freelance and salaried roles across many boards, use All Jobs Scraper.


🧭 Agent Execution & Routing Logic

Does the user want LIVE FREELANCE PROJECT listings?
├── NO → wrong Actor.
│ freelance + salaried roles, many boards → All Jobs Scraper
│ agencies / service providers → Clutch.co Scraper
│ a company's own contact details → Website Contact Scraper
└── YES
├── Is the work HOURLY? → ❌ out of scope: only fixed-price projects are requested
├── Do they want CLOSED / historical projects? → ❌ active listings only
├── Do they want BIDS or CLIENT identity? → ❌ not collected (poster is usually "N/A")
├── keywords — REQUIRED, an ARRAY. Each term is its own sweep.
│ comparing terms? → pass them together; every row is tagged with `keyword`
├── Size the run
│ ├── limitPerKeyword → 1-100 PER KEYWORD (total = keywords × limit)
│ └── nothing is saved until the end → size it so the run finishes
├── Budget bounds?
│ ├── minBudget / maxBudget → applied by Freelancer, in the PROJECT'S OWN currency
│ ├── 0 means "no bound" on either side
│ └── need precision? filter downstream on budgetMin + currency
├── What is the actual question?
│ ├── best-paid → sort budgetMax, EXCLUDING nulls
│ ├── rate benchmark → GROUP BY currency first ("$" is ambiguous)
│ ├── skill demand → aggregate the skills arrays
│ ├── keyword compare → count rows per `keyword`
│ └── what's new → SCHEDULE it; dedupe on projectUrl, read postedAt
└── Should results land in another app?
├── yes → mcpConnector + mcpTool + {message} or {digest} in mcpArguments
│ digest → summary (default) · long list → chunked · each → perProject
└── no → deliveryMode "none", or leave mcpConnector empty
[Execute Actor]
├──► SUCCEEDED with rows → dedupe on projectUrl, then analyse (never on `budget`)
├──► SUCCEEDED, 0 rows → READ THE LOG: no keywords / no matches / request failed
└──► 5 rows per keyword → free plan cap, not a data pull

💰 Cost Control & Pricing Transparency

Billing model: usage-based. This Actor bills for platform usage — the compute time and resources a run consumes — not per row. Current rates are on the Actor's Apify Store page; the Console shows the live total mid-run.

This is one of the cheaper Actors in the catalogue: it talks to a JSON endpoint rather than rendering pages, so a run is a handful of HTTP calls plus a one-second pause between pages.

ChoiceEffect on cost
Number of keywordsThe main multiplier — each is a separate sweep.
limitPerKeywordOne request per 100 projects, so 20 and 100 differ by one call.
minBudget / maxBudgetReduce cost: filtering at the source means fewer projects fetched.
Delivery modeperProject adds one connector call per project; summary adds one.

Worked examples — relative run shape

ScenarioKeywordsRequestsRowsNotes
Probe — 1 keyword, limitPerKeyword: 511≤ 5Baseline. Confirms the keyword returns live work.
Standard — 2 keywords × 5022≤ 100The common sourcing run.
Broad sweep — 4 keywords × 10044≤ 400Still only four API calls.
Filtered — 4 keywords × 100, minBudget: 50044far fewerCheapest per useful row.
Monitoring — 1 keyword × 20, hourly schedule11≤ 20Very cheap; dedupe on projectUrl.

Keeping runs predictable:

  1. First run: one keyword, limitPerKeyword: 5. Confirms the search returns live projects.
  2. Use minBudget rather than filtering afterwards — it is the one lever that reduces both cost and noise.
  3. Add keywords for coverage — they're the multiplier, but each is only a request or two.
  4. Set maxTotalChargeUsd on large scheduled runs, as a matter of habit.
  5. Schedule small and often for alerts rather than one big sweep.
  6. Free Apify plans get 5 projects per keyword — a connectivity check, not a data pull.

🛠️ Troubleshooting

Most problems are scope expectations — hourly work, closed projects, client identity — or the budget string. Very few are scraper faults.

#Symptom you seeMost likely causeFix
1Empty datasetNo keywords supplied, or nothing matchedCheck the log for Searching: lines and No more results for …. Broaden the keyword or lower minBudget.
2A keyword returned nothing while others workedNo live fixed-price projects for that term, or its request failedLook for Request failed in the log; retry later.
3No hourly projects anywhereOnly fixed-price projects are requestedOut of scope — this is a hard scope decision, not a filter.
4No closed or completed projectsActive listings onlyOut of scope.
5budget shows $ but the project is in another currencyThe display string is hard-coded with $Rebuild the label from budgetMin/budgetMax + currency. Never sort on budget.
6Budget averages look wrongSymbols mixed, and $ covers several currenciesGroup by currency; treat $ as ambiguous rather than as USD.
7Rows below my minBudgetThe bound is applied per project in its own currencyRe-filter downstream on budgetMin + currency.
8budgetMin / budgetMax are nullThe listing published no rangeExpected — exclude those rows rather than treating them as 0.
9Every poster field is "N/A"The listing endpoint rarely exposes client identityExpected. Don't build on client identity.
10The same project appears twiceIt matched two keywords; each row is taggedDedupe on projectUrl.
11postedAt is 1970-01-01T00:00:00ZThe listing had no submit timeTreat pre-2000 dates as missing.
12Fewer rows than keywords × limitPerKeywordThat many live projects don't existExpected. Add keywords rather than raising the limit.
13limitPerKeyword above 100 rejectedThe schema caps it at 100Split across more keywords.
14An aborted run saved nothingResults are written in one push at the endLower limitPerKeyword so the run completes.
15Only 5 projects per keywordFree plan capUpgrade; the log says so.
16Hundreds of connector messagesperProject sends one call per projectSwitch to summary or chunked.
17Slack / Notion received an empty messagemcpArguments didn't reference {message} or {digest}Map one of them in mcpArguments.
18Slack / Notion received nothing at allDelivery needs both mcpConnector and mcpToolSet both. Every dataset row is still saved.
19HTTP 401 / 403 from the Apify APIMissing, expired or malformed APIFY_TOKENRegenerate in Console → Settings → API & Integrations.
20HTTP 429 / 408 from the Apify APIApify rate limits / the sync endpoint's time ceilingBack off (2s → 4s → 8s), or switch to async POST /runs + polling.

Diagnostic checklist before opening an issue

  1. Read the log header — it echoes the keywords, limit and budget bounds actually in effect.
  2. Check for Request failed — that's an upstream problem, not a parsing one.
  3. Baseline run: one keyword, limitPerKeyword: 5, minBudget: 0, maxBudget: 0.
  4. Search the same keyword on freelancer.com — if there's no live fixed-price work there, there's nothing to return.
  5. Check currency before trusting any budget figure, and never sort on budget.
  6. Confirm your expectation is in scope — hourly, closed, bids and client identity are all deliberately absent.

If the issue survives all six, open an Issues ticket (or email support) with the run ID, the input you used, and what you expected.


❓ FAQ

Do I need a Freelancer.com account or API key?

No. The Actor reads publicly visible project listings. You need an Apify account and API token; you need no Freelancer credentials, OAuth app or API key.

Is this the official Freelancer API?

No. This is an independent Actor and is not affiliated with, endorsed by, or sponsored by Freelancer Technology Pty Limited. Freelancer's own API exists for participating in the marketplace — bidding, messaging, managing projects — which is a different job from analysing it.

Can I plug it into Claude, Cursor, or a LangChain agent?

Yes — it is a native MCP tool: claude mcp add --transport http apify "https://mcp.apify.com?tools=techforce.global/freelancer"

Does it return hourly projects?

No. The search is scoped to fixed-price projects only, and that isn't a switch you can flip in the input. If you need hourly contracts, this isn't the right Actor.

Does it return closed or completed projects?

No — active listings only. The point is work you can still bid on, not a historical archive.

How do the keywords work?

Each keyword in the array is searched separately, up to limitPerKeyword projects each, and every row records which keyword produced it. Two keywords at 50 is up to 100 rows.

Why does the same project appear twice?

Because it matched two of your keywords, and each row is tagged with its own keyword so per-keyword analysis stays honest. De-duplicate on projectUrl when you want a unique project list.

Why does budget show $ when the project is in another currency?

Because budget is a display string that is always formatted with a literal $. The currency field carries the project's real symbol. Use budgetMin, budgetMax and currency for anything numeric — sorting or averaging the string will mislead you.

Is currency an ISO code?

No, it's a symbol — and $ is ambiguous across USD, AUD, CAD, NZD, SGD and HKD. Group by it rather than ignoring it, but don't treat it as a reliable currency key, and never average budgets across different symbols.

How do minBudget and maxBudget actually filter?

They're passed to Freelancer's own search as average-price bounds and applied in each project's own currency — they are not converted first. So minBudget: 500 means "500 of whatever that project is priced in". Use them as a coarse, cost-saving filter, then refine on budgetMin + currency.

Why are budgetMin and budgetMax sometimes null?

Because the client published no budget range. budget then reads "N/A". Null is not zero — exclude those rows from averages rather than coercing them.

Why is the poster block always "N/A"?

Because the active-project listing rarely exposes client identity. The block is present for shape consistency, but you should assume it's empty and not build a workflow around it.

Why is postedAt sometimes 1970?

That's the Unix epoch, produced when a listing carries no submit time. Treat any pre-2000 postedAt as missing rather than as a very old project.

How many projects can I get per keyword?

Up to 100 — that's the schema's ceiling. For more coverage, add keywords rather than trying to raise the limit.

Can I get bid counts, proposals or freelancer profiles?

No. This Actor returns the project listing itself: what the work is, what it pays and what skills it needs. Bids, proposals and profiles are out of scope.

Does an aborted run keep partial results?

No. All keywords are fetched first and the whole set is written in a single push, so an aborted or timed-out run saves nothing. Keep limitPerKeyword sized so the run completes.

Which delivery mode should I use?

summary (the default) for one digest, chunked when the digest is long enough to trouble Notion's limits, perProject only when you want one record each — a 300-project run means 300 calls — and none for dataset-only runs.

What does it cost, and what do I get on the free plan?

Usage-based: you pay for the platform usage a run consumes, not per row. It's a lightweight JSON-endpoint scrape — roughly one request per 100 projects per keyword — so the keyword count is the main multiplier. Free Apify plans return 5 projects per keyword. Pass maxTotalChargeUsd for a hard per-run ceiling.


🔍 Companion machine-readable files

FileWhat it defines
.actor/input_schema.jsonEvery input, its type, default and bounds, plus the delivery enum
.actor/dataset_schema.jsonAll 11 output fields with nullability, and the three Console views
.actor/output_schema.jsonWhere the run's output is exposed
.actor/actor.jsonActor identity and storage wiring

If this page and the schema files disagree, the schema files win. They are what the platform validates against at run time; this page is documentation and can lag a release.


ActorBest for
This ActorFreelancer.com projects with numeric budget ranges and tagged skills
All Jobs ScraperFreelance and salaried roles across 26 boards in one normalised feed
Clutch.co ScraperAgency and service-provider profiles — the supply side
Website Contact ScraperBusiness contact details from a company's own site
Website Content CrawlerWhole-site text, markdown or HTML for RAG and search

Use All Jobs Scraper when you want freelance work in the same feed as employed roles; use this Actor when Freelancer's budget and skills detail is the point.

Browse the full catalogue at scraper.techforce.global.


🔐 Compliance & Data Privacy

Trademark & affiliation. This is an independent Actor. It is not affiliated with, endorsed by, or sponsored by Freelancer Technology Pty Limited. Freelancer.com™ is their trademark.

  • Public project listings only. No logins, no bids or proposals, no private messages, no client contact details, no freelancer profiles or portfolios.

  • Very little personal data — and mostly absent in practice. The poster block can carry a username, display name and country, which would be personal data about a real client. In practice the listing endpoint rarely populates it, so those fields are usually "N/A". If they are populated and you keep them, you are processing personal data — drop the block at ingest when your question is about budgets and skills, which it usually is.

  • Project descriptions are the client's content. Titles and skill tags are short factual labels; internal analysis, sourcing and benchmarking sit on far safer ground than republishing listings as your own job board.

  • Budgets are a snapshot, and a noisy one. They are what the client proposed, not what the work sold for — and the mixed-symbol currency field makes naive aggregation actively misleading. Publishing "the average price of X on Freelancer" without stating the currency, the sample size and the capture date produces a number that looks authoritative and isn't.

  • Listings expire. A project awarded or withdrawn after your run stays in your dataset until you re-scrape. Anything freelancer-facing needs a refresh cadence and a visible scrapedAt.

  • Freelancer.com's Terms of Use restrict automated access and data extraction. This Actor does not remove that risk — it is a risk you accept by running it. Keep volumes proportionate to the question you're answering.

  • Don't use it to spam clients. Aggregating live projects to pitch at scale is exactly the behaviour marketplaces police, and the listing gives you no sanctioned contact channel anyway. Bid through the platform.

  • Attribution over mirroring. Every row carries projectUrl. Link back to the project rather than presenting Freelancer's marketplace as your own listings.


🆘 Support & Custom Pipeline Engineering

Need automated multi-city scheduled feeds, webhook enrichment, or enterprise data warehouse syncs?



🏷️ Structured data for search & AI discovery

SoftwareApplication describes the Actor; FAQPage wraps the FAQ above so those answers are eligible for rich results, matching it question-for-question.

{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Freelancer.com Project Scraper",
"alternateName": "Freelance Project Data Feed",
"applicationCategory": "BusinessApplication",
"applicationSubCategory": "Web Scraping / Freelance Marketplace & Rate Research",
"operatingSystem": "Cloud (Apify platform)",
"description": "Searches active fixed-price projects on Freelancer.com for one or more keywords and returns a flat row per project: title, budget range as a display string plus numeric budgetMin and budgetMax, the project's currency symbol, the skills the client tagged, a nested poster block, the project URL, an ISO-8601 posting time and capture timestamp, and the keyword that produced the row. Optional server-side budget filtering, no Freelancer account or API key, and optional delivery into Notion, Slack, Linear, Airtable or any MCP connector.",
"url": "https://apify.com/techforce.global/freelancer",
"author": {
"@type": "Organization",
"name": "Techforce Global",
"url": "https://www.techforceglobal.com"
},
"provider": {
"@type": "Organization",
"name": "Apify",
"url": "https://apify.com"
},
"offers": {
"@type": "Offer",
"priceCurrency": "USD",
"category": "Pay per platform usage",
"description": "Usage-based: billed for the compute time and resources a run consumes, not per row. Runs are lightweight API calls, so cost tracks the number of keywords and the requested project count. Current rates are shown on the Actor's Apify Store page.",
"url": "https://apify.com/techforce.global/freelancer"
},
"featureList": [
"No Freelancer.com account, OAuth app or API key required",
"Multiple search keywords in one run, each row tagged with the keyword that found it",
"Numeric budgetMin and budgetMax alongside the display string",
"Server-side budget filtering via minBudget and maxBudget",
"Client-tagged skills as a clean array",
"Scoped to active, fixed-price projects - live work you can still bid on",
"ISO-8601 posting time and capture timestamp on every row",
"Up to 100 projects per keyword",
"Lightweight JSON-endpoint scrape rather than page rendering",
"Optional MCP delivery in summary, chunked or per-project shapes",
"Three Console dataset views covering projects, budgets and provenance"
],
"isAccessibleForFree": false,
"softwareRequirements": "Apify account and API token",
"keywords": "Freelancer.com scraper, freelance project scraper, gig marketplace data, freelance rate benchmarking, project budget data, in-demand skills, freelance lead generation, scrape freelance job postings, MCP connector"
}
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Do I need a Freelancer.com account or API key?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No. The Actor reads publicly visible project listings. You need an Apify account and API token; you need no Freelancer credentials, OAuth app or API key."
}
},
{
"@type": "Question",
"name": "Is this the official Freelancer API?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No. This is an independent Actor and is not affiliated with, endorsed by, or sponsored by Freelancer Technology Pty Limited. Freelancer's own API exists for participating in the marketplace — bidding, messaging, managing projects — which is a different job from analysing it."
}
},
{
"@type": "Question",
"name": "Can I plug it into Claude, Cursor, or a LangChain agent?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Yes — it is a native MCP tool: claude mcp add --transport http apify \"https://mcp.apify.com?tools=techforce.global/freelancer\""
}
},
{
"@type": "Question",
"name": "Does it return hourly projects?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No. The search is scoped to fixed-price projects only, and that isn't a switch you can flip in the input. If you need hourly contracts, this isn't the right Actor."
}
},
{
"@type": "Question",
"name": "Does it return closed or completed projects?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No — active listings only. The point is work you can still bid on, not a historical archive."
}
},
{
"@type": "Question",
"name": "How do the keywords work?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Each keyword in the array is searched separately, up to limitPerKeyword projects each, and every row records which keyword produced it. Two keywords at 50 is up to 100 rows."
}
},
{
"@type": "Question",
"name": "Why does the same project appear twice?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Because it matched two of your keywords, and each row is tagged with its own keyword so per-keyword analysis stays honest. De-duplicate on projectUrl when you want a unique project list."
}
},
{
"@type": "Question",
"name": "Why does budget show $ when the project is in another currency?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Because budget is a display string that is always formatted with a literal $. The currency field carries the project's real symbol. Use budgetMin, budgetMax and currency for anything numeric — sorting or averaging the string will mislead you."
}
},
{
"@type": "Question",
"name": "Is currency an ISO code?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No, it's a symbol — and $ is ambiguous across USD, AUD, CAD, NZD, SGD and HKD. Group by it rather than ignoring it, but don't treat it as a reliable currency key, and never average budgets across different symbols."
}
},
{
"@type": "Question",
"name": "How do minBudget and maxBudget actually filter?",
"acceptedAnswer": {
"@type": "Answer",
"text": "They're passed to Freelancer's own search as average-price bounds and applied in each project's own currency — they are not converted first. So minBudget: 500 means \"500 of whatever that project is priced in\". Use them as a coarse, cost-saving filter, then refine on budgetMin + currency."
}
},
{
"@type": "Question",
"name": "Why are budgetMin and budgetMax sometimes null?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Because the client published no budget range. budget then reads \"N/A\". Null is not zero — exclude those rows from averages rather than coercing them."
}
},
{
"@type": "Question",
"name": "Why is the poster block always \"N/A\"?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Because the active-project listing rarely exposes client identity. The block is present for shape consistency, but you should assume it's empty and not build a workflow around it."
}
},
{
"@type": "Question",
"name": "Why is postedAt sometimes 1970?",
"acceptedAnswer": {
"@type": "Answer",
"text": "That's the Unix epoch, produced when a listing carries no submit time. Treat any pre-2000 postedAt as missing rather than as a very old project."
}
},
{
"@type": "Question",
"name": "How many projects can I get per keyword?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Up to 100 — that's the schema's ceiling. For more coverage, add keywords rather than trying to raise the limit."
}
},
{
"@type": "Question",
"name": "Can I get bid counts, proposals or freelancer profiles?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No. This Actor returns the project listing itself: what the work is, what it pays and what skills it needs. Bids, proposals and profiles are out of scope."
}
},
{
"@type": "Question",
"name": "Does an aborted run keep partial results?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No. All keywords are fetched first and the whole set is written in a single push, so an aborted or timed-out run saves nothing. Keep limitPerKeyword sized so the run completes."
}
},
{
"@type": "Question",
"name": "Which delivery mode should I use?",
"acceptedAnswer": {
"@type": "Answer",
"text": "summary (the default) for one digest, chunked when the digest is long enough to trouble Notion's limits, perProject only when you want one record each — a 300-project run means 300 calls — and none for dataset-only runs."
}
},
{
"@type": "Question",
"name": "What does it cost, and what do I get on the free plan?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Usage-based: you pay for the platform usage a run consumes, not per row. It's a lightweight JSON-endpoint scrape — roughly one request per 100 projects per keyword — so the keyword count is the main multiplier. Free Apify plans return 5 projects per keyword. Pass maxTotalChargeUsd for a hard per-run ceiling."
}
}
]
}