Builds a list of verified business emails from Google Maps, Google SERPs, or a user-supplied URL list. Verification happens inside the same Apify run — no third-party verifier needed. Use when user asks to find verified emails, build a leads list, scrape emails from Maps or SERP, verify emails for a URL list, or find an Apollo / Hunter alternative.
npx skills add https://github.com/apify/awesome-skills --skill apify-verified-email-finder
Return a list of verified business emails by routing the user's input to the right Apify Actor and turning on the leads enrichment + email verification add-ons in a single run. No third-party verifier (Hunter, NeverBounce, Apollo) needed — verification happens inside the same Actor run.
(No need to check it upfront)
The skill supports two execution paths. Pick the one that matches your environment — Steps 4 and 5 show commands for both.
MCP path (default in Claude sessions, recommended). If the Apify MCP server is connected, no setup is needed — auth runs through the user's Apify account. Use the call-actor and get-dataset-items MCP tools.
Script path (CLI / scheduled / non-Claude execution). Requires:
.env file with APIFY_TOKEN--env-file support)Copy this checklist and track progress:
Task Progress:
- [ ] Step 1: Collect the six required anchor inputs
- [ ] Step 2: Route to the correct Actor (confirm if ambiguous)
- [ ] Step 3: Build the Actor input (verification always ON)
- [ ] Step 4: Run the Actor and wait
- [ ] Step 5: Apply the result-scope filter, deduplicate, and render
Ask all six as one block before any Actor call. Don't bundle Actor-specific optional fields (country code, language, max pages) into this round — surface those as follow-ups.
location query / SERP keyword / URL list. This drives the routing decision.c_suite, product, engineering_technical, design, education, finance, human_resources, information_technology, legal, marketing, medical_health, operations, sales, consulting. Default is any (leave the array empty), but ask every time.maximumLeadsEnrichmentRecords. Default 3, but ask every time.CSV or JSON. Ask every time.verified-only (default) — only leads with emailVerification.result == "ok". Safest for cold email.verified-plus-catchall — ok plus catch_all. Catch-all is often deliverable but unprovable.all-emails — any lead with a non-empty email, regardless of verification.with-phone — any lead with a non-empty phone number, regardless of email status. Use for call campaigns.everything — every lead the Actor returned, even incomplete ones.Inspect anchor #1 and pick the Actor.
| User has to start with | Actor ID | Use when |
|---|---|---|
| Location + business type ("dentists in Berlin") | compass/crawler-google-places | Local leads list from Maps listings; best when user wants address / phone / hours too |
| Keyword / search query ("best CRM software") | apify/google-search-scraper | Contacts from whichever sites Google ranks for a topic |
| Pre-existing URL list (pasted, file path) | vdrmota/contact-info-scraper | User already has domains; cheapest route since no discovery step |
All three Actors share the same three add-on fields, so verification behavior is identical across routes.
Decision examples
| User says | Route |
|---|---|
| "Dentists in Munich" / "Lawyers in Prague" | Maps |
| "Marketing contacts at the top results for 'AI agent builder'" | Search |
| "Find emails for these 5 URLs: acme-co.example, demo-co.example..." | URL list |
| "Find HR contacts at Fortune 500 companies" | Ask: SERP for "Fortune 500 HR" or a URL list? |
| "Find contacts at SaaS companies in Berlin" | Ask: Maps for "SaaS companies in Berlin" or SERP for "SaaS companies Berlin"? Maps works best when businesses are Google-Maps-listed. |
| (User pastes both a SERP keyword AND a URL list) | Ask: run one route, the other, or both as separate deliverables? |
Ambiguity rule: if anchor #1 is unclear, ask one follow-up before running. Never burn Actor compute on a guessed route.
Mixed deliverables: if the user explicitly asks for two routes in one deliverable, run both Actors and concatenate. The Source column makes the mix clear; dedupe by email across the combined output.
Always set these three fields, regardless of which Actor is selected.
| Field | Value |
|---|---|
| maximumLeadsEnrichmentRecords | anchor #4 (default 3, min 1) |
| leadsEnrichmentDepartments | anchor #3 as array, or [] if "any" |
| verifyLeadsEnrichmentEmails | true (always) — guard rail, never set to false |
Full per-Actor input parameters and example payloads are in reference/apify-actor-usage.md.
URL-list pre-validation: before submitting URLs to vdrmota/contact-info-scraper, parse each one and check it is http/https and parseable. Skipped entries must appear in the output as skipped — invalid URL, never silently dropped.
Maps and SERP runs with leads enrichment can take several minutes per query. Raise the timeout for large jobs.
MCP path (default in Claude sessions):
Call the call-actor tool:
actor: one of the three Actor IDs (compass/crawler-google-places, apify/google-search-scraper, vdrmota/contact-info-scraper)input: the JSON payload from Step 3callOptions: {"timeout": 1800, "memory": 4096} for a generous budgetThe tool returns runId and datasetId. If status is still RUNNING, poll with get-actor-run (waitSecs up to 45) until SUCCEEDED. Capture both IDs for the run_metadata.json sidecar.
Script path (CLI / scheduled use):
node --env-file=.env ${CLAUDE_PLUGIN_ROOT}/reference/scripts/run_actor.js \
--actor "ACTOR_ID" \
--input 'JSON_INPUT' \
--output YYYY-MM-DD_verified-emails.csv \
--format csv \
--timeout 900
Use --format json for JSON. The script writes the raw dataset to disk; Step 5 still applies the spurious-match + scope filters on top.
Pull the dataset:
get-dataset-items with the datasetId from Step 4. Use the fields parameter (e.g., title,searchString,countryCode,city,address,phone,website,leadsEnrichment) and clean: true to keep the response small. For datasets that still exceed the response cap, fetch directly via curl https://api.apify.com/v2/datasets/<id>/items?fields=...&clean=true and pipe through jq.Each record contains business fields plus a leadsEnrichment array (Maps, SERP) or top-level lead fields (URL list). Each lead has a departments array, a companyWebsite, and an emailVerification object with result (ok / invalid / disposable / catch_all / unknown / error) and quality (good / risky / bad).
companyWebsite=zoo.org was attributed to 8 unrelated Polish zoos because the matcher latched onto the zoo substring). Drop any lead whose companyWebsite hostname doesn't equal the source URL's hostname (strip https?://, leading www., anything after /; lowercase). Count drops in run_metadata.json and call them out in the deliverable header if non-zero.| Scope | Row-keep logic |
|---|---|
| verified-only | emailVerification.result == "ok" |
| verified-plus-catchall | emailVerification.result in {"ok", "catch_all"} |
| all-emails | email is non-empty (any result, including missing verification) |
| with-phone | phone (or company phone) is non-empty (regardless of email) |
| everything | keep every lead, no filter |
Source Query or URL if the same email appears from multiple sources. For with-phone rows that have no email, dedupe by lowercased phone instead.Email = "" and Email Verification Status = "no leads matched filter". Do not silently drop it. This is separate from the result-scope filter above — empty-domain rows are inserted before scope-filtering and always shown.Output row schema (16 columns, including Departments) and per-format rendering details are in reference/output-formats.md.
verifyLeadsEnrichmentEmails: false.Source column on every row; carry Apify runId + datasetId in run_metadata.json.Email verification is charged only for decisive results (ok / invalid / disposable); catch_all / unknown / error are free. Leads enrichment is charged per successfully extracted lead. Check the Apify console for live rates (they vary by subscription tier and change over time).
See reference/troubleshooting.md.
Analyzes meeting transcripts and recordings to uncover behavioral patterns, communication insights, and actionable feedback. Identifies when you avoid conflict, use filler words, dominate conversations, or miss opportunities to listen. Perfect for professionals seeking to improve their communication and leadership skills.
Toolkit for creating animated GIFs optimized for Slack, with validators for size constraints and composable animation primitives. This skill applies when users request animated GIFs or emoji animations for Slack from descriptions like "make me a GIF for Slack of X doing Y".
Analyzes your recent Claude Code chat history to identify coding patterns, development gaps, and areas for improvement, curates relevant learning resources from HackerNews, and automatically sends a personalized growth report to your Slack DMs.
Knowledge and utilities for creating animated GIFs optimized for Slack. Provides constraints, validation tools, and animation concepts. Use when users request animated GIFs for Slack like "make me a GIF of X doing Y for Slack.
A skill that creates new Claude skills and automatically shares them on Slack using Rube for seamless team collaboration and skill discovery.
Automate Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify, etc.) using agent-browser via Chrome DevTools Protocol. Use when the user needs to interact with an Electron app, automate a desktop app, connect to a running app, control a native app, or test an Electron application. Triggers include "automate Slack app", "control VS Code", "interact with Discord app", "test this Electron app", "connect to desktop app", or any task requiring automation of a native Electron application.
Prepare meeting materials with Notion context and Codex research; use when gathering context, drafting agendas/pre-reads, and tailoring materials to attendees.
Interactive daily standup/meeting update generator. Use when user says 'daily', 'standup', 'scrum update', 'status update', 'what did I do yesterday', 'prepare for meeting', 'morning update', or 'team sync'. Pulls activity from GitHub, Jira, and Claude Code session history. Conducts 4-question interview (yesterday, today, blockers, discussion topics) and generates formatted Markdown update.
Take apify/apify-verified-email-finder from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.