Company Data Scraper | Emails, Phones and Tech Stack avatar

Company Data Scraper | Emails, Phones and Tech Stack

Pricing

from $2.04 / 1,000 companies

Go to Apify Store
Company Data Scraper | Emails, Phones and Tech Stack

Company Data Scraper | Emails, Phones and Tech Stack

Company Data Scraper turns any domain list into structured company records: legal name, postal address, emails, phones, LinkedIn and 14 other social links, registration numbers, tech stack, and domain infrastructure. Built for sales prospecting, lead enrichment, KYC checks, and B2B research.

Pricing

from $2.04 / 1,000 companies

Rating

0.0

(0)

Developer

SilentFlow

SilentFlow

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Share

Company Data Scraper

Turn a list of domains into complete company records: identity, contacts, postal address, legal registration, technology stack and domain infrastructure, one row per company. 30 domains resolved in 7 minutes 29 seconds across France, Germany, the UK, the US, Spain and Italy.

How it works

How it works

  1. You submit a list of domains or website URLs. A bare domain and a full URL both work, the domain is extracted automatically, and duplicates in the list are combined into a single row.
  2. Each domain is read for the pages that actually carry company data. The homepage, plus the handful of pages a real visitor would open: about, contact, legal notice, pricing. The structured data a company already publishes about itself is parsed straight from those pages, rather than the scraper guessing what to look for.
  3. One consolidated row comes back per domain. Company identity, contacts, postal address, legal registration, 15 social profiles, a detected technology stack and domain infrastructure, all in the same record, with a status field explaining what happened on the domains that could not be fully resolved.

โœจ Why teams choose this over other company data scrapers

Tired of a contact scraper that hands you an email address and calls it a day? Sick of stitching four separate tools together just to confirm a company is even real? Done paying twice for the same domain because the output arrives one row per page and you dedupe it yourself?

  • ๐Ÿข Get the company, not just its inbox. Name, legal name, description, logo, founding year, industry code and headcount band all come back in the same row as the contacts, not behind a separate lookup.
  • ๐Ÿ“ฎ A postal address, not a city guess. Street, postal code, region, country and country code, pulled from the pages that actually carry them.
  • ๐Ÿงพ A legal registration number you can trust. Checksum-validated offline and checked against public registries where they exist, with the exact page it was found on attached. If a number does not validate, the row says so instead of asserting it.
  • ๐Ÿ’ป A technology stack in the same row as the contacts. Checked against 6,633 known technologies and returned with a confidence score for each match.
  • ๐ŸŒ Domain infrastructure done properly. Normalized registration dates on every TLD, a derived email and DNS provider instead of raw records to parse yourself, an email security read, and the sibling domains a certificate reveals.
  • ๐Ÿ”— One row per company, joinable on what you sent. The exact string you submitted comes back untouched as inputUrl, so the output snaps straight onto your source list without a join key you have to invent.
  • โœ… Every input gets a row. A domain that is dead, parked, or refuses to answer still produces a row, with a status explaining which, so your list stays complete and an empty cell is never ambiguous.
  • ๐Ÿ” Every fact carries where it came from. Every contact and every identifier includes the URL it was found on, so anything can be checked by hand in one click.
  • ๐Ÿ”“ No account, no API key, nothing to install. Point it at a domain list and run it.

๐ŸŽฏ What you can do with company data

TeamWhat they build
Sales opsTurn an exported prospect list into CRM-ready rows with legal name, postal address and headcount band, no manual dedup across pages
RevOps / data teamsSegment a market by technology, email provider, company age or headcount band before a campaign goes out
Compliance / procurementConfirm a supplier or partner is a registered, active legal entity, with the registry source attached for the file
Automation buildersWire a fixed 31-key schema into n8n, Make or Zapier once, and stop re-mapping the workflow every time a run comes back different
Growth teamsEnrich inbound signups by the domain they signed up with, and route the lead by headcount or industry code
Market researchersBuild a territory list from a conference exhibitor roster, ranked by employee range and industry
AgenciesTurn a client's competitor list into a side-by-side sheet: technology stack, social presence, and domain age, in one table

๐Ÿ“ฅ Input parameters

ParameterTypeDefaultDescription
domainsarray of strings, required-Domains or website URLs to look up, for example stripe.com or https://www.qonto.com/pricing. The domain is extracted automatically.
maxItemsinteger100Maximum number of company rows this run returns (1 to 10,000).
debugModebooleanfalseTurns on detailed logs, useful when investigating a specific run.

