# Habitissimo Spain Contractors Scraper — Phones & Addresses (`scrapersdelight/habitissimo-spain-contractors-scraper`) Actor

Spanish reformas & trade companies from habitissimo.es: each company's own phone numbers (mobile + landline, E.164), trades, provinces served, rating and reviews, plus street address, postal code, city, description and published rates. Filter by trade + province/city. $4 per 1,000 companies.

- **URL**: https://apify.com/scrapersdelight/habitissimo-spain-contractors-scraper.md
- **Developed by:** [Scrapers Delight](https://apify.com/scrapersdelight) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$4.00 / 1,000 per company returneds

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

## Habitissimo Spain Contractors Scraper — Phones & Addresses

Export Spanish **reformas and trade companies** from the [habitissimo.es](https://www.habitissimo.es/empresas) professional directory — electricians, plumbers, painters, builders, bathroom and kitchen fitters, solar installers and 80 more trades — with **each company's own published phone numbers**, its trades, the provinces it serves, rating and review count, and (profile pass) **street address, postal code, city**, description and published hourly / call-out rates.

**One row = one company.** A company found by several of your searches is delivered and charged once.

**$4 per 1,000 companies** ($0.004 per company). No start fee, no proxy cost, nothing charged for filtered-out companies, duplicates, or pages the site could not serve.

### Who uses this

- Building-materials distributors and manufacturer reps building a trade-installer call list by province
- Reformas lead-generation agencies and marketplaces sourcing contractors
- Home-insurance, home-warranty and assistance companies recruiting repair networks
- Iberian B2B telesales / dialer teams (phones are delivered in E.164, split mobile vs landline)

### What you get — measured on real runs (2026-09-23)

Fill measured on **3,342 companies across three frames** — (A) fontaneros + pintores × Valencia + Sevilla, 618 companies; (B) reformas-viviendas + albañiles × Barcelona + Málaga, 1,766; (C) reformas-baños + fontaneros × Madrid, 958 — every company in each search, profile pass on. A fourth frame, all **3,590** electricians in Spain (listing fields only), measured the phone and coverage numbers.

| Field | Fill | Notes |
|---|---|---|
| `phone` / `phoneE164` | **99.8–100%** (3,587 of 3,590 electricians) | The company's **own** number as printed on its profile data, never Habitissimo's call-tracking number |
| `phoneType` | 100% of phones | `mobile` 89–94% · `landline` 6–11% |
| `phones` / `phonesE164` | 15–23% have 2+ numbers | every distinct number the company publishes |
| `address`, `postalCode`, `city`, `province` | **99.9–100%** | from the profile's "Detalles de contacto" |
| `street` | 62–67% | the rest publish only postal code + city (a street of "." or "-" is returned as `null`) |
| `trades`, `servicesOffered`, `provincesServed` | 100% | |
| `description` | 65–73% | free text from "Información sobre …"; punctuation-only placeholders are `null` |
| `rating` | 47–51% | `null` when the company has no reviews (the site shows 0) |
| `reviewCount` | 100% | 0 when none |
| `experienceYears` | 40–48% | |
| `memberSinceYear` | 100% | "En habitissimo desde …" |
| `hourlyRateEur`, `callOutFeeEur` (+ 3 emergency rates) | 12–18% | only when the company publishes rates |
| `latestReview` | 16–25% | the review text shown on the listing card |
| `website`, `facebookUrl`, `instagramUrl` | **0–1%** | Habitissimo shows a website link **only on top-tier (membership 10) profiles** — see *Honest limits* |

**Coverage:** Habitissimo states a total for every search ("Encuentra entre 3.592 profesionales"). Measured unique companies vs that stated total: electricians Spain 3,590 / 3,592 (99.9%); fontaneros Valencia 153/153; pintores Valencia 321/321; reformas-baños Madrid 744/744; reformas-viviendas Barcelona 1,186/1,188; fontaneros Madrid 364/365; pintores Sevilla 160/162 (the lowest). Every run writes these numbers to the `RUN_SUMMARY` record.

### Input

| Field | Default | What it does |
|---|---|---|
| `trades` | `["electricistas"]` | Directory slugs from `habitissimo.es/empresas/<slug>`: 85 trades (`electricistas`, `fontaneros`, `pintores`, `albaniles`, `reformas-banos`, `reformas-cocinas`, `reformas-viviendas`, `carpinteros`, `cerrajeros`, `placas-solares`, `aire-acondicionado`, `tejados`, …) or 9 whole categories (`reformas`, `obras-menores`, `instaladores`, `construccion`, `mantenimiento`, `tecnicos`, `mudanzas`, `tiendas`, `comercializadoras`). "Reformas baños" is normalised to `reformas-banos`. |
| `locations` | `["madrid"]` | A province (`madrid`, `barcelona`, `valencia`, `illes-balears`, … 53 in total) or a city inside it (`madrid/getafe`). Empty = all of Spain. Each trade is searched once per location. |
| `includeProfileDetails` | `true` | Opens each company's profile for address, postal code, city, description, services, rates, member-since and profile dates. Off = listing fields only; same price per row. |
| `requirePhone` | `false` | Skip companies with no phone (never charged). |
| `minRating` / `minReviews` | `0` | Keep only companies rated at least X / with at least N reviews (never charged for the rest). |
| `maxResults` | `75` | Stop after this many companies. `0` = no limit. |
| `maxPagesPerSearch` | `0` | Limit listing depth per search (10 companies per page). `0` = every page. |
| `concurrency` | `6` | Parallel requests. |
| `requestTimeoutSecs` | `30` | Hard deadline per request; slow requests are retried. |
| `proxyConfiguration` | off | Not needed — the site answers Apify directly. If a proxy you choose cannot be set up, the run continues without one. |

Example — every plumber and electrician in Valencia and Alicante with at least 5 reviews:

```json
{
  "trades": ["fontaneros", "electricistas"],
  "locations": ["valencia", "alicante"],
  "minReviews": 5,
  "maxResults": 0
}
```

### Output — a real row (run vpUC6mrKDfNbI1NMi, 2026-09-23)

```json
{
  "companyId": 486613,
  "slug": "eonia",
  "name": "EONIA ENERGY",
  "phone": "668594824",
  "phoneE164": "+34668594824",
  "phoneType": "mobile",
  "phones": ["668594824", "938415188"],
  "phonesE164": ["+34668594824", "+34938415188"],
  "phoneHiddenByBusiness": false,
  "website": null,
  "facebookUrl": null,
  "instagramUrl": null,
  "address": "Sant Valeria 111, 08186, Barcelona, Lliçà d'Amunt",
  "street": "Sant Valeria 111",
  "postalCode": "08186",
  "city": "Lliçà d'Amunt",
  "province": "Barcelona",
  "provincesServed": ["Barcelona", "Girona"],
  "primaryTrade": "Electricistas",
  "primaryTradeSlug": "electricistas",
  "trades": ["Electricistas"],
  "servicesOffered": ["Electricistas", "Aire Acondicionado", "Aerotermia", "Alta De Suministros", "Placas Solares"],
  "rating": 4.8,
  "reviewCount": 21,
  "latestReview": "Han sido rápidos en la detección de la avería y eficaces en la solución. Nos han dado todo tipo de detalles de lo que iban a hacer con una gran amabilidad. Súper recomendables!",
  "description": "Electricidad, eficiencia energética y energías renovables.",
  "experienceYears": 10,
  "memberSinceYear": 2023,
  "hourlyRateEur": 35,
  "callOutFeeEur": 35,
  "emergencyHourlyRateDayEur": 75,
  "emergencyHourlyRateNightEur": 100,
  "emergencyCallOutFeeEur": 35,
  "membershipLevel": 5,
  "hasWarranty": false,
  "hasPremiumWarranty": false,
  "hasFreelanceVerification": false,
  "isNewOnHabitissimo": false,
  "photoCount": 15,
  "logoUrl": "https://es.habcdn.com/photos/business/thumbnail/img-20240311-085454-3626667.jpg",
  "profileUrl": "https://www.habitissimo.es/pro/eonia",
  "profileCreatedAt": "2023-10-20 01:46:00",
  "profileUpdatedAt": "2026-09-22 07:04:03",
  "profileDetails": true,
  "foundVia": ["https://www.habitissimo.es/empresas/electricistas/barcelona"],
  "listingPosition": 1,
  "scrapedAt": "2026-09-23T05:03:40.865Z"
}
```

On the website this company's **"Llamar" button dials 936178750** — a Habitissimo call-tracking number. This actor returns the company's own lines (668594824, 938415188) instead.

#### Field reference

- `companyId`, `slug`, `profileUrl` — Habitissimo's own id and profile page. Dedupe key.
- `phone`, `phoneE164`, `phoneType` — the first of the company's own numbers; `phones` / `phonesE164` — all of them, distinct. E.164 is pure reformatting (`+34` + the 9 national digits); numbers that are not 9-digit Spanish numbers are never "completed" (2 six-digit fragments in 3,590 electricians were left out).
- `phoneHiddenByBusiness` — `true` if the company switched its phone to hidden; then no phone is returned (0 of 6,932 companies measured had it hidden on .es).
- `address`, `street`, `postalCode`, `city`, `province` — as published; split right-to-left (city, province, CP, street).
- `provincesServed` — provinces the company says it works in; `trades` — trades on its listing card; `servicesOffered` — the full "Servicios que ofrece" list on its profile.
- `rating` (0–5, `null` without reviews), `reviewCount`, `latestReview`.
- `hourlyRateEur`, `callOutFeeEur`, `emergencyHourlyRateDayEur` (08–19h), `emergencyHourlyRateNightEur` (19–08h), `emergencyCallOutFeeEur` — published tariffs, € as numbers.
- `membershipLevel` — Habitissimo's own plan level for the profile as served (0 on most profiles; 5 and 10 observed).
- `hasWarranty`, `hasPremiumWarranty`, `hasFreelanceVerification`, `isNewOnHabitissimo`, `photoCount`, `logoUrl`, `experienceYears`, `memberSinceYear`, `profileCreatedAt`, `profileUpdatedAt`.
- `profileDetails` — `true` when the profile page was read; `false` when you turned the profile pass off or the profile could not be read (reported in `RUN_SUMMARY`).
- `foundVia` — the search that first found the company; `listingPosition` — its slot in that listing.

### How it works — and the traps it handles

- **The visible "Llamar" button is a call-tracking number.** Featured cards on the listing render `tel:` buttons whose numbers the page itself calls `managedNumbers` — Habitissimo's forwarding lines. The page's own data carries the company's published numbers separately; this actor returns only those, only when the company's `phone_business_visible` switch is on, and **fails the run** if any tracking number seen in the run ever reaches the output (0 leaked across 7,000+ companies measured). A number shared by 5+ different companies would be withheld as a shared line (the most measured was 2 — the same owner's duplicate accounts).
- **Past the last page is not empty.** `/empresas/electricistas/361` answers 200 with ten cards from a different, wider listing (stated total 7,976). The actor stops at the stated last page and rejects any page whose stated total disagrees with page 1's.
- **The site's backend replicas disagree.** The same listing states 3,571–3,592 companies depending on which server answers, which shifts pages by a few positions: a naive single pass over the electricians listing measured 3,468–3,541 unique companies. Pages served by an off-count replica are re-read (13 re-reads on the full electricians run), which brought coverage to 3,590 / 3,592.
- **HTTP 200 with a block page** is treated as a failed request and retried, never as "no companies". If more than 20% of pages or profiles fail after retries, the run stops and says so rather than shipping a partial list.

### Pricing

Pay per event: **$0.004 per company delivered** ($4 per 1,000). A run with the default input (`maxResults` 75) costs at most $0.30. Filtered-out companies, duplicates across your searches and unreadable pages are never charged. If you set a maximum charge for the run, the actor stops delivering exactly at your budget.

### Data limits

- **No e-mail.** Habitissimo does not publish company e-mails; contact goes through its own quote form.
- **Website: almost never.** The profile shows a "Página web" link only for top-tier members (every membership-10 profile in our measured runs had one; 0 of 3,340 lower-tier profiles did). Where that link points back into Habitissimo's own hosted mini-site (`empresas.habitissimo.es/pro/…`) it is **not** returned as the company website.
- **Coverage is 98.8–100% of the stated total, not always 100%.** The site's own count wobbles by up to ~20 between replicas during a run; a company that joins or leaves mid-run can be missed. `RUN_SUMMARY.searches[].coverageOfSiteTotal` gives the measured figure for your run.
- **Many companies are sole traders (autónomos).** A row can carry a person's name and personal mobile number as they published it on their public business profile.
- **Spain only.** habitissimo.com.mx runs on a different platform whose pages carry no phone numbers; habitissimo.pt marks phones hidden. Neither is supported.
- `experienceYears`, rates and `description` are whatever the company chose to publish; many leave them blank.

### Source

Data is read from public pages of habitissimo.es: the `/empresas` directory listings and `/pro/<company>` profiles, using the path pagination the site links (`/empresas/electricistas/2`).

# Actor input Schema

## `trades` (type: `array`):

Directory slugs as they appear in habitissimo.es/empresas/<slug>. Trades: electricistas, fontaneros, pintores, albaniles, reformas-banos, reformas-cocinas, reformas-viviendas, carpinteros, cerrajeros, placas-solares, aire-acondicionado, tejados, … (85 in total). Whole categories: reformas, obras-menores, instaladores, construccion, mantenimiento, tecnicos, mudanzas, tiendas, comercializadoras. Accents and spaces are normalised ("Reformas baños" → reformas-banos).

## `locations` (type: `array`):

Narrow each trade to a province ("madrid", "barcelona", "valencia", "illes-balears", …) or a city inside it ("madrid/getafe", "barcelona/badalona"). Each trade is searched once per location. Leave empty to search all of Spain. A company listed in several searches is delivered and charged once.

## `includeProfileDetails` (type: `boolean`):

Adds street address, postal code, city, province, website, Facebook, Instagram, full description, services offered, published hourly / call-out rates, member-since year and profile dates — one extra page per company. Off = listing fields only (name, phones, trades, provinces served, rating, reviews): faster, same price per row.

## `requirePhone` (type: `boolean`):

Skip companies that publish no phone (measured: 2 of 3,770 electricians). Skipped companies are never charged.

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

Keep only companies rated at least this (companies with no reviews have no rating and are skipped when this is above 0). Skipped companies are never charged.

## `minReviews` (type: `integer`):

Keep only companies with at least this many customer reviews on Habitissimo. Skipped companies are never charged.

## `maxResults` (type: `integer`):

Stop after delivering this many companies (cost guard). Set 0 for no limit — every company in every search.

## `maxPagesPerSearch` (type: `integer`):

Limit how deep each trade/location search goes (10 companies per page). 0 = every page the site states.

## `concurrency` (type: `integer`):

How many pages are fetched at once. The default is gentle on the site and fast enough for thousands of companies.

## `requestTimeoutSecs` (type: `integer`):

Hard deadline for a single page request; a slow request is retried.

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

Not needed: habitissimo.es answers Apify's servers directly (the default, and the cheapest). If you do pick an Apify proxy, choose the RESIDENTIAL group. If a proxy cannot be set up the run continues without one.

## Actor input object example

```json
{
  "trades": [
    "electricistas"
  ],
  "locations": [
    "madrid"
  ],
  "includeProfileDetails": true,
  "requirePhone": false,
  "minRating": 0,
  "minReviews": 0,
  "maxResults": 20,
  "maxPagesPerSearch": 0,
  "concurrency": 6,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `companies` (type: `string`):

The dataset of scraped habitissimo.es companies (one item per company).

## `runSummary` (type: `string`):

Measured totals: site-stated vs unique companies per search, per-field fill, phone audit, what was not charged and why.

# 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 = {
    "trades": [
        "electricistas"
    ],
    "locations": [
        "madrid"
    ],
    "includeProfileDetails": true,
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/habitissimo-spain-contractors-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 = {
    "trades": ["electricistas"],
    "locations": ["madrid"],
    "includeProfileDetails": True,
    "maxResults": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("scrapersdelight/habitissimo-spain-contractors-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 '{
  "trades": [
    "electricistas"
  ],
  "locations": [
    "madrid"
  ],
  "includeProfileDetails": true,
  "maxResults": 20
}' |
apify call scrapersdelight/habitissimo-spain-contractors-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapersdelight/habitissimo-spain-contractors-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/lGk9iC4NDbUhl3cJM/builds/I56aOpiEtUJCnxBPJ/openapi.json
