Shopify New Store Scraper – Daily Leads by Pixels
Under maintenancePricing
from $5.00 / 1,000 store detecteds
Shopify New Store Scraper – Daily Leads by Pixels
Under maintenanceShopify store scraper that detects newly launched stores in real time. Get a deduplicated list of new Shopify store URLs with country and first-seen date, updated daily. Ideal for ecommerce lead generation, cold outreach, and Shopify app marketing. Export to CSV, JSON, or Excel.
Pricing
from $5.00 / 1,000 store detecteds
Rating
5.0
(1)
Developer
Mohit Shyani
Maintained by CommunityActor stats
2
Bookmarked
2
Total users
1
Monthly active users
7 days ago
Last modified
Categories
Share
Store Radar — Shopify new-store detector (Railway-ready)
Always-on service that watches the Certificate Transparency firehose, verifies which newly-issued certs belong to Shopify stores, and writes one CSV per day. A built-in web page lets you watch status and download the leads from anywhere — no SSH.
It needs a certstream firehose to read from. The public one
(certstream.calidog.io) is offline most of the time, so you run your own. Total
setup is two Railway services and about five minutes.
Architecture
┌─────────────────────────┐ ┌────────────────────────────┐│ certstream (service 1) │ ws │ store-radar (service 2) ││ reloading01/ │───────▶│ this repo ││ certstream-server-rust │ │ • DNS-verifies vs Shopify ││ (public Docker image) │ │ • writes daily CSV │└─────────────────────────┘ │ • serves status + CSV │└────────────────────────────┘│ https▼you: open the URL,download today.csv
Step 1 — Deploy the certstream firehose (service 1)
- In your Railway project: New → Deploy from Docker Image.
- Image:
ghcr.io/reloading01/certstream-server-rust:latest - Under Settings → Networking, click Generate Domain (public URL). The server listens on 8080; set the public port to 8080 if asked.
- Copy the public domain, e.g.
certstream-production.up.railway.app.
That's the whole service — no code. (Optional: set a bearer token via its env vars if you don't want the stream open to the world. See its docs.)
Why a public domain instead of Railway's private network? Private networking is IPv6-only and the rust server binds IPv4 by default, so the public URL is the reliable path. The traffic is public CT data anyway.
Step 2 — Deploy this detector (service 2)
-
Push this folder to a GitHub repo (or use the Railway CLI).
-
Railway: New → Deploy from GitHub repo → pick it. It builds from the
Dockerfileautomatically (config inrailway.json). -
Variables → add:
Variable Value CERTSTREAM_URLwss://certstream-production.up.railway.app/(your service-1 domain,wss://)OUT_DIR/dataSMART_FILTER1HTTP_VERIFY0(set1to also grab.myshopify.comhandles — slower)NICHE(optional) apparel,bespoke,jewelto log only matching domainsWORKERS200(concurrent DNS-verification workers)DNS_THREADS256(getaddrinfo thread pool; raise for more DNS throughput)DNS_TIMEOUT5(seconds before a slow DNS lookup is given up on)NEW_ONLY0(set1to log only new domains, dropping cert renewals of existing stores)NEW_WINDOW_DAYS7(a domain is "new" if its earliest-ever cert is within this many days)KEEP_UNKNOWN1(inNEW_ONLYmode, still log rows whose age couldn't be determined; set0to drop them)CRTSH_CONCURRENCY3(max simultaneous crt.sh history lookups) -
Settings → Networking → Generate Domain for this service too.
-
Settings → Volumes → New Volume, mount path
/data. (Railway disks are ephemeral; the volume keeps your CSVs across restarts and redeploys.)
Step 3 — Use it
Open the detector's public URL:
/— live status: certs seen, stores found, finds/min, recent hits (now with a country column). Auto-refreshes./today.csv— download today's leads./shopify_new_stores_YYYY-MM-DD.csv— any past day (listed on the status page)./stores.json— last 200 finds as JSON (handy to wire into your pipeline)./countries— deduped leads split by country. One downloadable CSV per country plus a combined deduped file.
Deduped, country-split leads
The raw daily CSVs log every detected host, so the same store often appears
several times: bellemo.shop, www.bellemo.shop, account.bellemo.shop. The
organizer collapses every host to its registrable domain (so those three
become the single store bellemo.shop) and splits the result by country.
Country comes from the domain's TLD: country-code TLDs (.co.uk → UK, .de →
Germany, .com.au → Australia, .ca → Canada …) map to a country; generic TLDs
(.com, .shop, .store, .online …) and vanity ccTLDs (.co, .io, .me …)
go to a GENERIC bucket. (GeoIP on the resolved IP can't help — every store
points at Shopify's own IP block, so the IP only tells you where Shopify is.)
From the web UI: open /countries, click Rebuild from raw CSVs, then
download per-country files (/by-country/UK.csv, /by-country/AU.csv, …) or the
whole deduped set (/deduped.csv).
From the command line:
python organize_stores.py # organize every CSV in ./outpython organize_stores.py --in-dir ./out --out-dir ./out/organizedpython organize_stores.py "out/200000+ stores.csv" # one specific filepython organize_stores.py --colombia-real # treat .co/.io/.me as their real country
Output (under --out-dir, default ./out/organized):
| File | What |
|---|---|
all_stores_deduped.csv | every unique store, with registrable_domain, country_code, country, and the subdomains that were collapsed |
by_country/<CC>.csv | one file per country (UK.csv, AU.csv, DE.csv, GENERIC.csv, …) |
by_country/_index.csv | country, store count, file — a summary |
Columns:
registrable_domain, country_code, country, seen_host, subdomains, detected_at, myshopify_handle, resolved_ip, type, signal, freshnessRun locally (to test before deploying)
pip install -r requirements.txt# Point at your own certstream, or try the public one (often down):export CERTSTREAM_URL="wss://YOUR-certstream-host/"export OUT_DIR="./out"python store_radar_service.py# open http://localhost:8080
Run certstream locally too if you want a fully local stack:
docker run -d -p 8080:8080 ghcr.io/reloading01/certstream-server-rust:latestexport CERTSTREAM_URL="ws://localhost:8080/"
What it catches (and what it doesn't)
- Strong: stores that connect a custom domain and enable managed SSL — your best leads, caught within seconds of going live.
- Weak: free
*.myshopify.comstores often sit behind a wildcard cert and won't always appear; Cloudflare-fronted stores won't resolve to Shopify's IPs. SMART_FILTERnarrows to Let's-Encrypt + few-SAN certs (the managed-SSL pattern) to keep DNS volume sane. Turn it off to check everything (much heavier).- This is a high-signal daily stream, not a complete census of every new store.
New vs renewal
The CT firehose fires on certificate issuance, which mixes brand-new stores with existing stores whose SSL cert just auto-renewed. To tell them apart, each confirmed custom-domain store is checked against crt.sh: we take the earliest certificate ever issued for that domain and classify it.
new— earliest cert is withinNEW_WINDOW_DAYS(default 7) → likely a store that just came online.renewal— earliest cert is older → an existing store renewing SSL.unknown— crt.sh lookup failed, timed out, or returned nothing. crt.sh is slow and rate-limited, so this happens;*.myshopify.com(cert-SAN) rows are alwaysunknownbecause wildcard certs make crt.sh unreliable for them.
Set NEW_ONLY=1 to write only new (and unknown, unless KEEP_UNKNOWN=0) rows.
Lookups run behind a small concurrency cap (CRTSH_CONCURRENCY) with a 10s timeout,
one retry, and an in-memory cache, so they never starve DNS verification.
Caveat: this detects a new domain, not strictly a new Shopify store. A domain that existed on another platform (Wix, WooCommerce, a static site…) and later migrated to Shopify will have old certs and so look like a
renewal, even though the store is brand new on Shopify. Treatnewas high-confidence andrenewal/unknownas worth a second look rather than a hard exclusion.
Output columns
detected_at, domain, myshopify_handle, resolved_ip, type, signal, freshness
type is myshopify (cert SAN) or custom; signal is how it was confirmed
(cert, dns, or fingerprint); freshness is new, renewal, or unknown
(see New vs renewal).