# Website Contact & Tech Stack Enricher (`aimindteams/website-contact-tech-enricher`) Actor

Turn company websites into lead-ready rows: ranked emails, E.164 phones, LinkedIn and social profiles, address, 260+ tech stack fingerprints, email provider from DNS, domain age and careers page. One row per website, no API keys.

- **URL**: https://apify.com/aimindteams/website-contact-tech-enricher.md
- **Developed by:** [AIMindTeams](https://apify.com/aimindteams) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 website enricheds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Website Contact & Tech Stack Enricher

**Turn a list of company websites into lead-ready rows.** Paste domains or URLs and get one clean row per company with everything a sales or research team needs to qualify it:

- **Emails**, ranked so the best inbox (sales@, hello@, contact@, info@ or a named person on the company domain) comes first
- **Phone numbers** in international E.164 format, validated per country
- **Social profiles**: LinkedIn company page, X/Twitter, Facebook, Instagram, YouTube, TikTok, GitHub, Pinterest, Crunchbase
- **Company name and postal address** from the site's structured data
- **Tech stack**: 260+ technologies across CMS and site builders, ecommerce, analytics, ad pixels, marketing automation, CRM and sales tools, live chat, payments, hosting and frameworks
- **Email setup from DNS**: mailbox provider (Google Workspace, Microsoft 365 ...), email-sending services (HubSpot, Salesforce, SendGrid ...) and verified SaaS tools
- **Domain age**, registrar and expiry date from the official RDAP registry
- **Careers page and hiring system** (Greenhouse, Lever, Ashby, Workday ...)

No API keys, no logins and no browser. Press **Start** to see three sample websites enriched in seconds.

***

### Why this Actor exists

Most contact scrapers return one row per *page* and leave you to merge them. Tech-stack lookups, email-provider checks and domain-age checks usually live in separate paid tools. This Actor does all of it in one pass and returns **one row per website**, ready for a CRM import or a spreadsheet.

| | Typical contact scraper | **Website Contact & Tech Stack Enricher** |
|---|---|---|
| Emails and phones | Per page, unranked | **Per website, ranked, deduplicated** |
| Cloudflare-protected emails and "name \[at] domain \[dot] com" | Often missed | **Decoded** |
| Phone validation | Raw text | **E.164, validated per country** |
| Social profiles | Sometimes | **9 networks, company page preferred** |
| Tech stack | No | **260+ fingerprints** |
| Email provider and sending tools (DNS) | No | **Yes** |
| Domain age and registrar | No | **Yes** |
| Careers page and hiring system | No | **Yes** |
| Billing | Per page | **Per website** |

***

### How it works

1. **Normalize** every input (domain, URL, even an email address) and remove duplicates.
2. **Load the homepage** (following redirects to the brand's real domain) and pick the most promising contact, imprint, about and team pages. If no contact page is linked, common paths like `/contact` are tried.
3. **Extract** emails (including Cloudflare-obfuscated ones), phones, social links, schema.org company data and the careers page from each page.
4. **Fingerprint** the tech stack from HTML, response headers, cookies and the generator tag.
5. **Query DNS-over-HTTPS** for MX, SPF, DMARC and verification records, and **RDAP** for registration dates.
6. **Push one row** per website and charge one event for it.

Websites that block automated visitors still return their DNS email setup and domain data at a much lower price, and domains that don't exist are never charged.

***

### Quick start

1. Paste your websites into **Websites**, one per line (domains or URLs both work).
2. Press **Start**.
3. Open the **Overview** tab for a spreadsheet-style table, or export CSV, Excel or JSON.

Example input:

```json
{
    "websites": ["acme.com", "https://www.example-store.com", "northwind-analytics.com/contact"],
    "maxPagesPerSite": 4,
    "companyEmailsOnly": false
}
```

***

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `websites` | array of strings | 3 samples | Domains or URLs to enrich. Duplicates are removed. |
| `maxPagesPerSite` | integer (1 to 10) | 4 | Homepage plus the best contact, imprint, about and team pages. Billing is per website, not per page. |
| `companyEmailsOnly` | boolean | false | Keep only addresses on the company's own domain. |
| `detectTechnologies` | boolean | true | Fingerprint the tech stack. |
| `checkDns` | boolean | true | Read MX, SPF, DMARC and verification records. |
| `lookupDomainAge` | boolean | true | Registration and expiry dates from RDAP. |
| `defaultCountry` | string | US | Country used to read local phone numbers when the site doesn't reveal one. |
| `maxConcurrency` | integer (1 to 20) | 5 | Websites processed in parallel. |

***

### Output

One dataset item per website. Shortened example:

```json
{
    "input": "northwind.co",
    "domain": "northwind.co",
    "url": "https://northwind-analytics.com/",
    "status": "ok",
    "company_name": "Northwind Analytics, Inc.",
    "best_email": "sales@northwind-analytics.com",
    "emails": [
        { "email": "sales@northwind-analytics.com", "type": "role", "is_company_domain": true, "source_url": "https://northwind-analytics.com/contact/" },
        { "email": "jane@northwind-analytics.com", "type": "personal", "is_company_domain": true, "source_url": "https://northwind-analytics.com/about-us" }
    ],
    "best_phone": "+14155550132",
    "phones": [
        { "number": "+14155550132", "national_format": "(415) 555-0132", "country": "US", "source": "tel-link", "source_url": "https://northwind-analytics.com/contact/" }
    ],
    "social_profiles": {
        "linkedin": "https://www.linkedin.com/company/northwind-analytics",
        "twitter": "https://x.com/northwind",
        "facebook": "https://www.facebook.com/northwindanalytics"
    },
    "address": { "street": "500 Howard St", "city": "San Francisco", "region": "CA", "postal_code": "94105", "country": "US" },
    "tech_summary": {
        "cms": ["WordPress"],
        "analytics": ["Google Analytics"],
        "marketing_automation": ["HubSpot"],
        "live_chat": ["Intercom"],
        "hosting_cdn": ["Cloudflare"]
    },
    "cms_platform": "WordPress",
    "ecommerce_platform": null,
    "dns": {
        "email_provider": "Google Workspace",
        "mx_records": ["aspmx.l.google.com", "alt1.aspmx.l.google.com"],
        "spf_services": ["Google Workspace", "SendGrid"],
        "verified_services": ["Google Search Console"],
        "has_dmarc": true
    },
    "domain_info": { "registered_domain": "northwind-analytics.com", "created": "2015-03-02", "age_years": 11.6, "registrar": "Namecheap, Inc." },
    "hiring": { "careers_url": "https://northwind-analytics.com/careers", "ats": "Lever", "ats_board_url": "https://jobs.lever.co/northwind" },
    "pages_scanned": ["https://northwind-analytics.com/", "https://northwind-analytics.com/contact/", "https://northwind-analytics.com/about-us"],
    "charged_event": "website-enriched",
    "scanned_at": "2026-10-17T18:25:47Z"
}
```

**Status values**

| `status` | Meaning | Charged |
|---|---|---|
| `ok` | The website loaded and was fully enriched. | `website-enriched` |
| `website-unreachable` | The site was down or blocked automated visitors. DNS email setup and domain data are still returned. | `domain-checked` (only if any data was found) |
| `domain-not-found` | The domain has no DNS records (expired or mistyped). | Free |

Every run also writes a **run summary** to the `OUTPUT` record of the default Key-Value Store (counts, emails found, invalid inputs and warnings).

***

### Pricing (Pay-Per-Event)

| Event | When | Price |
|---|---|---|
| `website-enriched` | A website loaded and was enriched | See the **Pricing** tab |
| `domain-checked` | The site was unreachable but DNS or domain data was returned | A fraction of the full price |

- You pay **per website**, never per page, DNS query or technology.
- Domains that don't exist are free.
- Your run's maximum charge is respected: the Actor checks the remaining budget **before** each website and stops cleanly when it runs out.

***

### Use cases

- **Lead enrichment**: turn a list of company domains from a trade-show list, directory or CRM export into emails, phones and LinkedIn pages.
- **Technographic targeting**: find Shopify stores using Klaviyo, WordPress sites without analytics, or companies running HubSpot.
- **Email deliverability and IT research**: who runs on Google Workspace vs. Microsoft 365, who has DMARC, who sends through SendGrid.
- **Agency prospecting**: spot outdated stacks (old builders, no tag manager, no chat) and pitch upgrades.
- **Data hygiene**: flag dead or expired domains before an outreach campaign.

***

### Use it from AI agents (MCP)

Every input field has a default and a plain-language description, so AI agents can call this Actor without any setup.

**Hosted Apify MCP server** (Claude, ChatGPT, Cursor, VS Code and any client that supports remote MCP):

```
https://mcp.apify.com?tools=AIMindTeams/website-contact-tech-enricher
```

**Local stdio server** (for example, Claude Desktop `claude_desktop_config.json`):

```json
{
    "mcpServers": {
        "website-enricher": {
            "command": "npx",
            "args": ["-y", "@apify/actors-mcp-server", "--tools", "AIMindTeams/website-contact-tech-enricher"],
            "env": { "APIFY_TOKEN": "YOUR_APIFY_TOKEN" }
        }
    }
}
```

Example prompts:

- "Enrich these 20 domains and give me the best email, phone and LinkedIn page for each."
- "Which of these stores run Shopify and use Klaviyo for email?"
- "Check whether these companies use Google Workspace or Microsoft 365."

***

### Use it from code

**Python** (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("AIMindTeams/website-contact-tech-enricher").call(
    run_input={"websites": ["acme.com", "example-store.com"], "companyEmailsOnly": True}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["input"], item["best_email"], item["best_phone"], item["tech_summary"]["cms"], item["dns"]["email_provider"])
```

**cURL** (run and get the items in one call):

```bash
curl -X POST "https://api.apify.com/v2/acts/AIMindTeams~website-contact-tech-enricher/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"websites": ["acme.com"]}'
```

***

### FAQ

**Does it need a browser or proxies?**
No. It reads the HTML that websites send, which contains contacts, structured data and technology fingerprints for the vast majority of company sites. That keeps it fast and cheap.

**What if a site blocks automated visitors?**
You still get the DNS email setup and domain registration data for that site, billed as the low-cost `domain-checked` event, and the `status_reason` says what happened.

**How are emails ranked?**
Company-domain inboxes come first: sales@, hello@, contact@, info@ and similar, then named people on the company domain, then addresses on other domains. No-reply addresses are never chosen as the best email.

**Does it guess or verify emails?**
It only returns addresses that are published on the website (including obfuscated ones it decodes). It does not guess patterns or send test emails.

**How accurate is the tech stack?**
Each technology is matched on a product-specific asset host, global variable, header or cookie, and the `evidence` field says which one. A plain mention of a brand in page text never counts.

**Is this legal?**
The Actor only reads publicly available pages and public DNS and registry data. You are responsible for using contact data in line with the laws that apply to you (for example GDPR and CAN-SPAM).

***

### More from AIMindTeams

- [Career Site Jobs Scraper](https://apify.com/aimindteams/career-site-jobs-scraper): every open job from Greenhouse, Lever, Ashby, Workday and other career sites, with salaries and hiring signals.
- [Shopify Store Scraper & Price Monitor](https://apify.com/aimindteams/shopify-catalog-price-monitor): products, variants, prices and stock from any Shopify store, with price-drop alerts.
- [SAM.gov & SBIR Federal RFP + Attachment Deep-Parser](https://apify.com/aimindteams/govcon-rfp-deep-parser): federal opportunities with their attachments parsed.

***

### Changelog

- **1.0**: First release. Ranked emails, E.164 phones, 9 social networks, schema.org company data, 260+ technology fingerprints, DNS email setup, RDAP domain age and hiring-system detection.

# Actor input Schema

## `websites` (type: `array`):

Domains or URLs, one per line, for example acme.com, https://www.acme.com or https://acme.com/contact. Duplicates are removed automatically. You can also paste a comma-separated list.

## `maxPagesPerSite` (type: `integer`):

The homepage plus the most promising contact, imprint, about and team pages. More pages find more emails and phones but take longer. Billing is per website, not per page.

## `companyEmailsOnly` (type: `boolean`):

Drop addresses on other domains (for example gmail.com or an agency's domain).

## `detectTechnologies` (type: `boolean`):

Fingerprint 260+ technologies: CMS and website builders, ecommerce platforms, analytics, ad pixels, marketing automation, CRM and sales tools, live chat, payments, hosting/CDN and frameworks.

## `checkDns` (type: `boolean`):

Read MX, SPF, DMARC and verification records to reveal the email provider (Google Workspace, Microsoft 365 ...), email-sending services (HubSpot, SendGrid, Salesforce ...) and verified SaaS tools.

## `lookupDomainAge` (type: `boolean`):

Registration date, expiry date, age in years and registrar from the official RDAP registry.

## `defaultCountry` (type: `string`):

Two-letter country code used to read local phone numbers when a site's domain or language does not reveal its country. Country-code domains (.co.uk, .de, .com.au ...) are detected automatically.

## `maxConcurrency` (type: `integer`):

Higher is faster for big lists. Each website is still visited politely (a few pages, one after another).

## Actor input object example

```json
{
  "websites": [
    "apify.com",
    "wordpress.org",
    "mailchimp.com"
  ],
  "maxPagesPerSite": 4,
  "companyEmailsOnly": false,
  "detectTechnologies": true,
  "checkDns": true,
  "lookupDomainAge": true,
  "defaultCountry": "US",
  "maxConcurrency": 5
}
```

# Actor output Schema

## `websites` (type: `string`):

Every website with company name, ranked emails, phones in E.164 format, social profiles, address, technologies, DNS email setup, domain registration data and careers page.

## `overview` (type: `string`):

Flattened one-row-per-website view: best email, best phone, LinkedIn, CMS, ecommerce platform, email provider and domain age. Append \&format=csv or \&format=xlsx for spreadsheets.

## `runSummary` (type: `string`):

Counts of enriched, unreachable and not-found websites, emails found, invalid inputs and warnings for this run.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "websites": [
        "apify.com",
        "wordpress.org",
        "mailchimp.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("aimindteams/website-contact-tech-enricher").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "websites": [
        "apify.com",
        "wordpress.org",
        "mailchimp.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("aimindteams/website-contact-tech-enricher").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "websites": [
    "apify.com",
    "wordpress.org",
    "mailchimp.com"
  ]
}' |
apify call aimindteams/website-contact-tech-enricher --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,aimindteams/website-contact-tech-enricher"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/CYNaJK9bgrAtajNUZ/builds/9rY8Jy8rZVwq0otTm/openapi.json
