Med Spa Lead Discovery - Emails, Scores & Personalization Hooks avatar

Med Spa Lead Discovery - Emails, Scores & Personalization Hooks

Under maintenance

Pricing

Pay per event

Go to Apify Store
Med Spa Lead Discovery - Emails, Scores & Personalization Hooks

Med Spa Lead Discovery - Emails, Scores & Personalization Hooks

Under maintenance

Find med spa leads with emails, lead scores, and personalized outreach hooks. Built for agencies and SaaS companies targeting aesthetic clinics.

Pricing

Pay per event

Rating

0.0

(0)

Developer

George Kioko

George Kioko

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Share

MedSpa Lead Discovery PPE

Apify Actor Pay Per Event TypeScript

Budget-aware lead discovery engine for MedSpa and medical aesthetics businesses. Finds outreach-ready leads with ICP scoring, decision maker identification, and personalization signals -- all with pay-per-event pricing so you only pay for results.


How It Works

flowchart LR
A["Keywords\n+ Locations"] --> B["Discovery\n(Search + Directories)"]
B --> C["Domain\nProbing"]
C --> D["Deep\nCrawl"]
D --> E["Lead\nExtraction"]
E --> F["ICP\nScoring"]
F --> G["Classification"]
G --> H["Outreach-Ready\nLeads"]
style A fill:#4CAF50,color:#fff
style H fill:#2196F3,color:#fff
style F fill:#FF9800,color:#fff
style G fill:#9C27B0,color:#fff

The actor follows a multi-stage pipeline:

  1. Discovery -- Searches Google, Bing, and MedSpa directories using your keywords and locations
  2. Domain Probing -- Validates discovered domains are live, relevant, and worth crawling
  3. Deep Crawling -- Uses Cheerio crawler to extract structured data from each domain (about pages, team pages, contact pages, service pages)
  4. Lead Extraction -- Pulls business name, address, phone, email, social profiles, services offered, and team members
  5. ICP Scoring -- Scores each lead against your Ideal Customer Profile (services match, location, size signals, online presence)
  6. Quality Scoring -- Rates data completeness, contact info availability, and freshness
  7. Classification -- Labels each lead as outreachReady, needsManualReview, or rejected
  8. Output -- Delivers structured LeadRecords with personalization hooks for your outreach

Architecture

flowchart TB
subgraph Input
KW["Keywords"]
LOC["Locations"]
SEED["Seed URLs / CSV"]
end
subgraph Core["Actor Core"]
BG["BudgetGovernor\n(cost control)"]
DA["Discovery Adapters\n(Search, Directories, Seeds)"]
PROBE["Probe Crawler\n(domain validation)"]
DEEP["Deep Crawler\n(Cheerio-based extraction)"]
SC["Scorer\n(ICP + Quality)"]
CL["Classifier\n(readiness labeling)"]
end
subgraph Output
READY["Outreach-Ready\nLeads"]
REVIEW["Needs Manual\nReview"]
REJ["Rejected"]
end
KW --> DA
LOC --> DA
SEED --> DA
DA --> BG
BG --> PROBE
PROBE --> DEEP
DEEP --> SC
SC --> CL
CL --> READY
CL --> REVIEW
CL --> REJ
style BG fill:#E53935,color:#fff
style SC fill:#FF9800,color:#fff
style CL fill:#9C27B0,color:#fff
style READY fill:#4CAF50,color:#fff

BudgetGovernor tracks spend in real time and halts crawling when your budget ceiling is reached. You never get a surprise bill.


Pricing

EventPriceWhen Charged
Outreach-ready lead$0.01Each lead classified as outreachReady with verified contact info
Decision maker contact$0.005Bonus when a lead includes direct contact for an owner, CEO, manager, or director

Example: 100 outreach-ready leads with 40 decision maker contacts = $1.00 + $0.20 = $1.20 total

You pay nothing for leads classified as needsManualReview or rejected. Zero upfront cost -- pure pay-per-result.

Safety Controls

  • One base charge per leadId per run (no duplicate billing)
  • maxBudgetUsd hard ceiling enforced by BudgetGovernor
  • Zero charges when a lead does not pass billing quality gates
  • Full billing telemetry in RUN_SUMMARY.billingMeta

Use Cases

mindmap
root((MedSpa Lead\nDiscovery))
MedSpa Agencies
Client prospecting
Territory mapping
Competitive analysis
Healthcare Marketing
Campaign targeting
Market research
Service gap analysis
Local Lead Gen
City-by-city sweeps
New market entry
Franchise prospecting
Outreach Automation
CRM enrichment
Email campaign lists
Personalized sequences

Input Schema

