Request a tool
All toolsAutomationsGuidesMCP serverRequest a toolPlatformsCategories
Company Firmographics Scraper icon

Company Firmographics Scraper

Enrich a domain or company name with exact employee count, revenue, HQ address, industry, founding year, ownership and ticker. No API key and no login needed.

21 runs on Apify $0.00092 per company ($0.92 / 1,000)
Run this in the cloudRun on Apify →

Developer & Research Tools

How it works

  1. 1
    Open it on Apify

    Hit Run on Apify — it opens the tool in the cloud, no install.

  2. 2
    Set the inputs

    Adjust companyDomains, companyNames, companyUrls (sensible defaults are pre-filled).

  3. 3
    Click Run

    The tool runs on Apify’s cloud and collects the data for you.

  4. 4
    Export the results

    Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.

Pricing

$0.00092 per company = $0.92 per 1,000

You are charged forWhenPrice
Company returnedOne company with its revenue, employee count, address, industry, founding year and ticker. A company that cannot be resolved returns an uncharged row instead.$0.00092

Pay-per-event pricing: you are billed per result, not per subscription. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2026-09-20, and they are what you are actually charged.

Inputs

FieldWhat it doesType
companyDomainsThe company's own website domain, such as stripe.com or deliveroo.co.uk. This is the most reliable way to ask, because the domain is what the returned record is checked against - a profile whose website does not match yours is never charged for. Scheme and www. are stripped for you.array
companyNamesCompany names, such as Cloudflare or Trader Joe's. Less precise than a domain: several companies share a name, so a name-only lookup is only returned when the name on the profile matches yours after its legal suffix is stripped. If you have both, put the names and the domains in the same order and each pair is treated as one company.array
companyUrlsLinks of the form https://www.owler.com/company/shopify. Use these when you already know which profile you want, or when a name or domain lookup came back saying it was not confident. A link is taken at face value and always returned if the page exists.array
maxResultsA ceiling on how many companies are returned, whatever you put in the lists above. Hard limit 1,000. Keep it low while you are testing - you pay per company returned.integer
proxyUrlsLeave this empty. The run brings its own addresses and the cost of them is already inside the price. Fill it in only if you specifically want the traffic to leave through servers you already pay for, as http://user:pass@host:port.array

What you get

A structured dataset — each result includes fields like:

companyNamewebsiteindustrySectorsemployeeCountrevenueUsdfoundedYearownershipstatustickerexchangecitystatecountryowlerUrl

Export every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.

Related tools in Developer & Research Tools

Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.

GitHub Scraper iconDeveloper & Research Tools

GitHub Scraper

Search GitHub repos and users: stars, forks, language, topics, licence, plus user bio, company and followers. No token needed. $0.90 per 1,000 rows.

18 use cases

Stack Overflow / Stack Exchange Scraper iconDeveloper & Research Tools

Stack Overflow / Stack Exchange Scraper

Search Stack Overflow and Stack Exchange by keyword or tag. Score, answer count, views, reputation and body text. $2 per 1,000 questions.

2 use cases

Package Registry Scraper (npm + PyPI) iconDeveloper & Research Tools

Package Registry Scraper (npm + PyPI)

Get npm and PyPI package metadata as JSON. Version, license, author, repo, keywords and npm monthly downloads. $2 per 1,000 packages.

2 use cases

arXiv Scraper iconDeveloper & Research Tools

arXiv Scraper

Search arXiv papers by title, author, abstract or category. Get full abstracts, authors, categories, DOI, dates and PDF links. $2 per 1,000 papers.

2 use cases

OpenAlex Scholarly Works Scraper iconDeveloper & Research Tools

OpenAlex Scholarly Works Scraper

Search 250M+ OpenAlex papers with no API key. Get titles, authors, venue, year, citations, DOI, OA links and full abstracts. $2.00 per 1,000 papers.

2 use cases

Crossref Scholarly Works Scraper iconDeveloper & Research Tools