๐Ÿ“Š Output data

A resolved domain

{
"inputUrl": "brightloop.io",
"domain": "brightloop.io",
"finalUrl": "https://www.brightloop.io/",
"httpStatus": 200,
"status": "ok",
"isLive": true,
"redirectChain": ["https://brightloop.io/", "https://www.brightloop.io/"],
"language": "en",
"company": {
"name": "Brightloop",
"legalName": "Brightloop SAS",
"description": "Brightloop builds expense management software for finance teams.",
"tagline": "Spend management, simplified",
"logo": "https://www.brightloop.io/logo.png",
"foundedYear": 2019,
"industry": "Financial Software",
"employeeRange": "51-200",
"sourceUrl": "https://www.brightloop.io/about"
},
"contacts": {
"emails": [
{"address": "contact@brightloop.io", "isRole": true, "mxValid": true, "sourceUrl": "https://www.brightloop.io/contact"}
],
"phones": [
{"raw": "+33 1 84 88 32 10", "e164": "+33184883210", "country": "FR", "sourceUrl": "https://www.brightloop.io/contact"}
],
"contactPageUrl": "https://www.brightloop.io/contact"
},
"address": {
"raw": "14 Rue de la Paix, 75002 Paris, France",
"street": "14 Rue de la Paix",
"postalCode": "75002",
"city": "Paris",
"region": "Ile-de-France",
"country": "France",
"countryCode": "FR",
"confidence": "high",
"sourceUrl": "https://www.brightloop.io/legal-notice"
},
"registration": {
"ids": [
{"type": "SIREN", "value": "812345678", "checkable": true, "checksumValid": true, "verified": true, "sourceUrl": "https://www.brightloop.io/legal-notice"}
],
"legalName": "Brightloop SAS",
"status": "active",
"incorporationDate": "2019-03-12",
"naceCode": "6202A",
"officers": [{"name": "Claire Dubois", "role": "President"}],
"identityConfidence": "high",
"attributionUncertain": false
},
"social": {
"linkedin": "https://www.linkedin.com/company/brightloop",
"twitter": "https://twitter.com/brightloophq",
"facebook": "",
"instagram": "https://www.instagram.com/brightloophq/",
"youtube": "",
"tiktok": "",
"github": "https://github.com/brightloop",
"pinterest": "",
"threads": "",
"telegram": "",
"whatsapp": "",
"discord": "",
"reddit": "",
"snapchat": "",
"medium": "https://medium.com/brightloop"
},
"tech": {
"count": 14,
"technologies": [
{"name": "React", "categories": ["JavaScript Framework"], "version": "18.2", "confidence": 100},
{"name": "Segment", "categories": ["Analytics"], "version": "", "confidence": 95}
],
"categoriesSummary": {"JavaScript Framework": 1, "Analytics": 2, "CDN": 1},
"cms": "Webflow",
"ecommerce": "",
"cdn": "Fastly",
"framework": "React",
"analytics": ["Google Analytics", "Segment"]
},
"domainInfo": {
"registrar": "OVH SAS",
"createdAt": "2019-02-08T00:00:00Z",
"expiresAt": "2027-02-08T00:00:00Z",
"ageDays": 2657,
"nameservers": ["ns1.ovh.net", "ns2.ovh.net"],
"ips": ["51.68.24.10"],
"mx": ["aspmx.l.google.com"],
"emailProvider": "Google Workspace",
"dnsProvider": "OVH",
"spf": "v=spf1 include:_spf.google.com ~all",
"dmarcPolicy": "quarantine",
"dkimPresent": true,
"relatedDomains": ["app.brightloop.io", "brightloop.fr"]
},
"meta": {
"pagesFetched": 5,
"fetchProfile": "direct",
"warnings": []
},
"companyName": "Brightloop",
"email": "contact@brightloop.io",
"phone": "+33184883210",
"city": "Paris",
"country": "France",
"registrationId": "812345678",
"linkedin": "https://www.linkedin.com/company/brightloop",
"employeeRange": "51-200",
"industry": "Financial Software",
"techCount": 14,
"cms": "Webflow",
"emailProvider": "Google Workspace",
"domainAge": 2657,
"identityConfidence": "high",
"scrapedAt": "2026-08-17T09:14:22Z"
}

This example trims the technologies list for readability, and leaves out the certificate issuer and validity fields that also live inside domainInfo. See Data fields below for the full, exact count.

A domain that could not be reached