ParameterTypeRequiredDefaultDescription
keywordsstring[]No*["med spa", "medical spa", "medspa"]Search terms for discovery
locationsstring[]No*--Geographic targets (e.g., ["Miami FL", "Los Angeles CA"])
seedUrlsstring[]No[]Direct URLs to include (skips discovery phase)
seedCsvTextstringNo--Raw CSV text with seed domains for batch ingestion
seedCsvUrlColumnstringNo--Column name in CSV containing URLs
seedCsvDomainColumnstringNo--Column name in CSV containing domains
maxLeadsnumberNo100Maximum outreach-ready leads to return
modestringNo"balanced"Crawl mode: fast, balanced, or high_precision
qualityThresholdnumberNo0.6Minimum quality score (0-1) for outreach-ready classification
icpThresholdnumberNo0.5Minimum ICP score (0-1) for outreach-ready classification
maxBudgetUsdnumberNo5.0Budget ceiling in USD (BudgetGovernor enforced)
maxPagesPerDomainProbenumberNo--Max pages crawled during probe phase
maxPagesPerDomainDeepnumberNo--Max pages crawled during deep phase
maxJsRendersnumberNo--Cap on JavaScript-rendered pages (controls cost)
maxRuntimeSecondsnumberNo--Hard runtime limit
includeRejectedbooleanNofalseInclude rejected leads in output (useful for debugging)
enableDecisionMakerSearchbooleanNotrueDeep-search for owner/CEO/manager contacts

*At least locations or seedUrls is required.

Mode Comparison

ModeSpeedDepthBest For
fastFastestHomepage + contact page onlyQuick prospecting sweeps, lowest cost
balancedMediumHomepage + about + team + contact + servicesGeneral production use
high_precisionSlowestFull site crawl (up to 20 pages/domain)Maximum data quality on harder domains

Example Input

{
"keywords": ["med spa", "medical spa", "aesthetic clinic"],
"locations": ["Miami FL", "Fort Lauderdale FL", "West Palm Beach FL"],
"mode": "balanced",
"maxLeads": 50,
"maxBudgetUsd": 3.0
}

Output Schema

Each lead in the output dataset is a LeadRecord with the following structure:

FieldTypeDescription
businessNamestringCompany name
domainstringWebsite domain
urlstringPrimary URL crawled
addressobject{ street, city, state, zip, country }
phonestringPrimary phone number
emailstringPrimary contact email
emailsobject{ general, decisionMaker: { email, name, title, source } }
socialProfilesobject{ facebook, instagram, linkedin, tiktok, youtube }
servicesstring[]Services offered (Botox, fillers, laser, CoolSculpting, etc.)
brandAffiliationsstring[]Brand partnerships (Allergan, Galderma, etc.)
teamMembersobject[][{ name, title, email, phone, isDecisionMaker }]
decisionMakerobject{ name, title, email, phone } (if found)
nicheVerificationobject{ score, positiveSignals[], negativeSignals[], verdict }
icpScorenumberIdeal Customer Profile fit (0-1)
qualityScorenumberData completeness score (0-1)
readinessClassstringoutreachReady, needsManualReview, or rejected
rejectionReasonsstring[]Why a lead was rejected (when applicable)
personalizationHooksstring[]Source-backed talking points for outreach
painSignalsstring[]Issues detected (slow website, no booking system, old blog)
serviceGapsstring[]Services competitors offer that this lead does not
brandVoiceSnippetsstring[]Tone/language clues for matching outreach voice
bookingFlowSignalstringOnline booking status detected
discoverySourcestringHow the lead was found (google_search, directory, seed)
crawledAtstringISO timestamp of extraction

Example Output

{
"businessName": "Glow Aesthetics Miami",
"domain": "glowaestheticsmiami.com",
"url": "https://glowaestheticsmiami.com",
"address": { "street": "1455 Brickell Ave, Suite 220", "city": "Miami", "state": "FL", "zip": "33131" },
"phone": "+1-305-555-0234",
"emails": {
"general": "hello@glowaestheticsmiami.com",
"decisionMaker": {
"email": "dr.santos@glowaestheticsmiami.com",
"name": "Dr. Maria Santos",
"title": "Medical Director & Owner",
"source": "team_page"
}
},
"services": ["Botox", "Juvederm Fillers", "Laser Hair Removal", "Chemical Peels", "Microneedling"],
"brandAffiliations": ["Allergan", "Galderma"],
"icpScore": 0.87,
"qualityScore": 0.91,
"readinessClass": "outreachReady",
"personalizationHooks": [
"No online booking system detected -- competitors in Brickell all have one",
"Google reviews average 3.9 stars, below the Miami medspa average of 4.4"
],
"painSignals": ["Website loads in 6.8s (poor)", "Last blog post is 8 months old"],
"discoverySource": "google_search",
"crawledAt": "2026-03-22T09:45:12Z"
}

Run Summary

Each run also produces a RUN_SUMMARY in the key-value store with efficiency KPIs:

  • candidatesDiscovered / domainsAfterDedupe / outreachReadyCount
  • pagesPerOutreachReadyLead / requestsPerOutreachReadyLead
  • Rejection reason distribution
  • billingMeta with charge counts and skip reasons

Scoring Explained

ICP Score (0-1)

The Ideal Customer Profile score measures how well a lead matches the typical high-value MedSpa prospect:

SignalWeightWhat It Measures
Services breadth25%Number and variety of aesthetic services offered
Location match20%Proximity to your target locations
Online presence20%Website quality, social media activity, review count
Size indicators15%Multi-location, team size, facility indicators
Tech adoption10%Online booking, modern website, active social
Engagement signals10%Blog activity, promotions, events

