Skip to Content
CoursesResearch & Web Scraping04 Emails and phones from a site

Pulling Emails and Phones From a Site

Outcome: a contact-recovery column that runs only on rows enrichment missed, with role addresses filtered out and everything verified before use.

Surface
Sync GTM app and MCP server
Level
Beginner
Uses
scrape_emails_from_website · scrape_phones_from_website · verify_email
Credits
~6 for 20 rows
Prerequisite
A run of contact enrichment with some misses

When this is the right tool

Contact databases cover corporate B2B well and everything else patchily. Site scraping fills three specific gaps:

  • Small and local businesses — no LinkedIn presence, but a phone number on every page
  • Non-English markets — thinner database coverage, same public website
  • The tail of any list — the 25% your waterfall missed

It is a fallback, not a first choice. Run it on rows where enrichment returned nothing, not on the whole table.

Reference: scrape_emails_from_website, scrape_phones_from_website.


Where contact details live

PageWhat you find
/contactThe main address and phone, usually a shared inbox
Footer of any pageOften the most reliable single place
/about or /teamIndividual addresses at smaller companies
/support or /helpSupport addresses — usually the wrong target
Legal or imprint pagesRequired disclosures in some markets, and highly reliable where required

The scraper reads the site rather than one path, so you usually do not have to choose. What you do have to do is filter what comes back.


Filtering what you get

A raw scrape returns every address on the site. Most are not useful and some are actively harmful to send to.

Drop the never-send addresses

abuse@, privacy@, legal@, dmca@, postmaster@, noreply@. Mailing these is a complaint waiting to happen.

Separate role addresses from personal ones

info@, hello@, contact@, sales@ are role addresses. Useful in some segments, useless in others — see below.

Drop third-party domains

Addresses whose domain does not match the company. These usually belong to the agency that built the site.

Keep personal addresses

firstname.lastname@company.com — the actual prize, and common on smaller sites.

A simple pattern rule handles most of this as a free formula column.


Is a shared inbox worth it?

Depends entirely on the segment.

SegmentVerdict
Local business, trades, clinics, restaurantsYes. The owner reads it. Often the only route in.
Small agencies and consultancies, under ~20 peopleUsually. Read by someone with authority.
Mid-market B2BRarely. Routed to support or ignored.
EnterpriseNo. Goes nowhere.

And the message must change with the target. A shared inbox is read by someone busy who did not ask to hear from you — short, concrete, and specific to their business, or it is deleted in two seconds.


Verify anyway

Scraped addresses are unverified by definition, and they bounce more than enriched ones — sites carry addresses that were retired years ago.

Run verify_email over every scraped address before it enters any sequence. It is cheap, and it is the difference between recovering the tail of your list and damaging your sending domain to reach it.


Do this now

Filter to the misses

Rows where contact enrichment returned nothing. This is the only input set.

Confirm you have a website

No site means nothing to scrape. Those rows need a different path — phone, LinkedIn, or nothing.

Scrape emails on five rows

Read everything returned, including the addresses you would never send to.

Build the filter

A formula column implementing the four rules above.

Scrape phones on the same rows

Compare against any number you already have. Direct lines beat switchboards.

Verify every email

Then keep only valid.

Measure recovery

What percentage of previously-missing rows now have a contactable path? That number tells you whether this column is worth keeping.


Check your work

  • The column ran only on rows enrichment missed
  • Never-send and third-party addresses are filtered out
  • Role addresses are distinguishable from personal ones
  • Every scraped address has been verified
  • You have a recovery rate figure

Where this breaks

Sending to every address a scrape returns is how a sender reputation gets destroyed in one campaign. Spam-trap and abuse addresses exist on plenty of sites specifically to catch this behaviour, and hitting one has consequences that outlast the campaign by months. The filter is not a tidiness step — it is the point of the lesson.


Further automation

Chain it: enrich → check for a miss → scrape site → verify → merge into one best_contact column with a contact_source field next to it. The source field is what lets you compare reply rates between enriched and scraped contacts later, and that comparison usually justifies or kills the column.


Next lesson

05 — Research agents, moving from “read this page” to “go find out”.

Reference for this lesson: scrape_emails_from_website, scrape_phones_from_website, Verify email, Waterfall Enrichment.