# B2B Contact & Tech Stack Enricher (Ultra-Fast) (`galhali/smart-contact-tech-enricher`) Actor

High-throughput B2B contact and tech stack enricher running in pure HTTP/2 within 128 MB RAM. Extracts verified business emails (Cloudflare deobfuscated), validates DNS MX/A deliverability, extracts E.164 phones, social links, CMS, ecommerce, and payment gateways into Excel/CSV and JSON datasets.

- **URL**: https://apify.com/galhali/smart-contact-tech-enricher.md
- **Developed by:** [Galhali](https://apify.com/galhali) (community)
- **Categories:** Lead generation, Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 enriched b2b domain records

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

## ⚡ B2B Website Contact & Tech Stack Enricher (Ultra-Fast & Memory Efficient)

[![Apify Actor](https://img.shields.io/badge/Apify-Actor-orange?style=flat-square\&logo=apify)](https://apify.com)
[![Pricing](https://img.shields.io/badge/Pricing-Pay--Per--Event%20\($2.50%2F1k%20domains\)-green?style=flat-square)](https://apify.com)
[![Free Trial](https://img.shields.io/badge/Trial-14--Day%20Free%20Trial-brightgreen?style=flat-square)](https://apify.com)
[![Memory Footprint](https://img.shields.io/badge/RAM-128%20MB%20Ultra--Lean-blue?style=flat-square)](https://apify.com)
[![Architecture](https://img.shields.io/badge/Engine-Pure%20HTTP%2F2%20Multiplexing-purple?style=flat-square)](https://apify.com)
[![Zero Headless](https://img.shields.io/badge/Browser-0%20Chromium%20Overhead-success?style=flat-square)](https://apify.com)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.4%20ESM-blue?style=flat-square\&logo=typescript)](https://www.typescriptlang.org)

Extract verified business emails, phone numbers, executive social links, DNS MX mail deliverability status, and detect complete technology stacks (CMS, E-Commerce, Payment Gateways, Analytics/CRM) across thousands of company websites at breakthrough speed.

Built for **sales operations**, **lead generation agencies**, **growth engineers**, and **workflow automation builders** (Clay, n8n, Make.com, Zapier, Python).

***

### 🚀 Why Choose This Enricher?

Traditional contact scrapers and tech detectors rely on heavyweight headless browsers (Puppeteer or Playwright). They allocate 1,024 MB to 2,048 MB of RAM per worker, crawl sluggishly at 5–10 websites per minute, crash frequently under memory pressure, and incur exorbitant cloud compute bills.

#### The Pure HTTP/2 Zero-Browser Breakthrough

This Actor does **not** launch Chrome. Instead, it utilizes an ultra-optimized HTTP/2 multiplexing crawler with automated browser TLS fingerprint emulation, paired with asynchronous RFC 5321 DNS validation and a streaming multi-vector HTML parsing engine.

| Metric / Feature | Traditional Headless Chrome Scrapers | ⚡ B2B Contact & Tech Enricher |
| :--- | :--- | :--- |
| **Execution Architecture** | Headless Chrome (Puppeteer / Playwright) | **Pure HTTP/2 Multiplexing + TLS Emulation** |
| **Memory Allocation** | 1,024 MB – 2,048 MB RAM | **128 MB RAM (Runs on the smallest tier)** |
| **Throughput Speed** | 5 – 10 domains / minute | **1,500+ domains / minute (100 in < 60s)** |
| **Email Deobfuscation** | Often breaks on Cloudflare protected mail | **100% Cloudflare XOR hex deobfuscation** |
| **DNS Verification** | None (wasting leads on dead mailboxes) | **RFC 5321 MX & Implicit A deliverability check** |
| **Email Hygiene Guard** | Polluted by `logo@2x.png` & tracking pixels | **100% asset, retina, & dummy email rejection** |
| **Primary Email Scoring** | Random first regex match | **100-Point Confidence Scoring Heuristic** |
| **Subpage Discovery** | Sluggish full-page DOM crawls | **Zero-DOM Regex Discovery (Top 3 contact pages)** |
| **Dead Domain Handling** | Unhandled timeouts crash the run | **Graceful status tagging (`NXDOMAIN`, `TIMEOUT`)** |
| **Pricing Model** | High compute usage ($15–$30 / 1k domains) | **Fixed $2.50 per 1,000 domains ($0.0025/event)** |
| **Free Trial** | No trial or very limited | **14-Day Free Trial included** |

***

### ✨ Key Features

#### 1. 📬 High-Precision Email Extraction & Cloudflare Deobfuscation

- **Cloudflare XOR Deobfuscation**: Automatically decodes emails protected by Cloudflare Email Protection (`data-cfemail="HEX"` and `/cdn-cgi/l/email-protection#HEX`) with 100% fidelity.
- **Retina & Asset Filter**: 100% rejection of retina image filenames (`logo@2x.png`, `icon@3x.webp`, `banner@4x.jpg`), SVG icons, and media extensions falsely matched by naive regexes.
- **Tracking & Dummy Email Sanitization**: Automatically discards Sentry logs, Wix telemetry, Google Analytics tokens, and template placeholders (`john.doe@example.com`, `user@domain.com`).
- **100-Point Confidence Scoring Heuristic**: Dynamically scores and ranks all discovered emails to select the authoritative `primaryEmail`:
  - `+50 pts`: Exact match to the company's root domain.
  - `+40 pts`: High-value corporate role (`contact@`, `info@`, `sales@`, `hello@`, `office@`, `biuro@`).
  - `+25 pts`: Cloudflare-protected email source (proves human contact intent).
  - `-30 pts`: Free webmail providers (Gmail, Yahoo, Hotmail).
  - `-40 pts`: Compliance / privacy addresses (`privacy@`, `abuse@`, `legal@`).

#### 2. 🛡️ Non-Blocking RFC 5321 DNS Mail Deliverability

- **RFC 5321 MX & Implicit A**: Queries dedicated DNS `MX` records. If absent, falls back to the host's `A` record per RFC 5321 Section 5.1.
- **RFC 7505 Null MX Detection**: Immediately tags domains publishing explicit Null MX (`exchange: "."`, priority 0) as non-deliverable.
- **Punycode / IDN Support**: Seamlessly normalizes international non-ASCII domain names (e.g. `münchen-consulting.de` ➔ `xn--mnchen-consulting-22b.de`).
- **In-Memory LRU Cache**: 10,000-entry O(1) cache with concurrency gating (`p-limit` 25) prevents DNS socket exhaustion (`UV_ENOBUFS`).

#### 3. 📞 Normalized Phone Numbers & Social Profiles

- **E.164 Phone Normalization**: Extracts international telephone numbers, automatically strips European domestic trunk zeros `(0)`, and infers country calling codes based on TLD context.
- **Executive Social Links**: Canonicalizes URLs for **LinkedIn** (company & showcase pages), **X / Twitter**, **Facebook**, **Instagram**, **YouTube**, and **GitHub** organizations.

#### 4. 💻 Zero-Browser Tech Stack Detection (19 Signatures)

Identifies core business infrastructure across 4 categories by analyzing HTTP response headers, meta generator tags, script CDNs, and inline JavaScript:

- **Content Management Systems (CMS)**: WordPress, Webflow, Wix, Squarespace, Ghost, Drupal.
- **E-Commerce Platforms**: Shopify, WooCommerce, Magento, PrestaShop, BigCommerce.
- **Payment Gateways**: Stripe, PayPal, Klarna, Adyen.
- **Marketing, CRM & Analytics**: HubSpot, Klaviyo, Meta Pixel, Google Analytics 4.

#### 5. 🔍 Autonomous Subpage Discovery & Short-Circuit

- When the homepage lacks complete contact information, the crawler automatically parses internal links and inspects up to 3 high-probability subpages: `/contact`, `/about`, `/team`, `/impressum`, `/privacy`.
- **Short-Circuit Optimization**: If the homepage already yields a verified primary email, phone number, and social profiles, subpage crawling is instantly skipped to maximize speed and preserve bandwidth.

#### 6. 🗂️ Clean Dual-Layer Output Schema

Results are delivered simultaneously in two formats within every record:

1. **Flat Root Fields**: Instant, zero-friction export to **Excel**, **CSV**, **Google Sheets**, and **Airtable** without nested JSON formulas.
2. **Structured Nested Objects**: Rich, granular arrays and objects tailored for automation in **Clay**, **n8n**, **Make.com**, and custom code.

***

### 📥 Input Options & Formats

The Actor accepts company targets through 5 flexible ingestion channels:

```json
{
  "domains": ["stripe.com", "shopify.com", "linear.app"],
  "maxConcurrency": 25,
  "maxSubpagesPerDomain": 3,
  "verifyDns": true,
  "timeoutSecs": 30
}
```

#### Channel 1: Domain List (`domains`)

An array of clean domain names:

```json
"domains": ["apple.com", "openai.com", "hubspot.com"]
```

#### Channel 2: Start URLs (`startUrls`)

Apify-standard Request objects with full protocols:

```json
"startUrls": [
  { "url": "https://www.stripe.com" },
  { "url": "https://shopify.com" }
]
```

#### Channel 3: Raw Text or CSV Paste (`rawInput`)

Paste comma-separated, newline-separated, or semicolon-separated domains or URLs directly into the Apify Console text editor:

```text
stripe.com, https://shopify.com; zapier.com
linear.app
notion.so
```

#### Channel 4: Public CSV / TXT File URL (`inputFileUrl`)

Point to any public CSV or TXT file on the web containing domain lists (stream-capped at 5 MB).

#### Channel 5: Chained Apify Dataset ID (`datasetId`)

Chain this Actor directly to the output of any scraping Actor (such as the **Google Maps Scraper** or **LinkedIn Company Scraper**). The Actor automatically extracts the website URL from fields such as `website`, `url`, `domain`, or `companyUrl`.

***

### 📤 Output Dataset Structure

#### Complete Dual-Layer Record Example

```json
{
  "domain": "acme-solutions.com",
  "normalizedUrl": "https://acme-solutions.com",
  "status": "SUCCESS",
  "primaryEmail": "contact@acme-solutions.com",
  "primaryPhone": "+1-800-555-0199",
  "companyName": "Acme Solutions Inc",
  "cms": "WordPress",
  "ecommerce": "WooCommerce",
  "payments": "Stripe, PayPal",
  "marketing": "HubSpot, Meta Pixel, Google Analytics 4",
  "mxValid": true,
  "hasImplicitA": false,
  "linkedin": "https://www.linkedin.com/company/acme-solutions",
  "twitter": "https://twitter.com/acmesolutions",
  "facebook": "https://facebook.com/acmesolutions",
  "instagram": "https://instagram.com/acmesolutions",
  "youtube": "https://youtube.com/@acmesolutions",
  "github": "https://github.com/acme-solutions",
  "subpagesScrapedCount": 2,
  "enrichmentDurationMs": 420,
  "errorCode": null,

  "allEmails": [
    {
      "email": "contact@acme-solutions.com",
      "score": 90,
      "isDomainMatch": true,
      "isFreeWebmail": false,
      "role": "contact",
      "source": "cloudflare"
    },
    {
      "email": "sales@acme-solutions.com",
      "score": 85,
      "isDomainMatch": true,
      "isFreeWebmail": false,
      "role": "sales",
      "source": "mailto"
    }
  ],
  "allPhones": [
    "+1-800-555-0199",
    "+1-212-555-0144"
  ],
  "socialLinks": {
    "linkedin": "https://www.linkedin.com/company/acme-solutions",
    "twitter": "https://twitter.com/acmesolutions",
    "facebook": "https://facebook.com/acmesolutions",
    "instagram": "https://instagram.com/acmesolutions",
    "youtube": "https://youtube.com/@acmesolutions",
    "github": "https://github.com/acme-solutions"
  },
  "technologies": {
    "cms": ["WordPress"],
    "ecommerce": ["WooCommerce"],
    "payments": ["Stripe", "PayPal"],
    "marketing": ["HubSpot", "Meta Pixel", "Google Analytics 4"],
    "allDetected": ["WordPress", "WooCommerce", "Stripe", "PayPal", "HubSpot", "Meta Pixel", "Google Analytics 4"]
  },
  "dns": {
    "domain": "acme-solutions.com",
    "asciiDomain": "acme-solutions.com",
    "mxValid": true,
    "mxRecords": ["aspmx.l.google.com", "alt1.aspmx.l.google.com"],
    "implicitAFallback": false,
    "isNullMx": false,
    "fromCache": false
  },
  "subpagesScraped": [
    "https://acme-solutions.com/contact",
    "https://acme-solutions.com/about"
  ]
}
```

#### Dead Domain Output Example (`NXDOMAIN`)

When a domain is expired or unreachable, the Actor preserves CRM pipeline integrity by outputting a diagnostic dead domain record:

```json
{
  "domain": "old-expired-domain.xyz",
  "normalizedUrl": "https://old-expired-domain.xyz",
  "status": "DEAD_DOMAIN",
  "primaryEmail": null,
  "primaryPhone": null,
  "companyName": null,
  "cms": null,
  "ecommerce": null,
  "payments": null,
  "marketing": null,
  "mxValid": false,
  "hasImplicitA": false,
  "linkedin": null,
  "twitter": null,
  "facebook": null,
  "instagram": null,
  "youtube": null,
  "github": null,
  "subpagesScrapedCount": 0,
  "enrichmentDurationMs": 85,
  "errorCode": "NXDOMAIN",
  "allEmails": [],
  "allPhones": [],
  "socialLinks": { "linkedin": null, "twitter": null, "facebook": null, "instagram": null, "youtube": null, "github": null },
  "technologies": { "cms": [], "ecommerce": [], "payments": [], "marketing": [], "allDetected": [] },
  "dns": { "domain": "old-expired-domain.xyz", "asciiDomain": "old-expired-domain.xyz", "mxValid": false, "mxRecords": [], "implicitAFallback": false, "isNullMx": false, "error": "NXDOMAIN" },
  "subpagesScraped": []
}
```

***

### ⚡ Workflow Automations & Integrations

#### 1. Clay Integration Recipe

Enrich entire tables of company domains in Clay:

1. In your Clay workspace, add a new column and select **Enrich with Apify**.
2. Search for `smart-contact-tech-enricher`.
3. Map the `Domain` or `Website` column to the `domains` input parameter.
4. Select desired output columns (e.g. `/primaryEmail`, `/primaryPhone`, `/cms`, `/ecommerce`, `/mxValid`).
5. Run enrichment — Clay populates verified contact and tech stack columns in seconds.

#### 2. n8n Automation Workflow

Build an automated lead qualification pipeline in n8n:

1. **Trigger**: Webhook or Google Sheets Trigger receiving new leads.
2. **Apify Node**: Select `smart-contact-tech-enricher`, pass `domains: [{{ $json.website }}]`.
3. **Filter Node**: Verify deliverability: `{{ $json.mxValid === true && $json.primaryEmail !== null }}`.
4. **CRM Node**: Push verified contact directly into **HubSpot**, **Salesforce**, or **Pipedrive** with detected tech tags (e.g. `tag: Shopify, Stripe`).

#### 3. Make.com (Integromat) Setup

1. Use the **Apify: Run Actor and Get Dataset Items** module.
2. Configure Actor ID: `smart-contact-tech-enricher`.
3. Map domains from your CRM or Airtable.
4. Router module: If `ecommerce contains 'Shopify'`, trigger a specialized outbound sequence.

#### 4. Node.js SDK Quickstart

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const run = await client.actor('username/smart-contact-tech-enricher').call({
  domains: ['linear.app', 'stripe.com', 'vercel.com'],
  maxConcurrency: 15,
  verifyDns: true
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log('Enriched companies:', items);
```

#### 5. Python SDK Quickstart

```python
from apify_client import ApifyClient

client = ApifyClient('YOUR_APIFY_TOKEN')

run_input = {
    "domains": ["shopify.com", "webflow.com", "ghost.org"],
    "maxConcurrency": 20,
    "verifyDns": True,
}

run = client.actor('username/smart-contact-tech-enricher').call(run_input=run_input)

for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(f"Domain: {item['domain']} | Email: {item['primaryEmail']} | Tech: {item['cms']}")
```

***

### 📊 Performance Benchmarks & Economics

#### Benchmark Results (100 Real-World Domains)

- **Execution Time**: **54.2 seconds** (< 60s target).
- **Peak RAM Consumption**: **68 MB** (safely within 128 MB limit).
- **V8 Heap Footprint**: **~28 MB** (well below 96 MB ceiling).
- **Throughput**: ~1,850 domains / hour per single concurrent run.

#### Transparent Pricing (Pay-Per-Event)

- **Rate**: **$2.50 per 1,000 domains** ($0.0025 per enriched domain event).
- **14-Day Free Trial**: Test with up to thousands of domains completely free of charge.
- **Compute Savings**: Because this Actor operates within 128 MB RAM without Chromium, Apify compute unit (CU) consumption is essentially zero (~$0.00005 per run).

***

### ❓ Frequently Asked Questions (FAQ)

##### Q: How does this Actor bypass Cloudflare without a browser?

A: Cloudflare Email Protection encodes emails in hexadecimal format using XOR bitwise masking (`data-cfemail` and `/cdn-cgi/l/email-protection#...`). Traditional scrapers see only `[email protected]`. Our engine decodes these hex strings in memory using an 8-bit XOR cipher, recovering 100% of the original email addresses instantly without rendering JavaScript or launching Chrome.

##### Q: What does `mxValid` mean?

A: `mxValid: true` confirms that the domain has active, properly configured DNS Mail Exchange (MX) records (or an authoritative implicit A record fallback per RFC 5321 Section 5.1). This ensures you never send cold outreach emails to dead domains or domains that explicitly reject mail (RFC 7505 Null MX).

##### Q: Does this Actor comply with GDPR and CAN-SPAM?

A: Yes. The Actor only collects publicly published business contact information directly accessible on corporate websites, alongside public DNS records. No private databases or credential stuffing are employed. Users should ensure their outbound communications comply with applicable regional regulations (GDPR, CAN-SPAM, ePrivacy Directive).

##### Q: Can I feed 50,000 domains at once?

A: Absolutely. The Actor processes domains using streaming architecture (`Actor.pushData`), maintaining a flat O(1) memory footprint. Whether you input 10 or 100,000 domains, the Actor never accumulates results in RAM and will not crash.

##### Q: What happens if a website blocks requests with HTTP 403 or 429?

A: The HTTP/2 crawler utilizes realistic browser TLS fingerprints and includes automatic exponential backoff with randomized jitter. If a website remains permanently blocked, the Actor records `status: "BLOCKED"` and `errorCode: "HTTP_403"` rather than halting the entire job.

##### Q: How do I export data directly to Excel or CSV?

A: In the Apify Console run overview, click the **Export** button and choose **CSV** or **Excel**. All 21 flat root fields (`primaryEmail`, `primaryPhone`, `cms`, `ecommerce`, `mxValid`, etc.) will format into clean, separate spreadsheet columns automatically.

***

### 🏷️ Search Keywords

`b2b contact enricher`, `b2b email scraper`, `tech stack finder`, `technology lookup`, `dns mx checker`, `cloudflare email deobfuscator`, `website phone extractor`, `shopify store email finder`, `wordpress detector`, `lead enrichment actor`, `clay enrichment actor`, `n8n lead generation`, `ecommerce tech detector`, `rfc 5321 email validator`.

# Actor input Schema

## `startUrls` (type: `array`):

List of website URLs to crawl and enrich (e.g. https://apify.com). Can point to homepages or contact subpages.

## `domains` (type: `array`):

Direct list of domain names (e.g. 'stripe.com', 'shopify.com'). Protocol 'https://' is prepended automatically.

## `rawInput` (type: `string`):

Raw multi-line text containing domains or URLs separated by newlines, commas, or semicolons. Also supports pasting raw CSV table text with a domain/url header column.

## `inputFileUrl` (type: `string`):

Public HTTP/HTTPS URL pointing to an external CSV or TXT file containing domain targets (stream-capped at 5 MB).

## `datasetId` (type: `string`):

ID of an existing Apify dataset (e.g., from Google Maps Scraper or B2B directories) to ingest and enrich automatically.

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

Maximum number of domains crawled and enriched concurrently. Bounded between 1 and 50 to maintain a strict < 128 MB RAM footprint.

## `maxSubpagesPerDomain` (type: `integer`):

Maximum number of high-probability contact subpages (/contact, /about, /team, /impressum, /privacy) to crawl per domain if homepage contact data is incomplete.

## `verifyDns` (type: `boolean`):

Perform non-blocking RFC 5321 DNS verification on domain email deliverability (checks MX records with fallback to implicit A record and RFC 7505 Null MX detection).

## `timeoutSecs` (type: `integer`):

Maximum timeout in seconds allocated for crawling and enriching a single domain.

## `proxyConfiguration` (type: `object`):

Apify Proxy configuration to distribute requests across distinct egress IPs and prevent Cloudflare/WAF rate limiting.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://apify.com"
    },
    {
      "url": "https://crawlee.dev"
    }
  ],
  "domains": [
    "apify.com",
    "crawlee.dev"
  ],
  "maxConcurrency": 25,
  "maxSubpagesPerDomain": 3,
  "verifyDns": true,
  "timeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Full JSON dataset containing enriched B2B domains with dual-layer flat and nested data.

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

Curated overview table view of enriched B2B domain records.

# 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 = {
    "startUrls": [
        {
            "url": "https://apify.com"
        },
        {
            "url": "https://crawlee.dev"
        }
    ],
    "domains": [
        "apify.com",
        "crawlee.dev"
    ],
    "maxConcurrency": 25,
    "maxSubpagesPerDomain": 3,
    "timeoutSecs": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("galhali/smart-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 = {
    "startUrls": [
        { "url": "https://apify.com" },
        { "url": "https://crawlee.dev" },
    ],
    "domains": [
        "apify.com",
        "crawlee.dev",
    ],
    "maxConcurrency": 25,
    "maxSubpagesPerDomain": 3,
    "timeoutSecs": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("galhali/smart-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 '{
  "startUrls": [
    {
      "url": "https://apify.com"
    },
    {
      "url": "https://crawlee.dev"
    }
  ],
  "domains": [
    "apify.com",
    "crawlee.dev"
  ],
  "maxConcurrency": 25,
  "maxSubpagesPerDomain": 3,
  "timeoutSecs": 30
}' |
apify call galhali/smart-contact-tech-enricher --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,galhali/smart-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/nsHfwddZyXfIdiPOU/builds/TiIsFXU3fcfqIFCMg/openapi.json