Quality Score (0-1)

The quality score rates data completeness and reliability:

SignalWeightWhat It Measures
Contact info completeness30%Phone + email + address all present
Decision maker identified25%Owner/CEO/manager name and contact found
Data freshness20%Website recently updated, active social presence
Verification level15%Email format validated, phone format checked
Enrichment depth10%Services listed, team page found, about page present

Niche Verification

Before deep crawling, every domain is scored against curated signal lists:

  • Positive signals: "botox", "filler", "aesthetic nurse", "medical director", "medspa"
  • Negative signals: "nail salon", "hair stylist", "massage only", "day spa"
  • Domains below the niche threshold are rejected early, saving crawl budget

Classification Rules

ClassCriteria
outreachReadyICP score >= threshold AND quality score >= threshold AND at least one verified contact method
needsManualReviewOne score below threshold but the other is high, OR contact info is partial
rejectedBoth scores below threshold, OR domain fails niche verification, OR no contact info found

Rejected leads include explicit rejectionReasons so you can understand why and adjust thresholds if needed.


AI Agent Integration

JavaScript (Apify Client)

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('george.the.developer/medspa-lead-discovery-ppe').call({
keywords: ['med spa', 'medical aesthetics', 'botox clinic'],
locations: ['Miami FL', 'Fort Lauderdale FL'],
maxLeads: 100,
mode: 'balanced',
qualityThreshold: 0.7,
icpThreshold: 0.6,
maxBudgetUsd: 3.0,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const outreachReady = items.filter(lead => lead.readinessClass === 'outreachReady');
console.log(`Found ${outreachReady.length} outreach-ready MedSpa leads`);
for (const lead of outreachReady) {
console.log(`${lead.businessName} | ${lead.emails?.general} | ICP: ${lead.icpScore}`);
console.log(` Hook: ${lead.personalizationHooks?.[0]}`);
}

Python (Apify Client)

from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("george.the.developer/medspa-lead-discovery-ppe").call(run_input={
"keywords": ["med spa", "medical aesthetics", "botox clinic"],
"locations": ["Miami FL", "Fort Lauderdale FL"],
"maxLeads": 100,
"mode": "balanced",
"qualityThreshold": 0.7,
"icpThreshold": 0.6,
"maxBudgetUsd": 3.0,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
outreach_ready = [lead for lead in items if lead["readinessClass"] == "outreachReady"]
print(f"Found {len(outreach_ready)} outreach-ready MedSpa leads")
for lead in outreach_ready:
print(f"{lead['businessName']} | {lead['emails']['general']} | ICP: {lead['icpScore']}")

cURL

# Start the actor run
curl -X POST "https://api.apify.com/v2/acts/george.the.developer~medspa-lead-discovery-ppe/runs" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"keywords": ["med spa", "medical aesthetics"],
"locations": ["Los Angeles CA"],
"maxLeads": 50,
"mode": "balanced",
"maxBudgetUsd": 3.0
}'
# Fetch results as JSON
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?format=json" \
-H "Authorization: Bearer YOUR_API_TOKEN"
# Fetch results as CSV for CRM import
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?format=csv" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-o medspa_leads.csv

FAQ

Q: How many leads can I expect per run? A: It depends on your keywords, locations, and mode. A balanced run for a major US metro typically finds 30-80 outreach-ready leads. Use high_precision mode for maximum coverage.

Q: What if I hit my budget ceiling mid-run? A: The BudgetGovernor stops crawling immediately and returns all leads discovered up to that point. You will never be charged more than maxBudgetUsd.

Q: Can I use seed URLs instead of keywords? A: Yes. Pass URLs via seedUrls or batch domains via seedCsvText. The actor skips the discovery phase and goes straight to domain probing and deep crawling. Great for enriching an existing list with quality scores and personalization hooks.

Q: How does niche verification work? A: The actor scores each discovered website against curated lists of positive signals (e.g., "botox", "filler", "medical director") and negative signals (e.g., "nail salon", "hair stylist"). Sites that fail the niche check are rejected before deep crawl, saving budget.

Q: What counts as a "decision maker"? A: Owners, CEOs, founders, medical directors, practice managers, and office managers. The actor identifies them from team pages, about pages, LinkedIn references, and structured data.

Q: Do I get charged for rejected leads? A: No. You only pay for leads classified as outreachReady. The decision maker bonus is only charged when a decision maker contact is actually found on an outreach-ready lead.

Q: Can I integrate this into my CRM workflow? A: Absolutely. Use the Apify API or webhooks to push results directly into HubSpot, Salesforce, or any CRM. Export as CSV with ?format=csv for direct import.

Q: What is the difference between PPE and Pro? A: Both versions use the same discovery engine and the same pricing. PPE (Pay Per Event) is the original release. MedSpa Lead Discovery Pro is the same actor with professional branding.

Q: Is this compliant with data privacy regulations? A: This actor performs discovery and enrichment only. It does not send any outbound communications. You are responsible for lawful contact sourcing and required consent/opt-out handling in your outbound systems.


Support