Benchmarking contractor rates across Western Europe is messy because developer talent pools are fragmented by country-specific domains. A data engineer tracking daily rates for Python developers across France, Germany, and Spain often has to deal with localized domain variants (malt.fr, malt.de, malt.es), varying rating distributions, and anti-scraping defenses that immediately flag requests from cloud datacenters.
The Malt Freelancers Scraper extracts structured contractor profiles directly from Malt's regional marketplaces without requiring active platform sessions, credentials, or browser session tokens.
How Malt Handles Search and Rate Data
Malt operates 6 distinct marketplace domains: malt.com (Global/English), malt.fr (France), malt.de (Germany), malt.es (Spain), malt.be (Belgium), and malt.nl (Netherlands). While the underlying platform architecture is shared, localized talent pools index separately, and pricing norms vary significantly by region.
When extracting freelancer data, the actor operates in two distinct operational modes via the mode parameter:
-
searchFreelancers: Executes a skill or keyword query across a designated regional market, with optional city-level location filters. -
byProfileUrls: Takes an array of specific profile links and extracts full profile schemas.
Malt sits behind Cloudflare Bot Management, which blocks datacenter IP ranges. To bypass this, the actor relies on residential IP routing (pre-configured with German exit nodes) to fetch HTML payloads without encountering automated challenge pages.
Output Schema Structure
The scraper returns clean JSON records. Instead of populating missing data with null, absent values are omitted from the object payload. A standard record returns the following fields:
{
"profileId": "johndoe",
"name": "John Doe",
"profileUrl": "https://www.malt.fr/profile/johndoe",
"headline": "Senior Python & Data Engineering Freelancer",
"skills": ["Python", "Django", "PostgreSQL", "AWS"],
"location": "Paris",
"dailyRateEur": 650,
"avgRating": 4.9,
"reviewCount": 12,
"experienceYears": 8,
"verified": true,
"market": "fr",
"recordType": "freelancer",
"scrapedAt": "2026-05-15T10:30:00+00:00"
}
The verified field tracks whether the contractor holds Malt's verified status (labeled as "Supermalter" in select regional interfaces), which serves as an indicator of profile activity and completed contracts.
Configuring Searches with Regional Filtering
To run targeted talent extraction or compensation analysis, you construct JSON input payloads that define the geographic scope and freelancer qualification thresholds.
Key input properties include:
-
searchQuery: The primary target keyword or skill string (such asreact,data analyst, orpython developer). -
market: Specifies the target marketplace domain (fr,de,es,be,nl, orcom). -
location: Refines the search to a specific metropolitan area (such asBerlinorParis). -
minRatingandminReviews: Filter out unrated or low-rated profiles. Profiles with no rating data pass through by default to prevent dropping newly registered talent. -
maxItems: Sets an upper boundary on output count (up to 5,000 items).
Example: Extracting Python Freelancers in Paris
To gather rate distributions for Python contractors in France with a verified client history, configure the actor as follows:
{
"mode": "searchFreelancers",
"searchQuery": "python developer",
"location": "Paris",
"market": "fr",
"minRating": 4.5,
"minReviews": 2,
"maxItems": 50
}
Example: Direct Profile URL Enrichment
If you already have a target list of profile slugs from earlier runs or internal tracking sheets, switch mode to byProfileUrls:
{
"mode": "byProfileUrls",
"profileUrls": [
"https://www.malt.fr/profile/johndoe",
"https://www.malt.de/profile/jane-smith"
]
}
Running the Scraper via the Python Client
You can trigger runs programmatically and pull the dataset directly into a pipeline using the Apify Python SDK.
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run_input = {
"mode": "searchFreelancers",
"searchQuery": "data engineer",
"market": "de",
"location": "Berlin",
"maxItems": 25
}
# Run the actor and wait for execution to complete
run = client.actor("crawlerbros/malt-freelancers-scraper").call(run_input=run_input)
# Fetch dataset items
dataset_items = client.dataset(run["defaultDatasetId"]).list_items().items
for freelancer in dataset_items:
rate = freelancer.get("dailyRateEur", "N/A")
name = freelancer.get("name")
skills = ", ".join(freelancer.get("skills", []))
print(f"{name} | Daily Rate: €{rate} | Skills: {skills}")
Execution Cost Breakdown
Billing for this actor operates on a pay-per-event pricing model. Charges are strictly event-driven:
-
Actor Start (
apify-actor-start): $0.005 per GB of memory allocated to the run, charged once when the run initializes. -
Dataset Result (
result): Billed per item returned in the default dataset.- FREE tier: $0.005 per result
- BRONZE tier: $0.00433 per result
- SILVER tier: $0.00367 per result
- GOLD tier: $0.003 per result
- PLATINUM tier: $0.003 per result
- DIAMOND tier: $0.003 per result
Extracting 100 freelancer profiles on the FREE tier incurs $0.005 for the run start (assuming 1 GB allocation) plus $0.50 for the 100 result events, totaling $0.505.
Architecture Limitations
Malt's search results pages embed approximately 24 profile links per single search query response. Because of this UI limitation, running a single broad searchQuery without varying keywords, markets, or locations will hit a ceiling on unique profile discovery. To build larger market indexes, break your pipeline into multiple granular queries distributed across specific skill combinations and city locations.
Everything above runs on Malt Freelancers Scraper. Start with a small input and a low result limit before you widen the run -- the output shape is easier to check that way.
Prices quoted above are this Actor's published pay-per-event rates on the Apify Store, read from the Apify platform API on 2026-09-11. Check the Actor page for the current rates.
Top comments (0)