{
"inputUrl": "a-domain-that-recently-shut-down.com",
"domain": "a-domain-that-recently-shut-down.com",
"finalUrl": "",
"httpStatus": 0,
"status": "unreachable",
"isLive": false,
"redirectChain": [],
"language": "",
"company": {"name": "", "legalName": "", "description": "", "tagline": "", "logo": "", "foundedYear": 0, "industry": "", "employeeRange": "", "sourceUrl": ""},
"contacts": {"emails": [], "phones": [], "contactPageUrl": ""},
"address": {"raw": "", "street": "", "postalCode": "", "city": "", "region": "", "country": "", "countryCode": "", "confidence": "none", "sourceUrl": ""},
"registration": {"ids": [], "legalName": "", "status": "", "incorporationDate": "", "naceCode": "", "officers": [], "identityConfidence": "none", "attributionUncertain": false},
"social": {"linkedin": "", "twitter": "", "facebook": "", "instagram": "", "youtube": "", "tiktok": "", "github": "", "pinterest": "", "threads": "", "telegram": "", "whatsapp": "", "discord": "", "reddit": "", "snapchat": "", "medium": ""},
"tech": {"count": 0, "technologies": [], "categoriesSummary": {}, "cms": "", "ecommerce": "", "cdn": "", "framework": "", "analytics": []},
"domainInfo": {"registrar": "", "createdAt": "", "expiresAt": "", "ageDays": 0, "nameservers": [], "ips": [], "mx": [], "emailProvider": "", "dnsProvider": "", "spf": "", "dmarcPolicy": "", "dkimPresent": false, "relatedDomains": []},
"meta": {"pagesFetched": 0, "fetchProfile": "", "warnings": ["dns lookup failed"]},
"companyName": "",
"email": "",
"phone": "",
"city": "",
"country": "",
"registrationId": "",
"linkedin": "",
"employeeRange": "",
"industry": "",
"techCount": 0,
"cms": "",
"emailProvider": "",
"domainAge": 0,
"identityConfidence": "none",
"scrapedAt": "2026-08-17T09:14:30Z"
}

Every key is still present. Nothing is missing from the shape, only from the values, and status says exactly why.

๐Ÿ—‚๏ธ Data fields

Every row carries the same 31 top-level keys, whether the domain resolved or not. Fourteen of them are flat columns built for the table view and CSV export: companyName, email, phone, city, country, registrationId, linkedin, employeeRange, industry, techCount, cms, emailProvider, domainAge, identityConfidence. The remaining top-level keys are row metadata (inputUrl, domain, finalUrl, httpStatus, status, isLive, redirectChain, language, scrapedAt) and eight nested blocks:

BlockFieldsWhat is inside
company9name, legal name, description, tagline, logo, founding year, industry code, headcount band, source URL
contacts3emails[] (4 fields each: address, role flag, mail-server validity, source URL), phones[] (4 fields each: raw text, E.164 format, country, source URL), contact page URL
address9raw text, street, postal code, city, region, country, country code, confidence, source URL
registration8ids[] (6 fields each: type, value, whether the type can be checked at all, checksum validity, registry confirmation, source URL), legal name, status, incorporation date, industry classification code, officers[] (2 fields each: name, role), identity confidence, an attribution-uncertain flag
social15one profile URL field per platform: LinkedIn, X/Twitter, Facebook, Instagram, YouTube, TikTok, GitHub, Pinterest, Threads, Telegram, WhatsApp, Discord, Reddit, Snapchat, Medium
tech8technology count, technologies[] (4 fields each: name, categories, version, confidence score), a category summary, detected CMS, ecommerce platform, CDN, framework, analytics tools
domainInfo16registrar, created date, expiry date, age in days, nameservers, IP addresses, MX records, derived email provider, derived DNS provider, SPF record, DMARC policy, DKIM presence, certificate issuer, certificate issued date, certificate expiry date, and the sibling domains found in the certificate
meta3pages read, an internal note on how the domain answered, and any warnings raised during the run

status is one of ok, partial, blocked, unreachable, or parked. blocked means the server answered and declined to serve the page; unreachable means the domain could not be read at all, whether nothing answered or the answer was a server error. identityConfidence is one of high, medium, low, or none, and it is the field to filter on: a high-confidence company can still have an empty registrationId if the site never published one. The technology engine behind tech carries 6,633 technologies.

