Aviso Legal Scraper — Spain CIF, Registro Mercantil & Contacts
Pricing
from $5.00 / 1,000 per aviso legal lead returneds
Aviso Legal Scraper — Spain CIF, Registro Mercantil & Contacts
Turn Spanish company domains into verified B2B/KYB leads from each site's statutory Aviso Legal (Ley 34/2002): legal name, CIF/NIF with the official AEAT check digit, Registro Mercantil province + tomo/folio/hoja, domicilio social, email and phone.
Pricing
from $5.00 / 1,000 per aviso legal lead returneds
Rating
0.0
(0)
Developer
Scrapers Delight
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
🇪🇸 Aviso Legal Scraper — Spanish company leads with a validated CIF
Paste a list of Spanish company domains (or point this at another Actor's dataset) and get back one clean B2B/KYB lead per domain, read off each site's statutory Aviso Legal page: the legal entity name, the CIF/NIF checked against the official AEAT check-digit algorithm, the Registro Mercantil entry (provincia + tomo / folio / hoja / inscripción), the domicilio social, and a role contact email and phone — for $5 per 1,000 leads.
Why an Aviso Legal and not a directory? Because Ley 34/2002 (LSSI-CE) art. 10 obliges every commercial Spanish website to publish one. The corpus is therefore the whole Spanish web, not one directory's member list — and the data is a legally-mandated public disclosure the company published about itself.
✅ What does the Aviso Legal Scraper do?
For each domain you give it, two plain HTTP hops (no browser on the default path):
- Discovery. Fetch the homepage and collect every candidate whose
hrefor its anchor text matches the aviso-legal family (aviso legal,avís legal,nota legal,información legal,mencions legals,textos legales,legal notice…), plus a raw-HTML pass for string-literal hrefs a DOM parse misses. If nothing is linked, walk a bounded URL-guess ladder. - Resolution. Fetch each candidate, gate it on a strict statutory marker, extract the fields, score the page, and keep the best-scoring one.
Then it reads the fields off the page text with anchored patterns — never a loose regex over raw HTML — and validates the tax id locally.
The four things it does that a naive imprint scraper gets wrong
- 🎯 It never stops at the first page that loads.
tous.comlinks/us-es/legal-warning.htmlfrom its footer. That page is real, it says "Aviso Legal", and it carries a New York address and a US EIN. This Actor scores every candidate (valid CIF +3 · Registro Mercantil +2 · domicilio social +1 · locale preference as a tiebreak) and comes back with the Spanish entity —S. TOUS S.L., CIF B08332074, Registro Mercantil de Barcelona, Tomo 42.837 / Folio 89 / Hoja B-161.832, CP 08243 Manresa. - 📍 It ties the address to the company whose CIF it took. A single Aviso Legal routinely lists several entities — a Spanish parent, a foreign subsidiary, a separate data-protection contact.
tous.comwrites the parent's address as running prose ("con domicilio en Carretera de Vic…") and saves the literal words "domicilio social" for TOUS USA INC. Matching on the formal phrase alone pairs a Spanish CIF with a Rockefeller Center address. This Actor collects every address on the page and keeps the one nearest the validated tax id — the same anchor it uses for the company name. - 🔒 It refuses a page that merely contains the letters "CIF". A loose marker "recovered"
mango.com,eroski.esandmisako.comin testing — all three were SPA shells or raw CSS text, and re-extraction returned zero fields on all three. A page is accepted only if it names the statute, the Registro Mercantil or the domicilio social, or carries a tax id that passes the AEAT check digit. - 🧾 It validates the CIF, offline. The full official algorithm — NIF modulo-23 letter, NIE X/Y/Z prefix mapping, CIF double-odd-digit control with the letter/digit rules per first letter. Zero external calls. Every one of the 31 tax ids extracted in the benchmark run below passed.
📊 Measured, from real runs
Everything here is from actual runs, not estimates.
End-to-end over 50 varied Spanish company domains
Shops, insurers, industrial co-ops, logistics, telecoms, retail — datacenter proxy, concurrency 8, default settings plus the opt-in extended path ladder.
| Outcome | Domains | Share |
|---|---|---|
✅ ok — a resolved, billable lead | 32 | 64 % |
🟡 partial — page resolved, under the quality bar (free) | 2 | 4 % |
⚪ no_aviso_legal_found (free) | 7 | 14 % |
🔴 blocked by an anti-bot wall (free) | 9 | 18 % |
34 of 50 domains (68 %) resolved a verified Aviso Legal page; 32 of 50 (64 %) produced a billable lead — 50 domains in 2 min 51 s, and the run charged 32 events for 32 ok rows.
Per-field fill, over the 32 resolved leads
| Field | Fill | Field | Fill | |
|---|---|---|---|---|
legalName | 100 % (32/32) | domicilioSocial | 94 % (30/32) | |
legalForm | 100 % (32/32) | email | 69 % (22/32) | |
avisoLegalUrl | 100 % (32/32) | folio | 69 % (22/32) | |
taxId | 97 % (31/32) | registroMercantilProvincia | 69 % (22/32) | |
taxIdValid — and 31/31 passed | 97 % | phone | 69 % (22/32) | |
taxIdLegalForm (from the CIF letter) | 97 % (31/32) | tomo | 62 % (20/32) | |
province | 97 % (31/32) | hoja | 53 % (17/32) | |
postalCode | 91 % (29/32) | inscripcion | 34 % (11/32) | |
city | 84 % (27/32) | dpoEmail (LOPD address) | 25 % (8/32) |
Where the page was found
| Route | Domains |
|---|---|
| Footer / body link on the homepage | 26 |
URL-guess ladder (/aviso-legal ×4, /aviso-legal/ ×1) | 5 |
Extended ladder (/condiciones-generales) | 1 |
That last row is a real win worth knowing about: eroski.es has no /aviso-legal path and no aviso-legal link in its raw HTML, but its full legal block — EROSKI S.Coop., Barrio de San Agustín s/n, 48230 Elorrio (Bizkaia), dpo@eroski.es — sits on /condiciones-generales. Turn on Extended path ladder when coverage matters more than request count. Cost control: a domain costs the homepage fetch plus 4.0 legal-page candidates on average (measured over 40 domains; worst case 11, and maxRequestsPerDomain caps it at 12).
Transport
Sustained-load test on the winning transport (got-scraping over the Apify datacenter proxy): 30 of 31 sequential calls usable = 96.8 % — 28 first-attempt, 2 recovered on a retry with a fresh proxy IP. The single failure was one domain hammered repeatedly; in real use a buyer touches each domain once.
Measured on the escalation ladder: direct home IP 200 / 691,872 b, datacenter proxy 200 / 691,890 b (identical fields extracted), residential-ES 200 / 760,285 b. The cheapest rung already returns real data, so datacenter is the default and residential is only an override.
🧾 Output
One row per input domain.
| Field | Description |
|---|---|
domain | Registrable domain (eTLD+1) — the stable id. One domain = one row = one charge. |
website | The company homepage. |
avisoLegalUrl | The page the data came from. |
discoveryMethod | footer · guess:/aviso-legal · extended:/… · contact-page · render:… · none. |
legalName | Denominación social. |
legalForm | S.L. · S.A. · S.L.U. · S.A.U. · S.Coop. · S.Coop.V. · S.C.P. · A.I.E. · … |
taxId | CIF / NIF / NIE, normalised (A-46.581.666 → A46581666). |
taxIdType | CIF · NIF · NIE. |
taxIdValid | Official AEAT check digit. true = a real, well-formed Spanish fiscal id. |
taxIdLegalForm | Entity type decoded from the CIF's first letter (A = S.A., B = S.L., F = cooperativa, G = asociación/fundación, N = entidad extranjera, …). |
registroMercantilProvincia | The register province, resolved against the closed set of 52 (Spanish, Catalan, Basque and Galician spellings all map to one canonical name). |
tomo, folio, hoja, inscripcion | The Registro Mercantil entry. |
domicilioSocial | The registered-office line. |
postalCode, city, province | Postal address, province derived from the CP (01–52). |
email | Role contact address (info@, legal@, contacto@, lopd@…). |
dpoEmail | The dedicated data-protection address when the site publishes one (lopd@, protecciondatos@, dpo@) — a direct line to the compliance owner. |
emailMxValid | Only when Verify MX is on: does the email's domain actually accept mail? |
phone | Spanish phone, normalised to +34XXXXXXXXX. |
administrador | Administrador / representante legal — only when you enable personal names. |
status | ok · partial · no_aviso_legal_found · blocked · error · not_attempted. Only ok is ever charged. |
fetchedAt | ISO timestamp. |
emails[], phones[], allUrlsTried, candidateScore, renderedWithBrowser | Output mode Full. |
rawText | Only when Include the raw Aviso Legal text is on. |
Two dataset views ship with it: Spanish company leads (the flat lead) and Registry / KYB view (the Registro Mercantil entry plus the validated fiscal id).
⚙️ Input
Bring your domains any of five ways — they are merged, normalised and deduplicated before a single request goes out:
| Input | What it is |
|---|---|
| Company domains | ["suavinex.com", "https://www.joyeriasuarez.com", "polvillo.es/aviso-legal"] |
| Start URLs | The Apify Start-URLs shape, so the Console link-list UX and file uploads work. |
| Source dataset ID | Chain straight off a Google-Maps-Spain / Páginas Amarillas run. Pick the field with Source dataset field (default website, auto-falls back through url, domain, web, site, homepage, link, companyWebsite). |
| Domain list URL | A public .txt / .csv / .tsv for very large lists. |
| Exclude domains | Your suppression list — applied before any fetch, so an excluded domain never costs a request and can never be billed. |
Then 31 more knobs, grouped in the Console: limits & performance, network & anti-block, discovery, enrichment & data quality, filters & output. The ones worth knowing:
- Score every candidate page (on by default — leave it on) — the
tous.comfix above. - Preferred locales — used to score candidates and to try locale variants; never to rewrite a URL, because hard-forcing
/es-es/404s on joyeriasuarez.com. - Extended path ladder — the
/condiciones-generalesclass. Opt-in, because it costs extra requests per unresolved domain. - Filter by legal form (CIF first letter) —
["A"]for sociedades anónimas only,["F"]for cooperativas,["G"]for asociaciones y fundaciones. CIF-keyed prospecting, straight off the validated id. - Filter by province / postal-code prefix — Madrid + Barcelona only:
provinceFilter: ["Madrid","Barcelona"]orpostalCodeFilter: ["28","08"]. - Minimum fields for a billable lead — how many of
{taxId, legalName, email, phone}a page must yield before the row counts asokand is charged. Default 2. You set your own quality bar, and it is also the billing bar. - Render JavaScript — opt-in headless Chromium for the client-side-rendered-footer class. Set the run memory to 2048 MB when you enable it; below 1536 MB the Actor logs a warning and stays on HTTP rather than risk an out-of-memory kill.
{"domains": ["joyeriasuarez.com", "suavinex.com", "chocolatesatienza.com"],"provinceFilter": ["Bizkaia", "Alicante"],"legalFormFilter": ["B"],"minFieldsRequired": 2,"outputMode": "lead"}
💵 Pricing
Pay per event — $0.005 per resolved lead ($5 / 1,000).
- You are charged only for a row that resolved an Aviso Legal page and met your
minFieldsRequiredbar (status: ok). blocked,no_aviso_legal_found,partialanderrorrows are still delivered so you can see what happened to every domain you submitted — and they are never charged.- Rows are delivered and billed atomically (
pushData(row, event)), so a charge cap truncates delivery too. You can never be billed for a row you did not receive, and never receive a row you were not billed for. - Rows dropped by a filter, by
dedupeByTaxIdor byonlyResolvedare never pushed and never billed. - The opt-in browser fallback bills its own event,
aviso-legal-rendered, at $0.008 — it costs a full Chromium, so it is priced separately and only fires when you turn it on.
🚧 Honest limits
This is an enrichment tool, not a discovery tool. It does not find Spanish companies for you; it turns a domain list you already have into legal-entity records.
Four classes of domain do not resolve, and all four come back free. Measured on the 50-domain benchmark:
| Class | Domains in the benchmark | What happens |
|---|---|---|
| Enterprise CF/WAF | idealista.com, dynos.es, comsa.com, mahou-sanmiguel.com, cofas.es, urssa.es, batz.com, pccomponentes.com | 403 on both datacenter and residential-ES — residential is not the fix, which is why the escalation toggle is off by default. |
| Fastly proof-of-work interstitial | elganso.com | HTTP 202 instead of the page. Not solvable over plain HTTP. |
| Rate limit | kavehome.com | 429. Lower the concurrency and retry later. |
| Client-side-rendered footer | mango.com, misako.com | 200 OK, but the aviso-legal href exists nowhere in the raw HTML and there is no __NEXT_DATA__ / __NUXT__ to mine. This is what Render JavaScript is for. |
| No published Aviso Legal on a discoverable path | monbus.es, silennis.com, tallerescillero.es, casadellibro.com, espritdog.com | Try the Extended path ladder and Fall back to /contacto. |
Block behaviour is not deterministic, in both directions. Across three full benchmark passes pccomponentes.com was 403, then resolved cleanly (PC COMPONENTES Y MULTIMEDIA S.L.U., B73347494, Registro Mercantil de Murcia, Tomo 2236 / Folio 52 / Hoja MU-52949) off /pages/aviso-legal, then 403 again; cruzcampo.es and elganso.com each went the other way and resolved; eroski.es went from an unresolvable SPA shell to a clean lead via the extended ladder. So the 64 % headline is one sample, not a constant — expect a few points either way, and re-running a blocked list later costs nothing, because blocked rows are free.
Extraction is best-effort per field. Aviso Legal pages are free-form prose on thousands of unrelated stacks; a field the page does not publish comes back null. The fill table above is the honest distribution, not a promise. city in particular is a secondary field parsed out of an address line and can keep a trailing word on unusual layouts.
An empty address field is deliberate. domicilioSocial must look like an address — a street-type word, a Spanish postal code, or a street number — before it is returned. Spanish legal notices are full of the word "domicilio" in boilerplate that is not an address at all ("los tribunales del domicilio del consumidor", or a site quoting LSSI art. 10's own wording back at you), and three domains in the 50-domain benchmark used to return that sentence fragment as their registered office. Where a page prints a real address but never uses the word — "registered office at", "con sede en", or just the address sitting beside the CIF — the postal code is used as the anchor instead, which is what carries this field to 94 %.
taxIdValid proves the id is well-formed, not that the company is trading. The AEAT check digit is arithmetic, not a registry lookup. For live registry status you want a BORME / Registro Mercantil source — that is a different data path and a separate Actor.
No SMTP. emailMxValid says the email's domain accepts mail; it does not say the mailbox exists. Nothing on this platform can say that honestly.
A slow domain cannot silently eat your run. One domain behind a flaky wall can spend maxRequestsPerDomain × maxRetriesPerRequest × requestTimeoutSecs before giving up — measured, eight identical 3-domain runs on build 0.1.5 took 7.7 – 136.3 s, and the 136.3 s run returned exactly the same three rows as the 7.7 s one. Three clocks now bound that: each request is cancelled at its own requestTimeoutSecs (measured: a stalled site ran 22.0 s against a 20 s timeout the HTTP client failed to enforce, and only the cancel stopped it), each domain gets 60 s of wall clock to widen its search before the Actor stops enlarging it, and the run stops starting new domains at 80 % of the run's own timeout, delivering the remainder as not_attempted (free) with a warning naming the count. Re-measured on 0.1.8, same input, 14 runs: median ~10 s, worst 64.8 s. Raise the run timeout or split the list to finish not_attempted domains.
⚖️ Legal & fair use
The Aviso Legal is a statutory public disclosure, mandated by Ley 34/2002 de Servicios de la Sociedad de la Información y de Comercio Electrónico (LSSI-CE), artículo 10 — the company itself is legally required to publish exactly these identifying details, in a permanent, freely and directly accessible form. That makes it the most defensible starting point there is for Spanish B2B prospecting: no login, no private profile, no paywall.
- robots.txt is per-domain. The Respect robots.txt toggle is exposed so you can enforce it on your runs; check the specific domains you care about.
- Personal data is OFF by default.
administrador/ representante legal names (includePersonalNames) andnombre.apellido@addresses (includePersonalEmails) are both opt-in. Turning them on makes you the data controller for those fields under the RGPD/LOPDGDD. - Outreach compliance is yours. Spanish commercial email is governed by LSSI-CE art. 21 and the RGPD; you are responsible for lawful basis, opt-out and record-keeping when you contact anyone from this data.
- You are responsible for complying with each site's Terms of Service.