Business Profile Scraper – Contacts & Socials
Pricing
$5.00 / 1,000 business profiles
Business Profile Scraper – Contacts & Socials
Scrape a full business profile from a name or website: Google rating, reviews, category and address, every email and phone from the company site, plus social accounts with follower counts and latest posts.
Pricing
$5.00 / 1,000 business profiles
Rating
0.0
(0)
Developer
Simple Actors
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Scrape a complete business profile from nothing but a name and a town, or from a website you already have. One request returns the Google place record (rating, review count, category, price band, address, phone), every email and phone number published on the company's own website, and its social media accounts actually read — live follower counts, display names, verification and the three latest posts. It is built for lead generation, CRM enrichment, local market research and competitor monitoring: one row per business instead of five datasets to join.
Here is a real row, abridged — the full field reference is below:
Dishoom Covent Garden · 4.7 out of 29,573 reviews · Indian restaurant · £20–6012 Upper St Martin's Ln, London WC2H 9FB · +44 20 7420 9320press@dishoom.com · 12 phone numbers · contact form · dishoom.cominstagram Dishoom ✓ 3 posts latest 28 Aug, 525 likestiktok Dishoom 68,401 3 posts latest 27 Aug, 1,027 likesyoutube Dishoom 2,010 1 post latest 29 Maytwitter link onlylinkedin Dishoom 34,998 3 posts latest 28 Aug, 10 reactions
Features
- Google place record without a browser — rating, review count, category, price band, street address, phone and whether Google showed it open, read from the knowledge panel in Google's served HTML.
- Every contact on the website, not just one — every usable email and every valid phone number the site publishes, each with the page it was found on. One real lookup returned twelve numbers, one for each of that restaurant's locations, plus its press address and its contact-form URL.
- Phone numbers parsed properly — E.164 format, national formatting, line
type (
MOBILE,FIXED_LINE,TOLL_FREE) and country. - Social accounts read, not just linked — Instagram, TikTok, X (Twitter), YouTube, Facebook and LinkedIn accounts are opened and read for follower/subscriber count, display name, verification and three latest posts with text, date and likes.
- Every other platform still returned as a link — Yelp, Pinterest and the rest keep their URL and handle.
- Messaging links captured — WhatsApp, Telegram, Messenger, Skype, Viber and LINE, separately from accounts to follow.
- Postal address from the site's own markup — JSON-LD, microdata, an
addresselement or plain text, split into street/city/region/postcode/country. - Skip the search when you already have the URL — pass websites directly and only the contact and social steps run.
- Bounded cost per business — cap how many social accounts get read.
- Runs never fail on a bad target. A business with no knowledge panel, an unreachable site or a private social account is recorded on its row; the rest of the row still arrives.
Input
{"queries": ["Dishoom Covent Garden London"], // one business per line, "name + place""includeContacts": true, // read the site for emails, phones, address, social links"includeSocialProfiles": true, // open each social account for followers and latest posts"maxSocialProfiles": 3 // ceiling on the slow, per-account step (0–6)}
A name and a place. The more specific the place, the more reliably Google returns a knowledge panel rather than a list of similar businesses — a bare name in a big city often matches the wrong branch.
Already know the website? Skip the search:
{"websites": ["dishoom.com"] // no place record: there is nothing to search for}
| Field | Type | Default | What it does |
|---|---|---|---|
queries | array | — | Businesses, as "name + place". |
websites | array | — | Websites you already have. No place record, since nothing is searched for. |
startUrls | array | — | The same as websites, in the URL editor. |
includeContacts | boolean | true | Read the website for emails, phones, address, contact form and social links. |
includeSocialProfiles | boolean | true | Read each social account for followers and latest posts. The slow part. |
maxSocialProfiles | integer | 3 | Ceiling on the slow part, per business. Range 0–6. |
Output
One row per business. Every field it can emit is listed below — a field is
null (or [], or {}) when that thing genuinely was not found, never because
a step was skipped silently.
{"type": "business","query": "Dishoom Covent Garden London","name": "Dishoom Covent Garden","website": "https://www.dishoom.com/covent-garden/","placeFound": true,"rating": 4.7,"reviewCount": 29570,"category": "Indian restaurant","priceBand": "£20–60","openStatus": "Closed","placeAddress": "12 Upper St Martin's Ln, London WC2H 9FB","placePhone": "+44 20 7420 9320","email": "press@dishoom.com","phone": "+442074209320","emails": [{ "email": "press@dishoom.com", "source": "text", "foundOn": "https://www.dishoom.com/say-hello/" }],"phones": [{ "number": "+442074209320", "formatted": "+44 20 7420 9320", "raw": "020 7420 9320","type": "FIXED_LINE", "country": "GB", "source": "tel", "foundOn": "…" }],"contacts": [{ "name": null, "role": null, "email": "press@dishoom.com", "phone": "+442074209320","source": "ranked", "sourceUrl": "…" }],"contactFormUrl": "https://www.dishoom.com/say-hello/","websiteAddress": { "street": "12 Upper St. Martin's Lane", "city": "London", "region": null,"postalCode": null, "country": "England","raw": "12 Upper St. Martin's Lane, London, England", "source": "jsonld" },"description": "Bombay-style café and bar…","logo": "https://…","social": {"tiktok": { "url": "https://www.tiktok.com/@dishoom_uk", "handle": "dishoom_uk", "enriched": true,"followers": 68399, "displayName": "Dishoom", "verified": true,"latestPosts": [{ "url": "…", "text": "Chef Rufino cooks…","postedAt": "2026-08-27T15:09:00.000Z", "likes": 963 }] },"linkedin": { "url": "https://uk.linkedin.com/company/dishoom", "handle": "dishoom", "enriched": true,"followers": 34998, "displayName": "Dishoom", "verified": null,"latestPosts": [{ "url": "…", "text": "Southport Flower Show…","postedAt": "2026-08-28T09:31:13.485Z", "likes": 10 }] }},"messaging": { "whatsapp": "https://wa.me/…" },"socialPlatforms": ["instagram", "tiktok", "youtube", "twitter", "linkedin"],"notes": [],"scrapedAt": "2026-08-29T08:20:11.000Z"}
The row
| field | what it is |
|---|---|
type | "business", or "error" for a lookup that could not run at all |
query | what you asked for, verbatim — match rows back to your list with this |
name | the business's name, as Google's panel titles it. The website's own name is used only when Google had none: a site's og:site_name is often a tagline, and one real deli's is "NYC's oldest deli" |
website | the business's own site. Aggregators, delivery platforms and social networks are excluded, so this is the site the business runs |
scrapedAt | when the run read it, ISO 8601 UTC |
notes | anything that limited this row — no panel, no website, a failed sub-read. Empty on a clean lookup |
From Google's knowledge panel
| field | what it is |
|---|---|
placeFound | true when Google returned a panel. false means the search matched nothing structured — usually too vague a query — and every field below is null |
rating | rating out of 5, from the panel itself and not from the highest review snippet on the page (on one real result those disagreed, 4.2 against 3.4) |
reviewCount | how many Google reviews that rating is out of |
category | Google's own category, e.g. "Indian restaurant" |
priceBand | in the local currency — "$10–20", "£20–60", "Rs 10,000+" |
openStatus | whether Google showed it open or closed at the moment of the search |
placeAddress | the address on the panel |
placePhone | the phone on the panel — often present when the website publishes none |
From the business's own website
| field | what it is |
|---|---|
email | the best address to write to, or null — plenty of businesses publish none |
phone | the best number: the website's if it has one, otherwise the panel's |
emails[] | every usable address found, best first — { email, source, foundOn }. source is how it was found (mailto, jsonld, cloudflare, obfuscated, text…) and foundOn the page |
phones[] | every valid number — { number, formatted, raw, type, country, source, foundOn }. number is E.164; type is what the numbering plan says (MOBILE, FIXED_LINE, TOLL_FREE…) |
contacts[] | named contact points where the site grouped them — { name, role, email, phone, source, sourceUrl }. The first always carries the best email and phone together |
contactFormUrl | a page with a form a person could write into, for businesses that publish one instead of an address |
websiteAddress | the postal address as the site publishes it — { street, city, region, postalCode, country, raw, source }. Sometimes fuller than Google's. source is jsonld, microdata, address-element or text |
description | how the business describes itself, from its site's metadata |
logo | absolute URL to its logo |
messaging | WhatsApp, Telegram, Messenger, Skype, Viber, LINE links — ways to start a conversation rather than accounts to follow. {} when the site links none |
The social accounts
social is keyed by platform (instagram, tiktok, twitter, youtube,
facebook, linkedin, pinterest, …). socialPlatforms lists those keys, for
filtering.
| field | what it is |
|---|---|
url | the account, always present |
handle | the account's handle |
enriched | true when the account itself was read. false means the link was found but not read — either that platform has no Actor here, or it fell outside maxSocialProfiles |
followers | live follower or subscriber count. null is sometimes a real answer — see below |
displayName | the account's own display name |
verified | true/false where the platform says, null where it does not |
latestPosts[] | up to three, each { url, text, postedAt, likes }. postedAt is always an ISO 8601 string, normalised here — the underlying Actors variously return ISO strings, unix milliseconds and unix seconds |
note / error | why something is missing, when it is |
How to use
From Apify Console
- Open the Actor and click Try for free / Start.
- Put one business per line into Businesses, as a name and a place —
Dishoom Covent Garden London. Or paste websites you already have into Websites instead. - Leave Read the website for contacts and Enrich the social accounts on for a full profile. Turn the social step off for a fast place-plus-contacts sweep.
- Click Start and wait — expect roughly a minute per business.
- Open the Dataset tab and export as JSON, CSV, Excel or feed it to an API.
From the API
curl -X POST "https://api.apify.com/v2/acts/simple.actors~business-profile/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H 'Content-Type: application/json' \-d '{"queries": ["Dishoom Covent Garden London", "Bungalow restaurant east village new york"],"maxSocialProfiles": 3}'
Or with the JavaScript client:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('simple.actors/business-profile').call({queries: ['Dishoom Covent Garden London'],});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items[0].emails, items[0].social);
Use cases
- Lead generation and list building — turn a list of company names into verified emails, phone numbers and contact-form URLs ready for outreach.
- CRM and sales data enrichment — fill in missing rating, address, phone and
social handles against accounts you already hold, matched back by
query. - Local market and competitor research — pull rating, review count, category and price band across every business in a category and town.
- Influencer and partnership screening — see follower counts and posting recency across a business's Instagram, TikTok, YouTube, X and Facebook in one row before you reach out.
- Directory and marketplace seeding — build a business directory with place data, contact routes and social links from a name list alone.
Usage notes
Simple, transparent pay-per-result pricing — no subscriptions.
A row carries everything that could be found, never less because one part
failed. A private Instagram account costs that one section and nothing else;
the rating, the emails and the other accounts still arrive. Whatever was missed
is named in notes or on the section it belongs to.
Some nulls are real answers, not failures:
| why | |
|---|---|
email: null | plenty of businesses publish none — the place phone is usually the way in |
social.instagram.followers: null | Instagram publishes no follower count to a logged-out reader |
social.facebook.followers: null | that count comes from a different mode of the Facebook Actor than the one called here |
placeFound: false | Google had no knowledge panel for the search — try adding the street or town |
Each carries a note saying which.
It is not fast. Each business is a Google search, a website crawl and up to three social account reads — about a minute per business, most of it spent waiting on other people's servers. Businesses are read one at a time on purpose: each already fans out into several runs, and doing several at once turns that into a burst the target sites read as a flood.
How it works
It is assembled from Actors that already exist, each of which stays the one place its own platform's quirks are handled:
- The place comes from Google's knowledge panel. Not Google Maps — a Maps place page serves a shell and fetches the place by XHR, so reading it needs a browser. The same business searched on Google returns nearly the whole place record in the served HTML, for one request.
- The contacts come from
website-contacts, which finds the site's contact page for itself and knows a share button from a social account. - The socials come from
instagram-profile-posts,tiktok-profile-posts,x-profile-posts,youtube-channel-videos,facebook-page-postsandlinkedin-company-posts— one run each, for the accounts the website turned out to link.
Platforms without an Actor here (Yelp, Pinterest…) keep their link, which is still the useful half.
What it costs
This Actor calls six others, and their fees are billed to you on top of its own. That is how Apify works when one Actor calls another, and it is worth seeing plainly before you run a large list:
| what runs | its own price | a typical business |
|---|---|---|
| this Actor | $0.0050 per business | $0.0050 |
website-contacts | $0.0010 per site + $0.0005 per page | $0.0025 (3 pages) |
instagram-profile-posts | $0.0030 per profile | $0.0030 |
linkedin-company-posts | $0.0010 per company | $0.0010 |
tiktok-profile-posts | $0.0005 per profile | $0.0005 |
youtube-channel-videos | $0.0005 per video | $0.0015 (3 videos) |
| total | ~$0.0135 |
maxSocialProfiles caps how many of those social fees you can pay, whatever
a business links. At the default of 3 you are billed for at most three accounts,
so adding LinkedIn to the list of readable platforms widens the choice rather
than automatically widening the bill.
You only pay for what is actually there. A business with no TikTok is not
charged for one. maxSocialProfiles is the ceiling on the priciest part, and
setting includeSocialProfiles: false removes it entirely — a place record plus
website contacts is then about $0.0075 a business. includeContacts: false
drops it to $0.0050.
Assembling the same row yourself costs more, not less: the social and contact Actors charge you the same, and a Google place record has to come from a Maps scraper priced around $0.0070 a place. What this Actor removes is that cost and the joining — five datasets keyed differently, matched back to your list by hand.
Failures
The run always succeeds. Only a bug in this Actor fails a run.
error | what happened |
|---|---|
bad_input | nothing usable was given |
search_failed | Google could not be reached after three tries |
FAQ
Is scraping business data from Google and company websites legal? This Actor reads only pages that are public to any logged-out visitor — no login, no cookies, no paywall. That said, how you may use the data depends on where you are and what you do with it: check the platform's ToS, and check your local rules on personal data and marketing consent before using scraped emails or phone numbers for outreach.
Do I need a Google API key or a Maps API key? No. The place record is read from Google's own search results HTML, so there is no key, no quota and no browser to run.
Why is placeFound false for my business?
The search was too vague for Google to return a knowledge panel, so it showed a
list of similar businesses instead. Add the street, neighbourhood or town to the
query — Bungalow restaurant east village new york rather than Bungalow.
Why is a follower count null when the account clearly has followers?
Instagram publishes no follower count to a logged-out reader, and Facebook page
follower counts come from a mode of the Facebook Actor this one does not call.
Both cases carry a note on the account saying so, so you can tell a withheld
number from a failed read.
Can I run this on a list of thousands of businesses?
Yes — pass them all in queries. They are read one at a time on purpose, since
each business already fans out into several runs, so plan for roughly a minute
each. Lower maxSocialProfiles, or set includeSocialProfiles: false, to make
a large sweep much faster.
Does it support LinkedIn? Yes. A company page is opened and read like the other platforms, so you get its follower count, name and latest posts with their reaction counts. Personal LinkedIn profiles cannot be read, because LinkedIn serves those only behind a login.
What about Yelp, Pinterest and the rest? Their URL and handle are returned whenever the website links one, but the account itself is not opened, so there is no follower count or post list for it. Six platforms are read in full: Instagram, TikTok, X, YouTube, Facebook and LinkedIn.