inputUrl is preserved exactly as submitted, so it is the join key back to your source list even when domain has been normalized. registrationId in the flat column carries an identifier when it passed a checksum, or when its type has no checksum to pass and exactly one candidate was found on the site. Everything else stays in registration.ids with the page it came from: a number that failed its checksum, one of several same-type candidates where the row cannot say which is the company's, and any number a registry attributes to a different company, which also sets registration.attributionUncertain. So a flat cell you can trust never shares space with one you cannot. Timestamps (scrapedAt, domainInfo.createdAt, domainInfo.expiresAt) are RFC 3339.

๐Ÿš€ Examples

Look up a single company

{
"domains": ["qonto.com"]
}

Enrich a list of fintech competitors

{
"domains": ["qonto.com", "monzo.com", "wise.com", "revolut.com", "n26.com"],
"maxItems": 100
}

Cap a large exported list to a first batch

{
"domains": ["acme-corp.com", "beta-labs.io", "cargo-supply.eu", "delta-parts.de", "example-retail.co.uk"],
"maxItems": 3
}

Mix bare domains and full URLs from a bookmarks export

{
"domains": ["airtable.com", "https://www.qonto.com/pricing", "https://monzo.com/blog/2024/product-update"]
}

Investigate a run with unexpected statuses

{
"domains": ["a-domain-that-recently-shut-down.com"],
"debugMode": true
}

๐Ÿค– Copy to your AI assistant

Paste this block into Claude, ChatGPT, or Cursor to give it full context about this scraper:

You have access to the Company Data Scraper on Apify: silentflow/company-data-scraper
Input schema:
- domains (array of string, required): domains or website URLs to look up
- maxItems (integer, default 100, min 1, max 10000): maximum number of company rows returned
- debugMode (boolean, default false): detailed logs for troubleshooting a run
Output: one row per input domain, 31 top-level keys always present.
Flat columns (14, for table/CSV): companyName, email, phone, city, country, registrationId,
linkedin, employeeRange, industry, techCount, cms, emailProvider, domainAge, identityConfidence
Row metadata: inputUrl, domain, finalUrl, httpStatus, status (ok/partial/blocked/unreachable/parked),
isLive, redirectChain, language, scrapedAt
Nested blocks: company (10 fields), contacts (3 fields, emails[] and phones[] with 4 fields each),
address (9 fields), registration (8 fields, ids[] with 5 fields each and officers[] with 2 fields each),
social (15 platform URL fields), tech (8 fields, technologies[] with 4 fields each, checked against
6,633 technologies), domainInfo (16 fields), meta (3 fields)
Use apify-client for Python or JS to run it and read the resulting dataset.

๐Ÿ’ป Integrations

Build a segmented lead list (Python)