Crossref Scholarly Works Scraper

Search 150M+ papers on Crossref: DOI, title, authors, journal, publisher, date, citations and abstract. No API key. $1.00 per 1,000 works.

2 use cases

See all Developer & Research Tools →

Company Firmographics Scraper - Revenue, Headcount and HQ from a Domain

Give it a domain, a company name or an Owler profile link. Get one row back with the legal entity name, the website, the full street address, the industry sectors, the exact employee count, the exact revenue in dollars, the founding year, the ownership, the status, and the ticker and exchange if it is listed. No account, no API key, no login, no browser.

  • Employee count and revenue come back as exact integers: 7,600 staff and $13,269,000,000, not

"1,001-5,000" and "$10B+".

  • The full postal address, down to the street line and the postcode.
  • A company that has been bought reports status: "Acquired" and names the parent and the month.
  • Every row is checked against the company you asked for. A profile that does not match is handed

over as a free note saying what it found instead, never billed as your answer.

  • Run it with empty input and you get a labelled sample row, free, so you can see the shape first.

What this does not do

Read this part first, because it is where the surprises are.

  • About one lookup in ten comes back without a company, and that is the honest number.

Measured on 50 real domain lookups through this Actor: 45 returned a company, 5 did not. All five misses were the same shape: a profile exists, but it is filed under a different website than the one asked for, so it was refused rather than guessed at. You are not charged for a miss. The note you get instead names the profile that was found, so you can pass its link straight back and take it deliberately. Well-known companies land more often than long-tail ones: 24 of 25 on the first batch, 21 of 25 on a deliberately obscure second batch.

  • **A name on its own is a weaker question than a domain, and it is the one place a wrong company

can still get through.** Plenty of firms share a name. A name-only lookup is returned when the name on the profile matches yours once the legal suffix is stripped, but nothing then confirms it is *your* company rather than a namesake. Those rows carry matchedOn: "name" so you can see which ones rest on that. If you have the domain, use the domain: a domain lookup is only returned when the website on the profile is that exact domain, so it cannot hand you a namesake.

  • Revenue is an estimate, not a filing. For public companies it tracks reported figures closely.

For private ones it is the source's own model. Treat it as a size band that happens to be written as a precise number, and do not put it in an audit.

  • Blanks are the source's blanks. Small and very new companies often have a profile with almost

nothing on it. profileCompleteness is the source's own 0-100 fill rate for that record: 100 is a full profile, 25 is a stub with a name and a city. Null means not published. It does not mean zero. A company with no published revenue returns revenueUsd: null, never 0.

  • No people. The underlying profile carries named executives with photographs and their LinkedIn

URLs, plus a switchboard number. None of that is emitted. This returns facts about companies.

  • No funding rounds, no investors, no news, no competitors, no employee reviews. One company,

one row of firmographics.

  • Country codes are not normalised. The source writes CA, GB and USA on the same field and

they are published exactly as found rather than converted into a standard that might be wrong. If you need ISO-2 everywhere, map USA yourself. It is the only three-letter code seen so far.

  • It does not find companies for you. This is enrichment, not discovery: you bring a list, it

fills in the columns. There is no "give me every fintech in Berlin" search.

Input

{
  "companyDomains": ["stripe.com", "deliveroo.co.uk", "octopus.energy"],
  "maxResults": 25
}
FieldWhat it does
companyDomainsThe company's own website domain. The most reliable way to ask, because the returned profile is checked against it. Scheme and www. are stripped for you.
companyNamesCompany names. Looser than a domain; see the note above. If you supply names and domains as two lists of the same length, they are paired up and each pair counts as one company rather than two.
companyUrlsLinks of the form https://www.owler.com/company/shopify. Taken at face value and always returned if the page exists, so this is the fix for a lookup that came back unsure.
maxResultsCeiling on companies returned, whatever the lists hold. Hard limit 1,000. Keep it low while testing, because you pay per company returned.
proxyUrlsLeave empty. The run brings its own addresses. Fill it in only if you want the traffic to leave through servers you already pay for, as http://user:pass@host:port.

