Shopify Store Scraper: Emails, Phones & Social Links
Pricing
from $3.99 / 1,000 results
Shopify Store Scraper: Emails, Phones & Social Links
Shopify Store Scraper extracts store contact and social data, including emails, phone numbers, social media links, store details, product catalogs, and website URLs. Ideal for e-commerce lead generation, competitor research, market analysis, and prospecting.
Pricing
from $3.99 / 1,000 results
Rating
0.0
(0)
Developer
Scrapio
Maintained by CommunityActor stats
0
Bookmarked
10
Total users
0
Monthly active users
3 days ago
Last modified
Categories
Share
Shopify Store Scraper — Extract Emails, Phones and Social Links
Shopify Store Scraper: Emails, Phones & Social Links turns a list of storefront URLs into typed JSON merchant profiles — the published email address, phone number, social profile links, and policy inventory for each store, plus the full store identity and catalogue block. Unlike scraping frameworks that return raw HTML, it returns structured JSON ready for a CRM, a database, or an LLM context window without any parsing. Nothing is guessed: when a store doesn't publish a value, the field comes back empty rather than filled with a pattern. This guide covers every input and output field and how outbound, monitoring, and research teams actually run it.
🧭 What Does Shopify Store Scraper: Emails, Phones & Social Links Do?
It reads the public pages of a Shopify storefront — the homepage, up to a configurable number of contact pages, and the store's policy pages — and assembles one merchant profile row per store. No Shopify account, Partner API key, or storefront login is required; every page it reads is one a normal visitor can load. The row carries three things at once: the contact points the merchant actually publishes (email, phone, social links), a policy inventory (which of Shopify's six policy pages exist and what they say), and the full store identity and catalogue metadata (name, location, currency, theme, product and collection counts, price range).
- ✉️ Email discovery — reads the homepage, contact pages, policy pages, and any Organization JSON-LD, and picks the customer-facing address over a legal or press mailbox
- ☎️ Phone discovery — prioritizes a published
tel:link over a number found only in prose - 🔗 Social profile resolution — matches links against the store's own domain token so an app's or agency's profile doesn't get picked over the merchant's own
- 📜 Policy inventory — URL, body presence, and body length for each of the six Shopify policy types, plus a refund-window day count when the policy states one
- 🏬 Merchant identity —
myshopifyDomain, shop id, HQ city/region, money format, ships-to countries, accepted card brands, Shop Pay Installments flag - 📦 Catalogue snapshot — product/collection counts, price range, vendors, categories, and a top-10 recent-products sample
- 🚦 Honest status reporting — an
open,password_protected, orno_public_cataloguestore are three distinct states, not one blended "success"
⚡ Features & Capabilities
The Actor's job splits into three layers: contact discovery, policy inventory, and store identity/catalogue — all three arrive in the same row.
Core features
- Evidence-ranked contact picking. Every candidate email and phone is collected first, then ranked — an address on the store's own domain outranks one on a third-party domain, and a customer-facing local part (
hello@,support@,info@) outranks a legal or press mailbox. The winning value lands inprimaryEmail/primaryPhone, withemailSource/phoneSourcetelling you where it came from (homepage,contact_page,policy_page,structured_data,tel_link,contact_page_text,policy_text). - Placeholder and noise filtering. Theme-default addresses (
your@email.com,info@example.com), tracking-vendor domains, and file extensions masquerading as TLDs are filtered out ofemailsbefore ranking — a naive regex extractor emits these, this one doesn't. - Social profile scoring, not first-match.
extract_socialsgathers every candidate URL per platform across a page, then scores each by whether the handle matches the store's own brand token and how many times the store links it, so a one-off mention doesn't outrank the merchant's real footer link. - Configurable contact-page ladder.
contactPagePathsandmaxContactPagescontrol exactly which paths are tried and how many;contactPagesTriedandcontactPagesReadreport back what actually happened, so the count you set is verifiable in the output. - Policy body verification, not just existence. Each policy entry in
policiescarrieshasBodyandbodyChars— a policy page that resolves but ships no text is recorded as such, not silently skipped. - JSON-LD structured-data fallback. When a store publishes
Organization/Storeschema markup, itsemail,telephone,logo, andsameAslinks feed into the same candidate pool as page-scraped values. - Backward-compatible catalogue block.
total_products,total_variants,collections,price_min/price_avg/price_max,vendors,categories, andtop_productsride along on every row, sourced from the store's public/products.jsonand/collections.jsonendpoints.
Shopify Store Scraper: Emails, Phones & Social Links within the Scrapio data stack
This Actor covers store-level contact, policy, and identity data — one row per storefront. For deeper per-product fields (descriptions, specs, tags), use Shopify Products Scraper — Descriptions, Specs & Tags. For market, currency, and shipping-focused merchant metadata, use Shopify Merchant Scraper: Market Currency & Shipping Data. For related-product and price-comparison data, use Shopify Scraper: Related Products & Price Comparison.
Why do developers and data teams scrape Shopify stores?
🏢 Outbound and lead generation teams
You already have a list of Shopify domains — from a lead database, a niche directory export, or a prospecting tool — and need the mailbox and social handles to actually reach the brand. Feed merchantUrls in, read back primaryEmail, emailSource, primaryPhone, socialProfiles, and merchantName, and the row lands directly in a CRM import or an outbound sequencing tool. emailSource matters here: a contact_page hit is a mailbox someone checks; a policy_page hit is often a legal address, worth routing differently.
📊 AI training data and RAG indexing
merchantDescription, refundPolicyExcerpt, and the individual policies[].bodyChars fields are the highest-information text on a store: they describe what the merchant sells and what it promises, in the merchant's own words. For RAG enrichment, index merchantDescription and refundPolicyExcerpt against the store domain so an agent answering "does this store accept returns" can cite the actual policy text and its window (returnWindowDays). For training data, merchantCity, merchantProvince, acceptedCardBrands, and shipsToCountries return as consistently typed primitives across every store in a run, with no HTML to strip first.
📱 Competitive and market intelligence
Track price_min, price_avg, price_max, total_products, products_on_sale, and discount_pct_avg across a watch-list of competitor stores on a schedule, and the delta on any of those fields is the signal — a widening discount_pct_avg says a competitor moved into a sale cycle before their own marketing announces it.
🔬 Research and academic use
policies, returnWindowDays, acceptedCardBrands, and shipsToCountryCount build a structured, publicly sourced dataset on DTC merchant practices — return-policy generosity, international shipping reach, payment-method adoption — without touching anything behind a login. Public storefront data only; no account credentials are collected or required.
🎥 Product and SaaS development
Build a merchant-enrichment API, a Shopify store directory, or a compliance-monitoring tool on top of storefrontStatus, hasReturnPolicy, policyCount, and the contact fields — a due-diligence tool, for instance, can flag any store where hasReturnPolicy is false or primaryEmail is empty before a partnership proceeds.
🍚 Input Parameters
All twelve parameters, copied from .actor/input_schema.json. None is required — running with merchantUrls empty pushes a single no_input status row rather than failing.
| Parameter | Required | Type | Constraints | Description |
|---|---|---|---|---|
merchantUrls | No | array (stringList) | prefill: ["https://www.allbirds.com"] | One entry per Shopify store, for example https://www.allbirds.com or rothys.com. |
startUrls | No | array (stringList) | — | Kept so older input files keep working. Used only when merchantUrls is empty. |
findEmails | No | boolean | default: true | Read merchant email addresses from the store's own pages. Measured on two live runs over the same 12-store list: 9–10 of 12 stores (75–83%). Turn this off and the email columns come back empty. |
findPhones | No | boolean | default: true | Read merchant phone numbers from the store's own pages. Measured on two live runs over the same 12-store list: 8 of 12 stores (67%) in both. Stores with no published number return empty, never a guessed number. |
findSocialProfiles | No | boolean | default: true | Instagram, Facebook, TikTok, YouTube, Pinterest, X/Twitter and LinkedIn profile links. Measured on two live runs over the same 12-store list: 12 of 12 stores (100%) in both. |
contactPagePaths | No | array (stringList) | prefill: ["/pages/contact", "/contact", "/pages/contact-us", "/policies/contact-information"] | Store paths checked for contact details, in order. The row reports back which of them answered, in contactPagesRead. |
maxContactPages | No | integer | min 0, max 10, prefill 4 | How many of the paths listed above to try per store, counted from the top of that list. Enter 2 and only the first two are tried; enter 0 and none are, so contact details come from the storefront's own front page and its policy pages only. The number tried is reported back in contactPagesTried, and the ones that answered in contactPagesRead. Never more than the number of paths you listed. |
readPolicies | No | boolean | default: true | Builds a policy inventory with the page URL, whether it has body text, and how long that text is. |
policyTypes | No | array (select, multi) | enum: refund-policy, privacy-policy, terms-of-service, shipping-policy, contact-information, subscription-policy; prefill: all six | Leave all selected to inventory everything the store publishes. |
includePolicyExcerpt | No | boolean | default: true | Adds the opening text of the refund policy to the row. Empty when the store publishes the page without body text. |
excerptChars | No | integer | min 0, max 5000, prefill 600 | Hard limit on how many characters of the refund policy are kept in refundPolicyExcerpt. Enter 200 and the excerpt is never longer than 200 characters; enter 0 and no excerpt is returned. Shorter policies are returned in full. |
proxyConfiguration | No | object (proxy) | prefill: {"useApifyProxy": false} | Leave as-is unless you need the run routed differently. |
JSON input example
{"merchantUrls": ["https://www.allbirds.com","rothys.com","https://partakefoods.myshopify.com"],"findEmails": true,"findPhones": true,"findSocialProfiles": true,"contactPagePaths": ["/pages/contact", "/contact", "/pages/contact-us", "/policies/contact-information"],"maxContactPages": 4,"readPolicies": true,"policyTypes": ["refund-policy", "privacy-policy", "shipping-policy", "contact-information"],"includePolicyExcerpt": true,"excerptChars": 600,"proxyConfiguration": { "useApifyProxy": true }}
Supported URL types and input formats
merchantUrls accepts three input shapes, normalized internally before the run starts (https:// is prepended if missing, and any path/query is stripped down to scheme + host):
- Full URL —
https://www.allbirds.com - Bare domain —
rothys.com .myshopify.comhandle —partakefoods.myshopify.com
startUrls accepts the same three shapes and is read only when merchantUrls is empty, purely for input files written against an older schema version. Duplicate URLs (after normalization) are de-duplicated before the run starts.
📦 Output Format
Every run produces typed, normalized JSON — one row per reachable store, pushed the moment that store finishes, plus an uncharged status row for any store that couldn't be read or for a run started with no input at all. Field names stay stable across runs; there is no CSV/XML transform inside the Actor, but the Apify platform's own dataset export (CSV, JSON, XML, Excel, RSS) works on the resulting dataset regardless.
Uncharged rows. Only successful store profiles are billed, via the
row_resultcharged event. A store that returns no usable public data is pushed as{"type": "status", "storefrontStatus": "unreachable", ...}, and a run started with no store URLs at all pushes{"type": "status", "storefrontStatus": "no_input", ...}— neither is charged. Filter them out of an export withitem.type !== "status"(oritem.storefrontStatus !== "unreachable" && item.storefrontStatus !== "no_input").
Output for a store profile row
{"type": "store","isChild": false,"store_domain": "www.allbirds.com","store_url": "https://www.allbirds.com","shop_name": "allbirds.myshopify.com","country": "US","currency": "USD","locale": "en","theme_name": "Impulse","theme_id": 123456789,"theme_version": "8.1.0","apps_installed": ["Elevar Conversion Tracking"],"apps_by_category": { "Analytics": ["Elevar Conversion Tracking"], "Other": [] },"apps_count": 1,"total_products": 214,"total_variants": 812,"collections": ["Men", "Women", "Shoes", "Accessories"],"collections_count": 4,"categories": ["Apparel", "Footwear"],"vendors": ["Allbirds"],"price_min": 30.0,"price_avg": 88.45,"price_max": 150.0,"products_on_sale": 12,"discount_pct_avg": 22.5,"total_variants_available": 690,"inventory_availability_pct": 85.0,"estimated_launch_date": "2016-02-03","oldest_product_date": "2016-02-03","newest_product_date": "2026-07-30","products_with_images": 214,"avg_images_per_product": 4.3,"products_with_description": 214,"top_products": [{ "title": "Men's Tree Runners", "url": "https://www.allbirds.com/products/mens-tree-runners", "price": 98.0 }],"api_blocked": false,"myshopifyDomain": "allbirds.myshopify.com","shopId": 12345678,"merchantName": "Allbirds","merchantDescription": "Sustainably made shoes and apparel.","merchantCity": "San Francisco","merchantProvince": "CA","moneyFormat": "${{amount}}","shipsToCountries": ["US", "CA"],"shipsToCountryCount": 2,"acceptedCardBrands": ["visa", "master", "american_express"],"offersShopPayInstallments": true,"organizationLogoUrl": "https://cdn.shopify.com/s/files/allbirds/logo.png","organizationSameAs": ["https://www.instagram.com/allbirds", "https://www.facebook.com/allbirds"],"publishedProductsCount": 214,"publishedCollectionsCount": 6,"emails": ["hello@allbirds.com"],"primaryEmail": "hello@allbirds.com","emailSource": "contact_page","emailCount": 1,"phones": ["+1 415-489-1443"],"primaryPhone": "+1 415-489-1443","phoneSource": "tel_link","phoneCount": 1,"socialProfiles": {"instagram": "https://instagram.com/allbirds","facebook": "https://facebook.com/allbirds","twitter": null,"tiktok": "https://tiktok.com/@allbirds","youtube": null,"pinterest": null,"linkedin": "https://linkedin.com/company/allbirds"},"socialPlatformCount": 3,"policies": [{ "type": "refund-policy", "url": "https://www.allbirds.com/policies/refund-policy", "hasBody": true, "bodyChars": 1840 }],"policyCount": 6,"hasReturnPolicy": true,"returnWindowDays": 30,"refundPolicyExcerpt": "We want you to love your Allbirds. If you're not satisfied, return them within 30 days...","contactPageUrl": "https://www.allbirds.com/pages/contact","contactPagesRead": ["https://www.allbirds.com/pages/contact"],"contactPagesTried": 4,"storefrontStatus": "open","storeProfileComplete": true,"catalogueReadable": true,"collectionPagesRead": 1,"productPagesRead": 1,"scraped_at": "2026-08-15T09:12:47.123456+00:00","scrape_duration_sec": 4.87}
Output for a policy inventory entry
Each item inside policies[] — one per policy type the store actually publishes:
{"type": "refund-policy","url": "https://www.allbirds.com/policies/refund-policy","hasBody": true,"bodyChars": 1840}
Output for a top-product entry
Each item inside top_products[] — up to the 10 most recently created products found while walking the store's public product feed:
{"title": "Men's Tree Runners","url": "https://www.allbirds.com/products/mens-tree-runners","price": 98.0}
Schema stability and export options
Field names are fixed by the row-building code and do not change when Shopify updates a store's front-end theme — the Actor reads the store's public meta.json, products.json, collections.json, JSON-LD, and page HTML directly, not a theme-specific DOM structure. A field that cannot be honestly read comes back null rather than a fabricated 0 or empty string, so a missing value and a genuinely-zero value never look the same. Results live in the run's default Apify dataset and export as JSON, CSV, XML, Excel, or RSS from the Apify Console or API — there is no separate delivery mechanism beyond the dataset itself.
⚠️ Catalogue read ceiling. The Actor walks the store's public product and collection feeds in pages of 250 items, up to 60 product pages (15,000 products) and 40 collection pages (10,000 collections) per store. For a store with a catalogue larger than that, total_products / total_variants / collections_count and the price/vendor/category aggregates reflect only what was read before the ceiling, and storeProfileComplete is false. This ceiling does not affect the contact, policy, or identity fields, which come from the homepage, contact pages, and policy pages, not the catalogue feed.
💡 Shopify Store Scraper: Emails, Phones & Social Links Strategy Guide
🎯 Strategy 1: Real-time lead enrichment pipeline
When a new Shopify domain lands in your pipeline — from a form fill, a directory export, or a prospecting tool — trigger a single-store run with merchantUrls: [domain]. Read primaryEmail, emailSource, primaryPhone, socialProfiles, and merchantName back and append them to the lead record in your CRM or outbound tool. emailSource tells you whether the mailbox came from a contact_page (likely monitored) or a policy_page (often a legal address), which is worth routing to different sequences.
🎯 Strategy 2: Scheduled monitoring and alerting
Build a watch-list of competitor or partner store URLs and run it on an Apify Schedule. Diff each run's dataset against the previous one on price_avg, discount_pct_avg, hasReturnPolicy, returnWindowDays, and storefrontStatus. A store flipping from open to password_protected, or a returnWindowDays value shrinking, is the kind of delta worth an alert — nothing in the Actor itself sends webhooks, so wire the alert logic into whatever consumes the dataset after the run completes.
🎯 Strategy 3: Bulk dataset build
For a large list, split merchantUrls across several runs rather than one giant list — scrape_single_store processes stores one at a time within a run (its own products.json/collections.json fetches run concurrently, but stores in the list do not), so wall-clock time scales with list length per run. Aggregate the resulting datasets with the Apify API or apify_client and export to CSV or a database once every run finishes.
Strategy comparison at a glance
| Strategy | Best for | Run pattern | Output format |
|---|---|---|---|
| Real-time enrichment | New leads arriving one at a time | Single-store run triggered per event | JSON row appended to CRM |
| Scheduled monitoring | Tracking known stores over time | Recurring run on an Apify Schedule | Dataset diffed against the prior run's export |
| Bulk dataset build | Large one-off research or lead lists | List split across multiple runs | Combined dataset export to CSV / database |
🌴 Related Shopify Scrapers & Tools
| Scraper | What it extracts |
|---|---|
| Shopify Products Scraper — Descriptions, Specs & Tags | Per-product descriptions, specs, and tags — deeper catalogue detail than this Actor's top_products sample |
| Shopify Merchant Scraper: Market Currency & Shipping Data | Merchant-level market, currency, and shipping-zone metadata |
| Shopify Scraper: Related Products & Price Comparison | Related-product and price-comparison data across a store's catalogue |
| Amazon DE Sellers Leads Scraper By ASIN & Seller ID | Seller contact leads on Amazon.de — the cross-platform equivalent of a store-contact lookup |
| Instagram Post Details Scraper With Comments & Replies | Once you have a store's Instagram handle from socialProfiles, pull its post-level content |
| Facebook Reviews Scraper With Date & Keyword Filters | Complementary brand-monitoring once you have a store's Facebook page from socialProfiles |
How to integrate Shopify Store Scraper: Emails, Phones & Social Links with your stack
Shopify Store Scraper: Emails, Phones & Social Links works with any language or tool that can make an HTTP request — it runs on the Apify platform and is called through the Apify API or the apify-client SDKs.
Python
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_API_TOKEN>")run_input = {"merchantUrls": ["https://www.allbirds.com","rothys.com",],"findEmails": True,"findPhones": True,"findSocialProfiles": True,"readPolicies": True,"excerptChars": 600,}run = client.actor("<YOUR_APIFY_USERNAME>/shopify-store-scraper-emails-phones-social-links").call(run_input=run_input)rows = []for item in client.dataset(run["defaultDatasetId"]).iterate_items():if item.get("type") == "status":continue # skip uncharged no_input / unreachable rowsrows.append({"store_domain": item.get("store_domain"),"merchantName": item.get("merchantName"),"primaryEmail": item.get("primaryEmail"),"primaryPhone": item.get("primaryPhone"),"socialPlatformCount": item.get("socialPlatformCount"),})import csvwith open("shopify_stores.csv", "w", newline="", encoding="utf-8") as f:writer = csv.DictWriter(f, fieldnames=rows[0].keys())writer.writeheader()writer.writerows(rows)
Node.js
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_API_TOKEN>' });const runInput = {merchantUrls: ['https://www.allbirds.com', 'rothys.com'],findEmails: true,findPhones: true,findSocialProfiles: true,readPolicies: true,};const run = await client.actor('<YOUR_APIFY_USERNAME>/shopify-store-scraper-emails-phones-social-links').call(runInput);const { items } = await client.dataset(run.defaultDatasetId).listItems();const rows = items.filter((item) => item.type !== 'status').map((item) => ({store: item.store_domain,email: item.primaryEmail,phone: item.primaryPhone,socials: item.socialPlatformCount,}));console.log(rows);
Async and scheduled pipelines
For large or recurring jobs, start the run without waiting on it (client.actor(...).start(run_input=run_input) in Python, or the Console's "Run" button) and poll the run status or the dataset item count until it finishes, rather than holding a synchronous connection open. For recurring jobs, an Apify Schedule triggers the same input on a cron-style interval without any external orchestrator.
🎯 Who Needs Shopify Store Scraper: Emails, Phones & Social Links? (Use Cases & Industries)
🏢 Outbound and lead-gen teams
Turn a list of Shopify domains into a contactable list — primaryEmail, primaryPhone, and socialProfiles feed directly into a CRM import or a sequencing tool, with emailSource flagging whether the address is a monitored inbox or a policy-page mailbox.
📊 Data and analytics teams
Build a structured Shopify merchant dataset — merchantCity, merchantProvince, acceptedCardBrands, shipsToCountries, and the price/catalogue fields — for market-sizing or segmentation work, all typed and consistent across every store in the run.
📱 Ecommerce and DTC competitive intelligence
Watch price_avg, discount_pct_avg, hasReturnPolicy, and returnWindowDays on a competitor list over time; a policy or pricing change shows up in the next scheduled run's row.
🔬 Researchers
Build a public, structured dataset on DTC merchant practices — refund windows, shipping reach, payment-method adoption — using only publicly published storefront data, with no account or login involved.
🎥 Product and compliance tooling builders
Use storefrontStatus, hasReturnPolicy, and the contact-completeness fields as inputs to a due-diligence or partner-vetting tool, flagging stores that don't publish a return policy or a working contact channel before a deal proceeds.
Is it legal to scrape Shopify stores?
Scraping publicly accessible Shopify storefront pages — the same pages any visitor's browser loads — is generally lawful in most jurisdictions; the well-known US precedent for scraping public web data is hiQ Labs v. LinkedIn (9th Cir. 2019, 2022), which held that scraping data with no access controls does not violate the Computer Fraud and Abuse Act. That case concerned public profile data specifically and its reasoning does not automatically extend to every jurisdiction or every dataset, so it is cited here as context, not a blanket guarantee.
This Actor returns store-level business records — merchant identity, published contact points, social links, policy text, and catalogue metadata — not individual consumer profiles, so general data-protection frameworks built around personal profiles (GDPR's Article 6 lawful-basis requirements, for instance) generally do not attach to the bulk of this output the way they would to a scraper of individual people. What can apply regardless of jurisdiction is the target site's own Terms of Service: scraping in violation of a site's ToS is a potential civil contract matter between the scraper and the site operator, separate from the public-data legality question above. A published business email or phone number that happens to identify a specific individual (a sole proprietor's own inbox, for example) can still carry data-protection obligations for how you store and use it — that determination and the lawful basis for it sit with you.
Shopify Store Scraper: Emails, Phones & Social Links returns only publicly accessible data. What you do with that data is your responsibility — consult legal counsel for commercial applications involving personal data.
❓ Frequently asked questions
Does Shopify Store Scraper: Emails, Phones & Social Links work without a Shopify account?
Yes. It reads only public storefront pages — the homepage, contact pages, policy pages, and public meta.json/products.json/collections.json endpoints — so no Shopify account, Partner API key, or storefront login is needed or collected.
How does it handle Shopify's anti-scraping measures?
It runs an escalating connection ladder per request: on a blocking or error status (403, 406, 407, 408, 425, 429, 451, 500, 502, 503, 504) or a connection exception, it retries — up to 3 attempts per request — and, if Apify Proxy is enabled in proxyConfiguration, escalates from a direct connection to Apify's standard datacenter proxy and then to a residential proxy group. If Apify Proxy is left off (the schema's default, useApifyProxy: false), retries still happen but always over a direct connection, since there is no proxy tier to escalate into.
Can I run it at scale without getting blocked?
The Actor processes the store list one storefront at a time within a single run (each store's own product and collection pages fetch concurrently, but stores in the list do not run in parallel), so large lists are best split across multiple runs rather than one very large merchantUrls array. No uptime or throughput figure is published for this Actor.
How fresh is the data it returns?
Live per run. Every field is read from a fresh HTTP fetch of the target store at run time — there is no cached lookup table or stale contact database behind any field.
Which fields work best for AI training and RAG indexing?
For RAG, index merchantDescription and refundPolicyExcerpt against the store domain — they're the highest-information free text on a merchant page, in the merchant's own words. For training data, merchantCity, merchantProvince, acceptedCardBrands, shipsToCountries, and the price fields return as consistently typed primitives (strings, numbers, booleans, arrays) across every store, requiring no HTML stripping or normalization before use.
Does it work with Claude, ChatGPT, and other AI agent tools?
It is callable as an HTTP endpoint by any agent framework through the Apify API — every response is typed JSON, ready to drop into an LLM context window without a parsing step. No dedicated MCP server integration is documented for this Actor.
What happens to a password-protected storefront?
It's reported as storefrontStatus: "password_protected" with the catalogue and contact-discovery fields left empty — the Actor detects the store's own /password redirect and unlock form rather than guessing from body text, so an ordinary open store with a "password" string somewhere in its markup doesn't get misclassified.
Why might primaryEmail or primaryPhone come back empty for some stores?
Because that store genuinely doesn't publish the value anywhere the Actor checks — the homepage, the contact pages tried (per maxContactPages), the policy pages, and any JSON-LD structured data. Per the schema's own measured coverage over a 12-store sample across two runs: email resolved for 9–10 of 12 stores (75–83%), phone for 8 of 12 (67%). The Actor never fills a gap with a constructed value.
What is contactPagesTried versus contactPagesRead?
contactPagesTried is how many paths from contactPagePaths were attempted, bounded by maxContactPages. contactPagesRead is the subset of those that actually resolved to a real page (not a 404, not a password wall) and were read for contact data — so the two numbers diverge whenever a listed path doesn't exist on that particular store.
ℹ️ Disclaimer
Shopify Store Scraper: Emails, Phones & Social Links extracts only publicly available data from Shopify storefronts. This tool is intended for lawful use cases only. Users are responsible for complying with Shopify's terms of service and applicable data protection laws in their jurisdiction.