from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("silentflow/company-data-scraper").call(run_input={
"domains": ["qonto.com", "monzo.com", "wise.com", "revolut.com"],
"maxItems": 500,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
if item["status"] not in ("ok", "partial"):
continue
if item["employeeRange"] in ("201-500", "501-1000", "1001-5000"):
print(f"{item['companyName']} ({item['country']}): {item['email']} - {item['linkedin']}")

Flag suppliers with no validated registration number (JavaScript)

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('silentflow/company-data-scraper').call({
domains: ['acme-supplier.com', 'another-supplier.eu', 'third-vendor.de'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const unverified = items.filter(
(i) => i.registration.ids.length === 0 || i.registration.attributionUncertain
);
unverified.forEach((i) => console.log(`Check manually: ${i.domain} (${i.status})`));

Export a spreadsheet-ready CSV (Python)

import csv
from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("silentflow/company-data-scraper").call(run_input={
"domains": ["qonto.com", "monzo.com", "wise.com", "n26.com"],
})
with open("companies.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["domain", "companyName", "email", "phone", "city", "country", "registrationId", "linkedin", "status"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
writer.writerow([
item["domain"], item["companyName"], item["email"], item["phone"],
item["city"], item["country"], item["registrationId"], item["linkedin"], item["status"],
])

๐Ÿ“ˆ Performance

Measured on the actor's own end-to-end run, 30 domains across France, Germany, the UK, the US, Spain and Italy:

MetricValue
Domains resolved93%
Company name returned100% of resolved domains
Technology stack detected100% of resolved domains
Run time30 domains in 7 minutes 29 seconds
Pages read per domainAbout 5

๐Ÿ’พ Data export

Results are available in:

  • JSON (full nested structure, best for pipelines and AI ingestion)
  • CSV (the 14 flat columns plus row metadata, nested arrays flattened)
  • Excel (.xlsx, native formatting)
  • JSONL (for streaming consumers)

Download from the Apify console, or pull programmatically from the dataset API:

https://api.apify.com/v2/datasets/{DATASET_ID}/items?format=csv&token=YOUR_TOKEN

๐Ÿ’ก Tips for best results

  1. Submit bare domains when you have them. qonto.com resolves the same as https://www.qonto.com/pricing, a bare domain just skips a parsing step.
  2. Start with a small maxItems to confirm the fields you actually need are populated before scaling a run up to your full list.
  3. Filter on identityConfidence, not on whether registrationId is filled in. A high-confidence company can still have no registration number if the site never published one; an empty registrationId is not by itself a failure.
  4. Group your list by expected country before a large run. Legal registration and postal address coverage is strongest in the EU and the UK, where a legal notice page is standard practice, and thinner in the US. Segmenting sets the right expectation before you look at the results.
  5. Re-run domains that come back blocked or unreachable on their own. A site that failed once can answer on a second pass if it was mid-deploy or briefly down when this run read it.
  6. Turn on debugMode only when investigating one run. Leave it off day to day, it exists for troubleshooting a specific batch.

โ“ FAQ

What does the scraper return for each domain? One consolidated company record: identity (name, legal name, description, logo, founding year, industry, headcount band), contacts with the page each one was found on, a postal address, legal registration data, 15 social profile links, a detected technology stack, and domain infrastructure. Every row carries the same 31 keys, whether the domain resolved or not.

What can I put in domains? Bare domains (qonto.com) or full website URLs (https://www.qonto.com/pricing). The domain is extracted automatically, so mixing both formats in the same list works. Duplicate domains are combined into a single row.

How fresh is the data? Live. Each run reads the target pages at the moment it runs. There is no cached or pre-scraped data behind the results.

Do I need an account, an API key, or to log into the target sites? No. Point it at a domain list and run it. Only publicly available pages are read.

What happens when a domain does not resolve, is dead, or is parked? You still get a row. The status field says what happened (ok, partial, blocked, unreachable, or parked), so an empty cell never means "we don't know", it means exactly the thing the status says. Your list stays complete even when some domains fail.

How do I know a registration number is really that company's? Every identifier whose register publishes a check digit is checked against it, and the flat registrationId column carries that number once it passes. Some registers publish no check digit at all, so nothing can be verified locally; there the flat column carries the number only when the site named exactly one of that kind, and each identifier says which case it falls under. If a number fails its check, if a registry attributes it to a different company, or if the site named several and the row cannot choose, the row says so through identityConfidence and registration.attributionUncertain instead of asserting an answer. The raw finding stays available in registration.ids, with the page it came from.

Does coverage vary by country? Yes. Legal registration data is richest in the EU and the UK, where publishing a registration number on a legal notice page is standard practice. Coverage is thinner in the US, where no equivalent requirement exists. Company identity, contacts, technology and domain infrastructure are read the same way everywhere.

Can I submit a large list in one run? Yes. maxItems controls how many rows the run returns, raise it as your list grows.

How many technologies can it detect? The technology engine checks each site against 6,633 known technologies and returns every match with a confidence score, alongside a summary by category.

What is identityConfidence and how should I use it? It is the scraper's own read on how sure it is that the legal entity it found is this company: high, medium, low, or none. Filter on it instead of on whether registrationId is filled in.

Is this legal? Where does the data come from? The data comes from pages the companies themselves publish: homepages, about pages, contact pages, and legal notice pages. See the Legal section below.

This Actor extracts publicly available data from company websites and the legal notice pages they publish. It does not bypass any login, paywall, or CAPTCHA. Users are responsible for complying with the terms of service of the sites in their input list and with applicable data protection laws, including GDPR, CCPA, and PIPL where relevant. The output can contain personal data, such as named officers, work email addresses, and phone numbers: handle it accordingly. Registration numbers and registry attributions are informational; verify with the relevant national registry before relying on them for a compliance or KYC decision.

Need just one slice of this data instead of the full company record:

  • Technology only: Website Tech Stack Scraper runs the same 6,633-technology engine on its own, without the company, contact, or registration data.
  • Domain infrastructure only: Domain Enricher returns registration dates, DNS and email provider, and certificate data for a domain list, without the company record.
  • More scrapers from the same publisher: silentflow on Apify

๐Ÿ“ฌ Support

Need something this scraper doesn't do yet? We ship features fast.

  • Feature requests go straight to our backlog.
  • Enterprise needs? We do custom integrations and high-volume plans.

Response time: usually under 24 hours.

Check out our other scrapers: silentflow on Apify