
Hunter.io Domain Search
Deprecated
Pricing
Pay per usage
Go to Store

Hunter.io Domain Search
Deprecated
Hunter.io's Domain Search is a robust tool for discovering all email addresses linked to a specific domain. It offers confidence scores, department filters, and detailed sources, making it an invaluable resource for efficient contact information retrieval.
0.0 (0)
Pricing
Pay per usage
1
Total users
18
Monthly users
4
Last modified
2 years ago
package.json
{ "name": "hunter.io-domain-search", "version": "0.0.1", "description": "Discover emails across multiple domains, set limits, filter by type/seniority, specify departments, and obtain required fields with the 'Domain Email Search' actor. Pay only for returned emails. Simplify contact discovery for sales, marketing, and outreach efforts.", "author": "Adriaan", "dependencies": { "apify": "^3.1.4", "dotenv": "^16.1.3", "node-fetch": "^2.6.11" }, "devDependencies": { "@apify/eslint-config-ts": "^0.2.3", "@apify/tsconfig": "^0.1.0", "@types/jest": "^29.2.5", "@types/node": "^18.16.16", "@types/node-fetch": "^2.6.4", "@typescript-eslint/eslint-plugin": "^5.55.0", "@typescript-eslint/parser": "^5.55.0", "eslint": "^8.37.0", "jest": "^29.3.1", "ncp": "^2.0.0", "prettier": "^2.8.3", "ts-jest": "^29.0.5", "ts-loader": "^9.4.2", "ts-node": "^10.9.1", "typescript": "^4.9.5" }, "scripts": { "start": "node dist/main.js", "start:dev": "ts-node-esm -T src/main.ts", "build": "tsc", "lint": "eslint . --ext .ts", "lint:fix": "eslint ./src --ext .ts --fix", "test": "npm run test", "push:actor": "apify push" }}
.actor/actor.json
{ "actorSpecification": 1, "name": "hunter-domain-search", "title": "Hunter Domain Search", "version": "0.1", "buildTag": "latest", "input": "./input_schema.json", "storages": { "dataset": "./dataset_schema.json" }}
.actor/dataset_schema.json
{ "actorSpecification": 1, "views": { "overview": { "title": "Overview", "transformation": { "fields": [ "domain", "value", "type", "confidence", "sources", "first_name", "last_name", "position", "seniority", "department", "linkedin", "twitter", "phone_number", "verification" ] }, "display": { "component": "table", "properties": {} } } }}
.actor/input_schema.json
{ "title": "Domain Search", "type": "object", "schemaVersion": 1, "properties": { "api_key": { "title": "🔑 API Key", "description": "Your Hunter.io API key.", "type": "string", "editor": "textfield", "prefill": "fill in your API key", "nullable": false }, "domain": { "title": "Domain or company name from which you want to find the email addresses.", "description": "For example, 'stripe.com' or 'stripe'. Note that you'll get better results by supplying the domain name as we won't have to find it. It doesn't need to be in lowercase.", "type": "string", "editor": "textfield", "prefill": "stripe.com", "nullable": false }, "limit": { "title": "Specifies the max number of email addresses to return.", "type": "string", "description": "The default is 10.", "editor": "select", "default": "10", "enum": ["10", "20", "30", "40", "50", "60", "70", "80", "90", "100"], "nullable": false }, "offset": { "title": "Specifies the number of email addresses to skip.", "type": "string", "description": "The default is 0.", "editor": "select", "default": "0", "enum": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], "nullable": false }, "type": { "title": "Get only personal or generic email addresses.", "type": "string", "description": "Choose personal emails, generic emails, or select all.", "editor": "select", "default": "all", "enum": ["all", "personal", "generic"], "enumTitles": ["All Emails", "Personal", "Generic"], "nullable": true }, "junior": { "sectionCaption": "Get only email addresses for people with the selected seniority level.", "sectionDescription": "", "title": "Junior", "description": "", "type": "boolean", "default": false, "nullable": true }, "senior": { "title": "Senior", "description": "", "type": "boolean", "default": false, "nullable": true }, "executive": { "title": "Executive", "description": "", "type": "boolean", "default": false, "nullable": true }, "executives": { "sectionCaption": "Get only email addresses for people working in the selected department(s).", "sectionDescription": "", "title": "Executive", "description": "", "type": "boolean", "default": false, "nullable": true }, "it": { "title": "IT", "description": "", "type": "boolean", "default": false, "nullable": true }, "finance": { "title": "Finance", "description": "", "type": "boolean", "default": false, "nullable": true }, "management": { "title": "Management", "description": "", "type": "boolean", "default": false, "nullable": true }, "sales": { "title": "Sales", "description": "", "type": "boolean", "default": false, "nullable": true }, "legal": { "title": "Legal", "description": "", "type": "boolean", "default": false, "nullable": true }, "support": { "title": "Support", "description": "", "type": "boolean", "default": false, "nullable": true }, "hr": { "title": "HR", "description": "", "type": "boolean", "default": false, "nullable": true }, "marketing": { "title": "Marketing", "description": "", "type": "boolean", "default": false, "nullable": true }, "communication": { "title": "Communication", "description": "", "type": "boolean", "default": false, "nullable": true }, "education": { "title": "Education", "description": "", "type": "boolean", "default": false, "nullable": true }, "design": { "title": "Design", "description": "", "type": "boolean", "default": false, "nullable": true }, "health": { "title": "Health", "description": "", "type": "boolean", "default": false, "nullable": true }, "operations": { "title": "Operations", "description": "", "type": "boolean", "default": false, "nullable": true }, "full_name": { "sectionCaption": "Get only email addresses that have the selected field(s).", "sectionDescription": "", "title": "Full Name", "description": "", "type": "boolean", "default": false, "nullable": true }, "position": { "title": "Position", "description": "", "type": "boolean", "default": false, "nullable": true }, "phone_number": { "title": "Phone Number", "description": "", "type": "boolean", "default": false, "nullable": true } }, "required": ["api_key", "domain", "limit", "offset"]}
dist/main.js
1"use strict";2var __importDefault = (this && this.__importDefault) || function (mod) {3 return (mod && mod.__esModule) ? mod : { "default": mod };4};5Object.defineProperty(exports, "__esModule", { value: true });6const dotenv_1 = __importDefault(require("dotenv"));7dotenv_1.default.config();8const node_fetch_1 = __importDefault(require("node-fetch"));9const apify_1 = require("apify");10const utils_1 = require("./utils");11const types_1 = require("./types");12(async () => {13 try {14 await apify_1.Actor.init();15 const { domain, apiKey, limit, offset, type, seniorityLevels, departments, requiredFields, } = await getActorInput();16 const API_ENDPOINT = `https://api.hunter.io/v2/domain-search?api_key=${apiKey}`;17 const baseUrl = buildBaseUrl(API_ENDPOINT, domain, limit, offset, type, seniorityLevels, departments, requiredFields);18 const data = await fetchEmailData(baseUrl);19 if (!data?.emails?.length)20 apify_1.log.info(`No emails found for ${domain}`);21 if (data.emails.length)22 await logAndSaveData(domain, data);23 // add rate limit of 10 requests per second24 await (0, utils_1.delay)(100);25 }26 catch (err) {27 apify_1.log.error(err.message);28 }29 finally {30 await apify_1.Actor.exit();31 }32})();33const getActorInput = async () => {34 const input = await apify_1.Actor.getInput();35 const { domain, api_key: apiKey, limit, offset, type, } = input;36 if (!apiKey)37 throw new Error("No API key supplied!");38 if (!domain)39 throw new Error("No domain or company provided!");40 return {41 domain,42 apiKey,43 limit,44 offset,45 type,46 seniorityLevels: (0, utils_1.getEnumVal)(types_1.Seniority, input),47 departments: (0, utils_1.getEnumVal)(types_1.Departments, input),48 requiredFields: (0, utils_1.getEnumVal)(types_1.RequiredFields, input),49 };50};51const fetchEmailData = async (baseUrl) => {52 const response = await (0, node_fetch_1.default)(baseUrl);53 if (!response.ok) {54 throw new Error(`HTTP error! status: ${response.status}`);55 }56 const jsonResponse = await response.json();57 const { data } = jsonResponse;58 return data;59};60const logAndSaveData = async (domain, data) => {61 const emailCount = data.emails.length;62 apify_1.log.info(`Found ${emailCount} emails for ${domain}`);63 await saveResults(domain, data);64};65function buildBaseUrl(endpoint, domain, limit, offset, type, seniorityLevels, departments, requiredFields) {66 const url = new URL(endpoint);67 if ((0, utils_1.isNumeric)(limit))68 url.searchParams.append("limit", limit);69 if ((0, utils_1.isNumeric)(offset))70 url.searchParams.append("offset", offset);71 if (type === "personal" || type === "generic")72 url.searchParams.append("type", type);73 if (seniorityLevels.length)74 url.searchParams.append("seniority", seniorityLevels.join());75 if (departments.length)76 url.searchParams.append("department", departments.join());77 if (requiredFields.length)78 url.searchParams.append("required_field", requiredFields.join());79 // check if domain or company is provided80 const isDomainProvided = (0, utils_1.isDomain)(domain);81 if (isDomainProvided)82 url.searchParams.append("domain", domain);83 if (!isDomainProvided)84 url.searchParams.append("company", domain);85 return url.toString();86}87async function saveResults(domain, data) {88 for (const email of data.emails) {89 await apify_1.Actor.pushData(Object.assign({ domain }, email));90 }91}
dist/types.js
1"use strict";2Object.defineProperty(exports, "__esModule", { value: true });3exports.RequiredFields = exports.Departments = exports.Seniority = void 0;4var Seniority;5(function (Seniority) {6 Seniority["junior"] = "junior";7 Seniority["senior"] = "senior";8 Seniority["executive"] = "executive";9})(Seniority = exports.Seniority || (exports.Seniority = {}));10var Departments;11(function (Departments) {12 Departments["executives"] = "executive";13 Departments["it"] = "it";14 Departments["finance"] = "finance";15 Departments["management"] = "management";16 Departments["sales"] = "sales";17 Departments["legal"] = "legal";18 Departments["support"] = "support";19 Departments["hr"] = "hr";20 Departments["marketing"] = "marketing";21 Departments["communication"] = "communication";22 Departments["education"] = "education";23 Departments["design"] = "design";24 Departments["health"] = "health";25 Departments["operations"] = "operations";26})(Departments = exports.Departments || (exports.Departments = {}));27var RequiredFields;28(function (RequiredFields) {29 RequiredFields["full_name"] = "full_name";30 RequiredFields["position"] = "position";31 RequiredFields["phone_number"] = "phone_number";32})(RequiredFields = exports.RequiredFields || (exports.RequiredFields = {}));
dist/utils.js
1"use strict";2Object.defineProperty(exports, "__esModule", { value: true });3exports.getEnumVal = exports.isDomain = exports.isNumeric = exports.delay = void 0;4async function delay(ms) {5 return new Promise((r) => setTimeout(r, ms));6}7exports.delay = delay;8function isNumeric(str) {9 const parsedNr = parseFloat(str);10 return !isNaN(parsedNr) && isFinite(parsedNr);11}12exports.isNumeric = isNumeric;13function isDomain(str) {14 const domainRegex = /^(?:[-A-Za-z0-9]+\.)+[A-Za-z]{2,}$/;15 return domainRegex.test(str);16}17exports.isDomain = isDomain;18function getEnumVal(ENUM, input) {19 return Object.entries(input)20 .map(([key]) => {21 const enumVal = ENUM[key];22 return input[key] === true ? enumVal : null;23 })24 .filter((val) => val);25}26exports.getEnumVal = getEnumVal;