Output

One row per company. A real row from a real run:

{
  "ok": true,
  "charged": true,
  "recordType": "company",
  "companyName": "Shopify, Inc.",
  "shortName": "Shopify",
  "website": "https://www.shopify.com/",
  "domain": "shopify.com",
  "description": "Shopify is a Canada-based multinational company that provides E-commerce solutions for online retailers.",
  "industrySectors": ["E-commerce"],
  "industryGroups": ["Software, Internet & Computer Services"],
  "employeeCount": 7600,
  "revenueUsd": 13269000000,
  "foundedYear": 2004,
  "ownership": "Public",
  "status": "Independent Company",
  "parentCompany": null,
  "acquiredOn": null,
  "ticker": "SHOP",
  "exchange": "NYSE",
  "street1": "151 O'Connor Street",
  "street2": "Ground Floor",
  "city": "Ottawa",
  "state": "Ontario",
  "country": "CA",
  "postcode": "K2P 2L8",
  "owlerUrl": "https://www.owler.com/company/shopify",
  "companyId": "100740",
  "profileCompleteness": 100,
  "matchedOn": "domain",
  "requestedName": null,
  "requestedDomain": "shopify.com"
}

Field notes

  • companyName is the legal entity, which is often not the brand. Airtable comes back as

Formagrid, Inc. and Instacart as Maplebear, Inc. shortName is the brand if that is what you wanted.

  • employeeCount and revenueUsd are exact integers or null. Null means the source has not

published a figure. It is never written as 0.

  • status is the company's standing: Independent Company, or Acquired. When it is

Acquired, parentCompany names the buyer and acquiredOn gives the month, e.g. Deliveroo PLC reports Acquired / DoorDash, Inc. / 05/2025.

  • ticker and exchange are filled only for listed companies. A private company returns

null for both, and ownership says Private.

  • industrySectors is the specific sector, such as E-commerce. industryGroups is the broad

bucket above it, such as Software, Internet & Computer Services. Thin profiles often have the group and not the sector.

  • matchedOn says which evidence returned this row: domain means the website on the profile

is exactly the domain you gave, and is the strongest; name is a name-only lookup, where the name is the only evidence there was; url means you supplied the link yourself. If you only want the strongest, filter on matchedOn == "domain".

  • profileCompleteness is the source's own 0-100 fill rate. Sort by it descending and the thin

records fall to the bottom.

  • requestedName and requestedDomain echo what you asked for, so you can join the output

back onto your input list without matching on names.

What it costs

$0.92 per 1,000 companies returned, plus a $0.0002 start fee per run. Flat on every plan, with no volume tiers, no minimum, no subscription.

You are charged only for companies that come back with data. About one lookup in ten cannot be resolved to a profile, and those return an uncharged row telling you so. On a list of 1,000 domains you would expect roughly 900 rows and a bill near $0.83, not $0.92.

Nothing else bills. A run that reaches nothing is free past the start fee, a domain that resolves to no profile is free, and a row dropped because the profile's website did not match the domain you asked for is free. That last one is deliberate, and it is why a lookup occasionally returns nothing rather than returning a company with a similar name.

How it works

It reads the company's public profile page and pulls the structured record the page is built from, rather than scraping rendered text. That is why the numbers are exact integers instead of parsed strings, and why a field that is genuinely empty comes back null rather than as a guess.

The site refuses a share of requests outright. Six different connection profiles were measured against it from the cloud, and they were not close: the one this Actor reaches for first answered 42 out of 42, while the profile most scrapers reach for by habit managed 11 out of 45 in the same job against the same addresses. When a request is refused the run changes both its connection profile and its outbound address and asks again, up to six times, and a refusal that survives all six is reported as a free note rather than billed.

