Company Data Scraper | Emails, Phones and Tech Stack
Pricing
from $2.04 / 1,000 companies
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
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Categories
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

- 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.
- 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.
- 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
| Team | What they build |
|---|---|
| Sales ops | Turn an exported prospect list into CRM-ready rows with legal name, postal address and headcount band, no manual dedup across pages |
| RevOps / data teams | Segment a market by technology, email provider, company age or headcount band before a campaign goes out |
| Compliance / procurement | Confirm a supplier or partner is a registered, active legal entity, with the registry source attached for the file |
| Automation builders | Wire 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 teams | Enrich inbound signups by the domain they signed up with, and route the lead by headcount or industry code |
| Market researchers | Build a territory list from a conference exhibitor roster, ranked by employee range and industry |
| Agencies | Turn a client's competitor list into a side-by-side sheet: technology stack, social presence, and domain age, in one table |
๐ฅ Input parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
domains | array 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. |
maxItems | integer | 100 | Maximum number of company rows this run returns (1 to 10,000). |
debugMode | boolean | false | Turns 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:
| Block | Fields | What is inside |
|---|---|---|
company | 9 | name, legal name, description, tagline, logo, founding year, industry code, headcount band, source URL |
contacts | 3 | emails[] (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 |
address | 9 | raw text, street, postal code, city, region, country, country code, confidence, source URL |
registration | 8 | ids[] (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 |
social | 15 | one profile URL field per platform: LinkedIn, X/Twitter, Facebook, Instagram, YouTube, TikTok, GitHub, Pinterest, Threads, Telegram, WhatsApp, Discord, Reddit, Snapchat, Medium |
tech | 8 | technology count, technologies[] (4 fields each: name, categories, version, confidence score), a category summary, detected CMS, ecommerce platform, CDN, framework, analytics tools |
domainInfo | 16 | registrar, 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 |
meta | 3 | pages 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-scraperInput 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 runOutput: 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, identityConfidenceRow metadata: inputUrl, domain, finalUrl, httpStatus, status (ok/partial/blocked/unreachable/parked),isLive, redirectChain, language, scrapedAtNested 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 against6,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 ApifyClientclient = 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"):continueif 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 csvfrom apify_client import ApifyClientclient = 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:
| Metric | Value |
|---|---|
| Domains resolved | 93% |
| Company name returned | 100% of resolved domains |
| Technology stack detected | 100% of resolved domains |
| Run time | 30 domains in 7 minutes 29 seconds |
| Pages read per domain | About 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
- Submit bare domains when you have them.
qonto.comresolves the same ashttps://www.qonto.com/pricing, a bare domain just skips a parsing step. - Start with a small
maxItemsto confirm the fields you actually need are populated before scaling a run up to your full list. - Filter on
identityConfidence, not on whetherregistrationIdis filled in. A high-confidence company can still have no registration number if the site never published one; an emptyregistrationIdis not by itself a failure. - 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.
- Re-run domains that come back
blockedorunreachableon 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. - Turn on
debugModeonly 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.
โ๏ธ Legal
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.
๐ Related scrapers
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