
TikTok Shop Scraper
scrape.ly/store/shelfbright/tiktok-shop-scraperE-commerceSocial media
1 monthly user

Find local businesses on Google Maps and pull emails, phone numbers, and social profile links from their websites. Build B2B lead lists by niche and city in minutes.
Turn a Google Maps search into a lead list: place name, address, phone, website, and the public emails and social profiles printed on that website.
Built for sales teams, agencies, and operators who already know the trade or the city and need contacts they can load into a CRM the same day.
searchStringsArray plus locationQuery, a city/state/postal combination, a GeoJSON customGeolocation, or Google Maps startUrls. A place_id:ChIJ... search term opens that place directly.mailto addresses already in that HTML are included. A wall or a page with no address leaves the email fields empty. Addresses are not guessed.tel: links and numbers written on the homepage or those contact pages are added as phones and phonesUncertain.placeMinimumStars), places with or without a website, skip permanently or temporarily closed places, exact or partial name match (searchMatching), and category words (categoryFilterWords).language is sent as the Maps hl parameter, so category names and hours come back in the language you pick.maxCrawledPlacesPerSearch continues in neighboring map tiles that still overlap a 25 km radius around the geocoded query. Places farther out are not stored. One search reads at most 160 map tiles, because the places of a run are held in memory until they are saved.results-map.false or a real 0 stays. You can trust an empty column to mean “the page did not say.”maxCrawledPlacesPerSearch, and export JSON or CSV. Run it again next week for the next territory.{
"language": "en",
"locationQuery": "New York, USA",
"maxCrawledPlacesPerSearch": 20,
"scrapeSocialMediaProfiles": {
"facebooks": false,
"instagrams": false,
"tiktoks": false,
"twitters": false,
"youtubes": false
},
"searchStringsArray": [
"restaurant"
]
}
One item from a real run of the example input, shortened. Long text is cut and lists show their first entries.
{
"title": "Buena Vista Restaurant & Bar",
"placeId": "ChIJJaOjl3VZwokRmGLCoIs-LgU",
"address": "88 2nd Ave, New York, NY 10003",
"categoryName": "Latin American restaurant",
"categories": [
"Latin American restaurant",
"Cocktail bar"
],
"totalScore": 4.9,
"reviewsCount": 157,
"location": {
"lat": 40.726813899999996,
"lng": -73.9886355
},
"street": "88 2nd Ave",
"city": "New York",
"postalCode": "10003",
"state": "New York",
"neighborhood": "Manhattan",
"countryCode": "US",
"phone": "+1 555 0100",
"phoneUnformatted": "+1 555 0100",
"website": "https://www.buenavistany.com/",
"openingHours": [
{
"day": "Monday",
"hours": "11 AM to 11 PM"
},
{
"day": "Tuesday",
"hours": "11 AM to 11 PM"
}
],
"imageUrl": "https://lh3.googleusercontent.com/…",
"imagesCount": 238,
"fid": "0x89c2597597a3a325:0x52e3e8ba0c26298",
"cid": "373304588536799896",
"kgmid": "/g/11yzl1xj4d",
"businessProfileId": "14681402408299020922",
"url": "https://www.google.com/maps/search/?api=1&query=Buena+Vista+Restaurant+%26+Bar&query_place_id=ChIJJaOjl3VZwokRmGLCoIs-LgU"
}
Provide a search term and a location, or paste Google Maps URLs. URLs take priority over search terms.
{
"searchStringsArray": ["zahnarzt"],
"locationQuery": "Konstanz, Germany",
"maxCrawledPlacesPerSearch": 8,
"language": "en",
"website": "withWebsite",
"skipClosedPlaces": false
}
| Field | What it does |
|---|---|
searchStringsArray | Terms you would type into Maps. Also accepts place_id:ChIJ.... |
locationQuery | City, address, or region. This wins over the geolocation fields below. |
maxCrawledPlacesPerSearch | Places to keep per search term. Above one list, the run continues in neighboring tiles. Empty uses 20. |
language | Maps UI language, default en. |
searchMatching | all, only_includes, or only_exact against the place name. |
placeMinimumStars | two through fourAndHalf. Places with no rating are skipped when this is set. |
website | allPlaces, withWebsite, or withoutWebsite. |
skipClosedPlaces | Drop places Maps marks permanently or temporarily closed. |
categoryFilterWords | Keep a place when one of its categories matches. Used as the search text when no search terms are set. |
city, state, county, postalCode, countryCode | Combined into the location when locationQuery is empty. countryCode also selects the residential proxy country. |
customGeolocation | GeoJSON point or polygon. Coordinates are [longitude, latitude]. Used as the map center when no location text is set. |
startUrls | Google Maps search or place URLs. Each bad URL is skipped. |
scrapePlaceDetailPage | Also open the Maps place preview and fill any extra fields that preview contains. |
scrapePlaceDetailPage, scrapeTableReservationProvider, scrapeOrderOnline, scrapeDirectories, and maxQuestions open the Maps place preview and keep fields that preview already contains, including reserveTableUrl when a reservation link is there. scrapeSocialMediaProfiles opens profile URLs found on the website and keeps a follower or subscriber count only when that page shows an integer. Empty lists stay off the item.
Each dataset item is one place. These fields are present when Maps or the website sent them:
Contact. emails, phones, phonesUncertain, phone, phoneUnformatted, website, linkedIns, twitters, instagrams, facebooks, youtubes, tiktoks, pinterests, discords.
Place. title, placeId, url, address, street, neighborhood, city, postalCode, state, countryCode, location (lat, lng), categories, categoryName, totalScore, reviewsCount, reviewsDistribution, imageUrl, imagesCount, openingHours, description, additionalInfo, subTitle, reserveTableUrl, claimThisBusiness, permanentlyClosed, temporarilyClosed, wasOpenAtScrapeTime.
Identity. fid, cid, kgmid, businessProfileId, searchString, searchPageUrl, language, rank, scrapedAt.
openingHours is included when the card has at least five weekdays. Review counts and the star histogram are included when the Maps payload has them. scrapePlaceDetailPage is the switch that fetches the preview for a fuller card. The default search does not invent them.
The key-value store record results-map is an HTML list of the places that had coordinates.
You pay per event, plus platform usage (compute and proxy traffic). Reading each place's website for emails, phones and social links is included in the place price.
| Event | When it is charged | Price |
|---|---|---|
| Place scraped | Each place saved to the dataset, with its website contacts | $0.004 |
| Filter applied | Each saved place when a filter is on (category words, minimum stars, closed places, website) | $0.0008 |
| Place details scraped | Each place whose detail page was opened and read (scrapePlaceDetailPage) | $0.0016 |
| Social profile scraped | Each social profile returned with its follower or subscriber count | $0.008 |
Add-ons are charged only when you turn the option on and only for places where it returned data.
Example: 1,000 places with no add-ons cost $4.00 in event fees plus platform usage. In our test runs platform usage was about $0.28 to $0.51 per 1,000 places. The default 20-place search costs $0.08 in event fees.
If you set a maximum cost per run, the run saves as many places as that budget pays for and then stops cleanly.
Every field below can be set in the run form, passed through the API, or saved as a task. Unset fields fall back to the defaults shown.
searchStringsArrayarrayOptionalSearch terms
What you would type into the Google Maps search bar, e.g. English breakfast or pet shelter. Distinct terms are faster than near-synonyms (bar, restaurant, cafe). When looking for a specific business, also fill in Location. Putting the location into the search term (e.g. restaurant Pittsburgh) caps results at about 120 per term. Place IDs are accepted as place_id:ChIJ8_JBApXMDUcRDzXcYUPTGUY.
locationQuerystringOptionalLocation
One location per run, as free text. Simple formats work best, e.g. City, Country. A whole country or state is split into smaller areas automatically. City outlines can be smaller than the metro area; use Search area and language for an exact area.
startUrlsarrayOptionalGoogle Maps URLs
Optional. Google Maps search or place URLs (https://www.google.com/maps/...), also https://google.com/maps?cid=... and https://goo.gl/maps/... links. Up to 300 results per search URL.
maxCrawledPlacesPerSearchintegerOptionaldefault 20Max places per search term or URL
Number of places to return for each search term or URL. Higher numbers take longer. Empty uses 20. One search reads at most 160 map tiles within 25 km of the location, because the places of a run are held in memory until they are saved.
Narrow down which places are returned.
categoryFilterWordsarrayOptionalPlace categories
Only return places in these categories. Many places are miscategorised and Google Maps has over 4,000 categories, so list every category you want, including synonyms (e.g. divorce lawyer, divorce attorney, divorce service).
searchMatchingenumOptionaldefault "all"Get exact name matches (no similar results)
Filter places by how their name matches the search term, e.g. every place with chicken in its name vs. only places called Kentucky Fried Chicken.
placeMinimumStarsenumOptionaldefault ""Set a minimum star rating
Scrape only places rated at or above the selected stars. Places without reviews are skipped too, so fewer places are found.
websiteenumOptionaldefault "allPlaces"Scrape places with/without a website
Use this to exclude places without a website, or vice versa. This option is turned off by default.
skipClosedPlacesbooleanOptionaldefault falseSkip closed places
Skip places that are marked as temporary or permanently closed. Ideal for focusing on currently open places.
Results language, and an exact search area instead of Location.
languageenumOptionaldefault "en"Language
Results will be scraped in this language.
countryCodeenumOptionalCountry
Country, e.g. United States.
citystringOptionalCity
City only, e.g. Pittsburgh, without state or country. City outlines can be smaller than the metro area.
statestringOptionalState
State, e.g. Massachusetts (mainly for US addresses).
countystringOptionalCounty
County, e.g. New York County. Means different things in different countries: a US county, a Canadian regional district, a French département.
postalCodestringOptionalPostal code
One postal code, e.g. 10001. Combine it with Country only, not with City.
customGeolocationobjectOptionalCustom search area
A GeoJSON geometry, e.g. a Polygon or MultiPolygon, for an exact search area. Coordinates are [longitude, latitude].
Extra data for each place.
scrapePlaceDetailPagebooleanOptionaldefault falseScrape place detail page
Open each place's detail page for extra fields: review distribution and tags, image categories, popular times, opening hours, people also search, updates from customers, questions and answers, reservation links, owner updates and hotel fields. Slower, because every place needs another page load. Required by the other options in this section.
scrapeTableReservationProviderbooleanOptionaldefault falseScrape table reservation provider data
Scrape table reservation provider data like name, address, email or phone. This data is present only in restaurants that have a blue "RESERVE A TABLE" button.
scrapeOrderOnlinebooleanOptionaldefault falseScrape order online widget data
Scrape the 'Order online' section of restaurants to get pickup and delivery providers (Uber Eats, DoorDash, etc.), along with fees and estimated times.
scrapeDirectoriesbooleanOptionaldefault falseScrape inside places (e.g. malls or shopping center)
Also scrape businesses listed inside a place, such as shops in a mall (the Directory or At this place list). Requires Scrape place detail page.
maxQuestionsintegerOptionaldefault 0Number of questions to extract
Questions and answers to scrape per place. 0 or empty returns only the first one; 999 returns all. Some fields contain personal data.
scrapeSocialMediaProfilesobjectOptionaldefault {"facebooks":false,"instagrams":false,"youtubes":false,"tik…Social media profile enrichment
Fetch public details for the social media profiles found on each place's website: name, follower and following counts, description, post or video counts and verification status. Turns on company contacts enrichment automatically.
Every run writes its results to a dataset. Preview it in the dashboard, then export it or read it through the API.
| Field | Type | Description |
|---|---|---|
| webResults | array | Web search results related to the place |
| userPlaceNote | string | User's personal note about the place |
| tableReservationLinks | array | Links for table reservations |
| tableReservationProviders | array | Table reservation providers available for the place. Populated only when `scrapeTableReservationProvider` is enabled. |
| bookingLinks | array | Links for booking (hotels, tours, etc.) |
| orderOnline | object | Online ordering options (pickup and delivery). Omitted unless `scrapeOrderOnline` is enabled. Note: Google may also omit this data in ~5% of cases. |
| questionsAndAnswers | any | Questions and answers from the Q&A section |
| ownerUpdates | array | Updates posted by the business owner |
| restaurantData | object | Restaurant-specific data |
| reviewsCount | number | null | Total number of reviews |
| title | string | Name/title of the place |
| placeId | string | Unique Google Place ID |
| address | string | null | Full address of the place |
| location | any | Geographic coordinates (latitude and longitude) |
| categories | array | Array of category names for the place |
| isAdvertisement | boolean | Whether this place is a paid advertisement |
| categoryName | string | null | Primary category name |
| totalScore | number | null | Average rating score (0-5) |
| permanentlyClosed | boolean | Whether the place is permanently closed |
| temporarilyClosed | boolean | Whether the place is temporarily closed |
| url | string | Google Maps URL for the place |
| price | string | null | Price level indicator (e.g., "$", "$$", "$$$") |
| cid | string | null | Google CID (Customer ID) - numeric identifier |
| fid | string | null | Feature ID - More info at https://dataforseo.com/help-center/what-is-cid-place-id-feature-id |
| imageUrl | string | null | URL of the main place image |
| hotelStars | string | null | Hotel star rating (for hotels) |
| scrapedAt | string | Timestamp when the data was scraped (ISO 8601) |
| searchPageUrl | string | URL of the search page where this place was found |
| searchString | string | Search query used to find this place |
| inputPlaceId | string | Place ID from the input if specified |
| inputStartUrl | string | Start URL from the input if specified |
| language | string | Language code used for scraping |
| rank | number | Position in search results (1-based) |
| kgmid | string | null | Google Knowledge Graph ID |
| businessProfileId | string | null | Business Profile ID |
| neighborhood | string | null | Neighborhood or district name |
| street | string | null | Street address including building number |
| city | string | null | City name |
| countryCode | string | null | Two-letter country code (ISO 3166-1 alpha-2) |
| postalCode | string | null | Postal or ZIP code |
| state | string | null | State or province name |
| emails | array | Array of email addresses found |
| phones | array | Array of phone numbers found |
| phonesUncertain | array | Array of uncertain/possible phone numbers |
| linkedIns | array | Array of LinkedIn profile URLs |
| twitters | array | Array of Twitter profile URLs |
| instagrams | array | Array of Instagram profile URLs |
| facebooks | array | Array of Facebook profile URLs |
| youtubes | array | Array of YouTube channel URLs |
| tiktoks | array | Array of TikTok profile URLs |
| pinterests | array | Array of Pinterest profile URLs |
| discords | array | Array of Discord server URLs |
| facebookProfiles | array | Array of Facebook profile data |
| instagramProfiles | array | Array of Instagram profile data |
| youtubeProfiles | array | Array of YouTube profile data |
| tiktokProfiles | array | Array of TikTok profile data |
| twitterProfiles | array | Array of Twitter profile data |
| description | string | null | Brief description of the place |
| phone | string | null | Formatted phone number |
| phoneUnformatted | string | null | Unformatted phone number with country code |
| imagesCount | number | Total number of images available |
| openingHours | any | Opening hours for each day of the week |
| additionalOpeningHours | object | Additional opening hours for specific services (e.g., delivery, pickup) |
| claimThisBusiness | boolean | Whether the business can be claimed by its owner |
| peopleAlsoSearch | array | Related places suggested by Google |
| additionalInfo | any | Additional information grouped by categories (accessibility, amenities, etc.) |
| reviewsTags | array | Tags extracted from reviews |
| placesTags | array | Tags related to the place itself |
| imageCategories | array | Categories available in the image gallery |
| gasPrices | array | Gas prices (for gas stations) |
| reserveTableUrl | string | null | URL for making table reservations |
| googleFoodUrl | string | null | Google Food ordering URL |
| website | string | Official website of the place |
| leadsEnrichment | array | Enriched leads data from external sources |
| parentPlaceUrl | string | URL of the parent place (for places within other places) |
| hotelDescription | string | null | Description of the hotel |
| checkInDate | string | null | Check-in date for the search query |
| checkOutDate | string | null | Check-out date for the search query |
| similarHotelsNearby | array | Array of similar hotels in the area |
| hotelReviewSummary | any | Summary of hotel reviews by traveler type |
| hotelAds | array | Array of booking advertisements for the hotel |
| subTitle | string | null | Subtitle or secondary name |
| ownerDescription | string | null | Description written by the owner in Google Business Profile, shown in the "From the business" section. Unlike `description`, which is Google's own editorial summary. Kept in the language the owner wrote it in. |
| menu | string | null | URL to the menu (for restaurants) |
| servicesLink | string | null | URL to book services or appointments (for service businesses like barbershops, spas) |
| locatedIn | string | null | Name of the location where this place is situated |
| floor | string | null | Floor number or level |
| plusCode | string | null | Plus Code for the location |
| reviewsDistribution | any | Distribution of reviews across star ratings |
| reviewsRemovedNotice | any | Notice about reviews removed due to legal defamation complaints |
| updatesFromCustomers | any | Latest update posted by a customer |
| openingHoursBusinessConfirmationText | string | Confirmation text about opening hours from the business |
| wasOpenAtScrapeTime | boolean | null | Whether the place was open at the moment it was scraped, as reported by Google in the place's own time zone. Always `false` for permanently or temporarily closed places, and `null` when the status is missing or unrecognized, e.g. the place publishes no opening hours. |
| popularTimesLiveText | string | null | Human-readable text describing current occupancy level |
| popularTimesLivePercent | number | null | Current occupancy as a percentage (0-100) |
| popularTimesHistogram | object | Hourly occupancy data for each day of the week |
| isExternalServicePlace | boolean | Whether this place data comes from an external service |
| externalServiceProvider | string | null | Name of the external service provider |
| externalId | string | Identifier in the external service |
You pay for the events the actor reports, such as each result or page it produces. Platform usage is included in the event prices.
| Event | Charged when | Price |
|---|---|---|
| Filter applied | One saved place while a filter (category words, minimum stars, closed places, website) is on | $0.0008 |
| Place details scraped | One place whose detail page was opened and read | $0.0016 |
| Place scraped | One Google Maps place saved with the emails, phones and social links found on its website | $0.004 |
| Social profile scraped | One social media profile returned with its follower or subscriber count | $0.008 |
Run this actor from your own code. Swap in your API token and the examples work as-is.
import { ScrapelyClient } from 'scrapely-client'
const client = new ScrapelyClient({ token: process.env.SCRAPELY_TOKEN })
// Start the actor and wait for the run to finish.
const run = await client.actor('cornerledger/google-maps-email-extractor').call({
"searchStringsArray": [
"dentist"
],
"locationQuery": "Austin, Texas",
"maxCrawledPlacesPerSearch": 20,
"language": "en",
"website": "withWebsite"
})
// Read the dataset the run produced.
const { items } = await client.dataset(run.defaultDatasetId).listItems()
console.log(items)Tokens live in your account settings. Keep them server-side: a token carries the full permissions of your account.
Connect the Scrape.ly MCP server once and your agent can run this actor as a tool. Pick your tool:
Fetch scrape.ly/agents.md and run cornerledger/google-maps-email-extractorPaste into Claude Code, Codex, Cursor or any AI agent. It signs you in once in the browser.
{
"mcpServers": {
"scrapely": {
"url": "https://api.scrape.ly/mcp?tools=actors,runs,storage,docs&actors=cornerledger/google-maps-email-extractor"
}
}
}No key in the file: your client opens the browser to sign you in the first time it connects.
Inputs the developer prepared for common jobs. Open one to see its input, then copy it to your account to run it as-is or adjust it.
Search plus city, with emails from the places' websites.
Open places with 2+ stars that have a website.
Places and emails from a pasted Google Maps search link.
Scrape.ly gives you the infrastructure, the tooling, and the team to extract, process, and operationalize web data at any scale. Setup takes minutes. The advantage lasts forever.