Turning a domain into the right profile is the other half. The address is derived from the domain and the record that comes back is then checked against what you asked for, because a plausible-looking address can be a real page belonging to a different company with a similar name. That check is the reason a small number of lookups return nothing: refusing is the right answer when the alternative is billing you for somebody else's headcount.

What people use it for

  • Filling in the size, revenue and location columns on a CRM export that arrived as nothing but

company names and domains.

  • Scoring inbound sign-ups by company size before a human looks at them.
  • Territory and account planning, where a real headcount matters more than a band.
  • Checking whether a supplier or counterparty still exists independently, since an acquired company

reports its parent.

  • Building a market map from a list of domains you already have.

Reading the output

Every run writes three kinds of row and they are easy to tell apart:

  • Real rows carry "charged": true and "recordType": "company". One billed event each.
  • The sample row carries "_sample": true, "charged": false and "recordType": "sample".

There is exactly one, it only appears when the input had no company in it, and it exists so you can see the shape before you spend anything.

  • Notes carry "_diagnostic": true, "charged": false and an errorCode worth switching on:

NO_RESULTS when a profile was found but did not match the company you asked for (the message names what it found), NOT_FOUND when no profile exists at all, BLOCKED when the source refused every attempt, BAD_INPUT when an entry could not be turned into a lookup, TIME_BUDGET when the run ran out of time before reaching an entry.

The difference between NO_RESULTS and BLOCKED is the one that matters: the first means the company genuinely could not be confirmed, the second means nobody got to look and a re-run will usually succeed. Neither is charged.

If you only want data, filter on charged == true. The count of those rows is the number of events you were billed for, so the dataset is its own invoice.

Limitations

  • Coverage is good for established businesses and thin for very small, very new or privately held

local companies. A profile may exist with only a name, a city and a founding year.

  • Revenue and employee figures are the source's estimates. They are refreshed periodically, not

live, and a company that grew this quarter may still read last quarter's headcount.

  • A company with no profile returns an uncharged note. There is no fallback to another source.
  • Name-only lookups are refused unless the name matches exactly after the legal suffix is stripped,

so a common or abbreviated name may come back unmatched even though the company is covered.

  • The source writes country codes inconsistently (CA, GB, USA) and they are published as found.
  • Executives, phone numbers, funding rounds, investors, acquisitions made, competitor lists and news

are all present on the source record and all deliberately not emitted.

  • The hard ceiling is 1,000 companies per run. Split bigger lists across runs.
  • A share of requests is refused by the source at random. The run retries across several connection

profiles and addresses, and reports the ones that never got through without charging for them.

Questions

Do I need an account or an API key for anything? No. There is no login, no cookie and no key anywhere in this Actor, and you do not need an account with the source.

Why is revenue null on a company I know makes money? Because the source has not published a figure for it, which is common for private companies. Null means "not published". It is never written as 0, so you can tell a genuine blank from a genuine zero.

I asked for a domain and got a note saying it was not confident. What now? That means a profile was found whose website is a different domain from the one you gave. The note names it. If it is the company you meant, put its owler.com/company/... link in companyUrls and it will be returned. If it is not, you have been saved from a wrong row.

Can I look up a company by name only? Yes, but it is the weakest of the three inputs and it is deliberately strict. Supplying the name and the domain together as two lists of the same length is better than either alone.

Is the employee count exact or a band? An exact integer, when the source publishes one. That is the main reason to use this rather than a profile scraper that returns "1,001-5,000 employees".

What happens on a company that has been acquired? status reads Acquired, parentCompany names the buyer and acquiredOn gives the month. The rest of the row still describes the company you asked about, not the parent.

Will the run fail if the source is down? No. You get uncharged notes saying what could not be reached, and the run still finishes as succeeded. A failed run would still bill the start fee, which would mean paying to be told something was broken.

Can I run this on a schedule? Yes. Nothing is held between runs, and requestedDomain gives you a stable key to join today's rows onto yesterday's.