Company Name to Domain API in JavaScript: Full Tutorial

Company Name to Domain API in JavaScript

The first time I wired a company-name-to-domain lookup into a JavaScript app, I did it the sloppy way.

API key sitting right in the frontend. No error handling. One company at a time.

It worked in the demo. And it broke the second real data hit it.

So I rebuilt it properly. And then I kept rebuilding it, across Node.js servers, browser apps, an Express proxy, a couple of serverless functions, and a little React dashboard for our sales team. This post is all of that, cleaned up and handed to you so you skip the mistakes I made.

We’ll use the Company URL Finder API. You give it a company name, it gives you back the verified domain. That’s the whole job. Let me show you how to do it right in JavaScript.

📌 TL;DR: POST a company name to the Company URL Finder API → get the verified domain back as JSON. In Node.js use axios or built-in fetch. In the browser, NEVER call the API directly; proxy through your own backend so your key stays server-side. Handle the six status codes, cache repeat lookups, and batch big lists with a concurrency limit. Copy-paste code for all of it below.

What you’ll walk away with

Everything you need to turn company names into domains in JavaScript, start to finish.

Here’s the map:

  • Setting up the API with Node.js and with browser JavaScript
  • Making requests with fetch and with axios
  • Handling all six status codes without your app falling over
  • Bulk-processing a CSV of hundreds of companies
  • Real patterns I run in production: caching, concurrency, webhooks, serverless, React

If your stack isn’t JavaScript, I wrote the same walkthrough for Java, Kotlin, and PHP. Same API, same ideas, different syntax.

Let’s go 👇

Why use JavaScript for this?

Because one language covers your whole stack. That’s the honest answer.

A Chrome extension. A React dashboard. A Node.js API. An edge function. They can all share the exact same lookup code. I’ve built the same integration in Python and Ruby too, and I still reach for JavaScript first when the app itself lives in the browser or on Node.

It’s a natural fit for data enrichment work for a few reasons:

Async is built in. Promises and async/await make API calls feel native. No threading gymnastics.

JSON is the native tongue. The API returns JSON, JavaScript reads JSON. No serialization layer in between.

The tooling is right there. npm has clean helpers for CSV parsing, rate limiting, retries, caching. You’re never writing plumbing from scratch.

I’ve shipped the same enrichment script to AWS Lambda, Vercel, and Cloudflare Workers with zero code changes. That portability is the real win.

What you need before you start

Not much. Let’s get you set up.

For Node.js:

  • Node.js 18+ installed (check with node --version). Version 18 and up ship fetch built in, so you don’t even need a library for simple calls. Read the Node.js docs if you’re setting up fresh.
  • npm or yarn
  • A Company URL Finder API key (grab a free one at companyurlfinder.com/signup)
  • Any code editor you like

For the browser:

  • Any modern browser (the Fetch API has been standard since 2017)
  • Basic HTML and JavaScript
  • A backend you control (you’ll need it to hide the key, more on that in a second)

Nice to have: axios (npm install axios) for cleaner timeouts, dotenv for env vars, and csv-parser for bulk jobs.

I’m on Node.js 20 here, but everything runs the same on Windows, macOS, and Linux.

💡 Read this twice: NEVER put your API key in frontend code. Anyone can open DevTools and read it. Frontend → your backend → the API. Your key lives on the server, always. The secure proxy pattern is a few sections down.

Step 1: Install your dependencies (Node.js)

Make a folder and initialize it:

mkdir company-domain-finder
cd company-domain-finder
npm init -y

Then install axios and dotenv:

npm install axios dotenv

That’s it. Two packages, ten seconds.

Do you actually need axios? No. Node 18+ has fetch built in and it’s perfectly fine. But axios gives you cleaner timeouts and error objects, and it works the same in Node and the browser. For production jobs, I lean axios. Quick scripts? Built-in fetch is great.

A couple of setup tips

Add a run script to package.json so you’re not typing filenames all day:

{
  "scripts": {
    "start": "node index.js",
    "test": "node test.js"
  }
}

On TypeScript: install types with npm install -D @types/node. The API response shape is simple and typed cleanly, which I’ll show you near the end.

On modules: my examples use ES modules (import/export). Add "type": "module" to package.json, or switch to require if that’s your setup. Either works. I prefer ES modules for new projects.

Step 2: Set up authentication

Create a .env file in your project root:

COMPANY_URL_FINDER_API_KEY=your_api_key_here

Now add .env to your .gitignore. Do it right now, before you forget. I mean it.

Create your main file, index.js:

import 'dotenv/config';

const API_KEY = process.env.COMPANY_URL_FINDER_API_KEY;

if (!API_KEY) {
  throw new Error('API key not found. Check your .env file.');
}

console.log('✅ API key loaded successfully');

This keeps your credential out of your code and out of your git history.

Why does this matter so much?

Because a hardcoded key gets found. Fast.

Security: bots scrape public repos for keys within minutes. GitHub’s own scanners flag them instantly.

Teamwork: each developer uses their own key. Share a .env.example template, never the real thing.

Environments: different keys for dev, staging, and prod. Change one variable, not a hundred lines.

I learned this the expensive way. Once, I pushed a key to a public repo. It was scraped and abused before I’d finished my coffee. So please, env vars from day one.

Step 3: Make your first request (Node.js)

Here’s the full code to turn a company name into a domain with axios:

import axios from 'axios';
import 'dotenv/config';

const API_KEY = process.env.COMPANY_URL_FINDER_API_KEY;
const API_URL = 'https://api.companyurlfinder.com/v1/services/name_to_domain';

async function findCompanyDomain(companyName, countryCode = 'US') {
  try {
    const response = await axios.post(API_URL, 
      {
        company_name: companyName,
        country_code: countryCode
      },
      {
        headers: {
          'x-api-key': API_KEY,
          'Content-Type': 'application/x-www-form-urlencoded'
        }
      }
    );
    
    return response.data;
  } catch (error) {
    console.error('Error:', error.message);
    throw error;
  }
}

// Test it
const result = await findCompanyDomain('Microsoft', 'US');
console.log(result);

Run it with node index.js.

You’ll get back something like this:

{
    "status": 1,
    "code": 1000,
    "errors": {},
    "data": {
        "exists": true,
        "domain": "https://microsoft.com/"
    }
}

And there it is. Microsoft’s domain, verified, in one call.

What’s in the response?

Five fields, and each one earns its place. Check status before you touch data, always.

status: 1 means success, 0 means error. Your first gate.

code: an internal code. 1000 is success. Other numbers point at specific errors.

exists: a boolean for whether a domain was actually found. This is your filter for clean output.

domain: the verified website, protocol included.

errors: an object with details when something goes wrong. Empty on success.

That exists field is the one people skip. Don’t. It’s the difference between a clean output file and a column full of undefined. Good data quality starts with checking it every single time.

Step 4: Call it from the browser with Fetch

In the browser, you never call the API directly. You call your own backend, and your backend calls the API.

Here’s the frontend half using the native fetch API:

async function findCompanyDomain(companyName, countryCode = 'US') {
  const API_URL = 'https://api.companyurlfinder.com/v1/services/name_to_domain';
  
  // CRITICAL: Never put API keys in frontend code!
  // This request should go through your backend proxy
  const response = await fetch('/api/find-domain', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      company_name: companyName,
      country_code: countryCode
    })
  });
  
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  
  return await response.json();
}

// Use in your frontend
document.getElementById('findButton').addEventListener('click', async () => {
  const companyName = document.getElementById('companyInput').value;
  
  try {
    const result = await findCompanyDomain(companyName);
    
    if (result.data.exists) {
      document.getElementById('result').textContent = result.data.domain;
    } else {
      document.getElementById('result').textContent = 'Domain not found';
    }
  } catch (error) {
    console.error('Error:', error);
    document.getElementById('result').textContent = 'Error occurred';
  }
});

See how it posts to /api/find-domain, not to the API? That’s your proxy endpoint. So the browser never sees the key.

The backend proxy (Express.js)

Here’s the proxy the frontend is talking to. It’s a tiny Express server:

import express from 'express';
import axios from 'axios';
import 'dotenv/config';

const app = express();
app.use(express.json());

const API_KEY = process.env.COMPANY_URL_FINDER_API_KEY;

app.post('/api/find-domain', async (req, res) => {
  try {
    const { company_name, country_code } = req.body;
    
    const response = await axios.post(
      'https://api.companyurlfinder.com/v1/services/name_to_domain',
      {
        company_name,
        country_code: country_code || 'US'
      },
      {
        headers: {
          'x-api-key': API_KEY,
          'Content-Type': 'application/x-www-form-urlencoded'
        }
      }
    );
    
    res.json(response.data);
  } catch (error) {
    res.status(error.response?.status || 500).json({
      error: error.message
    });
  }
});

app.listen(3000, () => console.log('Proxy server running on port 3000'));

That’s the whole secret. The key stays on the server. Your browser gets its answer. Nobody reading your page source finds anything useful.

Node or browser: where should the call live?

On a server you control, almost always. The browser only ever talks to your proxy, never to the API.

Here’s the quick way to decide:

Where the call runsCan it hold the API key?Good forWatch out for
Node.js server / ExpressYes, safelyBulk jobs, cron, the proxy itselfNothing major
Browser (direct)No, key is exposedNothing. Don’t do it.Leaked key, stolen quota
Browser via your proxyKey lives on the proxyDashboards, live lookupsAdd auth so it isn’t open to all
Serverless (Lambda, Vercel)Yes, via env varsOn-demand, spiky trafficCold starts on the first hit

So the rule of thumb: the key touches a server, never a browser. Everything else is just picking the server that fits your traffic.

Step 5: Handle all the status codes

The API returns six status codes, and your code should have a plan for each one.

Skip this and your bulk job dies on the first weird row. Here’s a function that handles every case, with retries where they help:

import axios from 'axios';

async function findCompanyDomain(companyName, countryCode = 'US', maxRetries = 3) {
  const API_URL = 'https://api.companyurlfinder.com/v1/services/name_to_domain';
  
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await axios.post(
        API_URL,
        {
          company_name: companyName,
          country_code: countryCode
        },
        {
          headers: {
            'x-api-key': process.env.COMPANY_URL_FINDER_API_KEY,
            'Content-Type': 'application/x-www-form-urlencoded'
          },
          timeout: 10000
        }
      );
      
      // Status 200: Success
      if (response.status === 200) {
        return {
          success: true,
          company: companyName,
          domain: response.data.data.domain,
          exists: response.data.data.exists,
          statusCode: 200
        };
      }
      
    } catch (error) {
      if (error.response) {
        const status = error.response.status;
        
        // Status 400: Not enough credits
        if (status === 400) {
          return {
            success: false,
            company: companyName,
            error: 'Not enough credits',
            statusCode: 400
          };
        }
        
        // Status 401: Invalid API key
        if (status === 401) {
          return {
            success: false,
            company: companyName,
            error: 'Invalid API key',
            statusCode: 401
          };
        }
        
        // Status 404: No data found
        if (status === 404) {
          return {
            success: false,
            company: companyName,
            error: 'No data found',
            statusCode: 404
          };
        }
        
        // Status 422: Invalid data format
        if (status === 422) {
          return {
            success: false,
            company: companyName,
            error: 'Invalid data format',
            statusCode: 422
          };
        }
        
        // Status 500: Server error - retry
        if (status === 500) {
          if (attempt < maxRetries - 1) {
            const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
            await new Promise(resolve => setTimeout(resolve, delay));
            continue;
          }
          return {
            success: false,
            company: companyName,
            error: 'Server error after retries',
            statusCode: 500
          };
        }
      }
      
      // Network errors
      if (error.code === 'ECONNABORTED' || error.code === 'ETIMEDOUT') {
        if (attempt < maxRetries - 1) {
          await new Promise(resolve => setTimeout(resolve, 2000));
          continue;
        }
        return {
          success: false,
          company: companyName,
          error: 'Request timeout',
          statusCode: null
        };
      }
      
      // Other errors
      return {
        success: false,
        company: companyName,
        error: error.message,
        statusCode: null
      };
    }
  }
  
  return {
    success: false,
    company: companyName,
    error: 'Max retries exceeded',
    statusCode: null
  };
}

// Test with different scenarios
const result1 = await findCompanyDomain('Google', 'US');
console.log(result1);

const result2 = await findCompanyDomain('NonexistentCompany12345', 'US');
console.log(result2);

Here’s what each code means and what you should actually do about it:

StatusMeaningRetry?What to do
200SuccessNoRead data.domain, but check data.exists first
400Not enough creditsNoTop up your account, then re-run the failed rows
401Invalid API keyNoFix your .env. The key is wrong or missing
404No data foundNoClean the input name. Common with brand-new companies
422Invalid data formatNoCheck for missing fields or a bad country code
500Server errorYesRetry with backoff (1s, 2s, 4s), then give up gracefully

Notice the pattern? Only 500 and network timeouts get a retry. The others won’t fix themselves, so retrying just burns time and credits.

A few error-handling habits worth keeping

Log which codes you see most. Lots of 404s usually means your input needs a scrub, not that the API is wrong.

Retry only what’s retryable. 500 and timeouts, yes. 400, 401, 404, 422, no.

Keep timeouts sane. 10 seconds is generous. For a live dashboard, drop it to 5.

Return errors a human can act on. “Invalid API key” tells you exactly what to fix. “Error occurred” tells you nothing.

These habits saved me hours of debugging when I was building enrichment jobs. If you want more patterns, our roundup of the best company-name-to-domain APIs covers how different tools handle errors.

Step 6: Process companies in bulk

Single lookups are for testing. Real work means a CSV with hundreds of rows.

Here’s how I read a CSV, enrich every row, and write a clean file back out:

import fs from 'fs';
import csv from 'csv-parser';
import { createObjectCsvWriter } from 'csv-writer';

async function processBulkCompanies(inputFile, outputFile) {
  const companies = [];
  
  // Read input CSV
  return new Promise((resolve, reject) => {
    fs.createReadStream(inputFile)
      .pipe(csv())
      .on('data', (row) => {
        if (row.company_name) {
          companies.push({
            name: row.company_name,
            country: row.country_code || 'US'
          });
        }
      })
      .on('end', async () => {
        console.log(`📋 Loaded ${companies.length} companies`);
        
        const results = [];
        
        // Process each company with progress tracking
        for (let i = 0; i < companies.length; i++) {
          const company = companies[i];
          
          console.log(`Processing ${i + 1}/${companies.length}: ${company.name}`);
          
          const result = await findCompanyDomain(company.name, company.country);
          
          results.push({
            company_name: company.name,
            country_code: company.country,
            domain: result.success ? result.domain : null,
            status: result.success ? 'found' : result.error,
            status_code: result.statusCode
          });
          
          // Rate limiting: 100 requests per second max
          // In practice, add small delay for stability
          await new Promise(resolve => setTimeout(resolve, 50));
        }
        
        // Write results to CSV
        const csvWriter = createObjectCsvWriter({
          path: outputFile,
          header: [
            { id: 'company_name', title: 'Company Name' },
            { id: 'country_code', title: 'Country Code' },
            { id: 'domain', title: 'Domain' },
            { id: 'status', title: 'Status' },
            { id: 'status_code', title: 'Status Code' }
          ]
        });
        
        await csvWriter.writeRecords(results);
        
        // Print summary
        const successCount = results.filter(r => r.status === 'found').length;
        console.log(`\n✅ Processed ${companies.length} companies`);
        console.log(`✅ Found ${successCount} domains (${(successCount/companies.length*100).toFixed(1)}%)`);
        console.log(`💾 Results saved to ${outputFile}`);
        
        resolve(results);
      })
      .on('error', reject);
  });
}

// Install required packages first:
// npm install csv-parser csv-writer

// Run bulk processing
await processBulkCompanies('companies.csv', 'companies_enriched.csv');

The progress logging matters more than it looks. On a big batch, you want to know exactly where you are. And if it crashes, you know which row to blame.

Bulk habits that save you later

Save as you go. Write results every 100 rows. If the script dies at row 467, you don’t restart from zero. I once lost a 5,000-row job to a crash near the end. Never again.

Isolate errors per row. One bad company shouldn’t take down the whole batch. Catch per company, not per file.

Clean your input first. “Google Inc.” “google” and “GOOGLE LLC” are the same company, and messy names hurt your match rate. This is really a data matching problem, so normalize before you send.

Want ideas for what to do with all these enriched domains? Our list of company-name-to-domain API use cases has 50 of them.

Step 7: The production patterns I actually use

Once the basics work, these are the patterns that make it hold up under real load.

Run requests in parallel, but with a limit

Process several companies at once instead of one-at-a-time. The trick is a concurrency cap so you don’t flood anything:

async function processInParallel(companies, concurrency = 10) {
  const results = [];
  
  for (let i = 0; i < companies.length; i += concurrency) {
    const batch = companies.slice(i, i + concurrency);
    
    const batchResults = await Promise.all(
      batch.map(company => findCompanyDomain(company.name, company.country))
    );
    
    results.push(...batchResults);
    
    console.log(`Processed ${Math.min(i + concurrency, companies.length)}/${companies.length}`);
  }
  
  return results;
}

Ten at a time turned an eight-minute job into about ninety seconds for me. Start at 10 and tune from there.

🧠 Concurrency math: pick a batch size → measure one batch → scale up only if error rates stay flat. Faster is not always better. If 404s or 500s start climbing, you went too high. Back off.

Push straight into your CRM with a webhook

Enrich a lead and forward it the moment it’s done:

async function enrichAndPushToCRM(companyName) {
  const result = await findCompanyDomain(companyName);
  
  if (result.success) {
    // Push to CRM webhook
    await fetch('https://your-crm.com/api/webhook', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        company_name: companyName,
        website: result.domain,
        enriched_date: new Date().toISOString()
      })
    });
  }
}

I hang this off a form submission through a Lambda. A lead comes in, gets a verified domain, and lands in the CRM already enriched. No manual step.

Cache repeat lookups with Redis

Store results so you don’t pay for the same company twice:

import Redis from 'ioredis';

const redis = new Redis();

async function findWithCache(companyName, countryCode = 'US') {
  // Check cache first
  const cacheKey = `domain:${companyName}:${countryCode}`;
  const cached = await redis.get(cacheKey);
  
  if (cached) {
    return JSON.parse(cached);
  }
  
  // Make API call
  const result = await findCompanyDomain(companyName, countryCode);
  
  // Cache for 30 days if successful
  if (result.success) {
    await redis.setex(cacheKey, 30 * 24 * 60 * 60, JSON.stringify(result));
  }
  
  return result;
}

Domains don’t change often, so a 30-day cache is safe and cuts your call volume a lot. If you’re new to it, the Redis docs get you running in minutes. One caching note: only cache successes. You don’t want a 500 stuck in there for a month.

Deploy it as a serverless function (AWS Lambda)

For on-demand enrichment, a serverless function is a clean fit:

// lambda.js
import axios from 'axios';

export const handler = async (event) => {
  const { company_name, country_code } = JSON.parse(event.body);
  
  try {
    const response = await axios.post(
      'https://api.companyurlfinder.com/v1/services/name_to_domain',
      {
        company_name,
        country_code: country_code || 'US'
      },
      {
        headers: {
          'x-api-key': process.env.COMPANY_URL_FINDER_API_KEY,
          'Content-Type': 'application/x-www-form-urlencoded'
        }
      }
    );
    
    return {
      statusCode: 200,
      body: JSON.stringify(response.data)
    };
  } catch (error) {
    return {
      statusCode: error.response?.status || 500,
      body: JSON.stringify({ error: error.message })
    };
  }
};

The API is stateless and fast, so it fits comfortably inside serverless timeout limits. No connection pooling, no warm-up dance. Just deploy and call.

A real example: a React lookup dashboard

Let me show you something we actually shipped.

The problem: our marketing team needed to look up domains for trade-show leads on the spot. No code, no CSVs, no waiting on engineering.

The fix: a tiny React box. Paste a company name, get the domain. It calls the same proxy endpoint from Step 4, so the key stays hidden.

Here’s the component:

// CompanyDomainFinder.jsx
import { useState } from 'react';

function CompanyDomainFinder() {
  const [companyName, setCompanyName] = useState('');
  const [result, setResult] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  
  const findDomain = async () => {
    setLoading(true);
    setError(null);
    setResult(null);
    
    try {
      // Call your backend proxy endpoint
      const response = await fetch('/api/find-domain', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          company_name: companyName,
          country_code: 'US'
        })
      });
      
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }
      
      const data = await response.json();
      setResult(data);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };
  
  return (
    <div className="p-6 max-w-md mx-auto">
      <h1 className="text-2xl font-bold mb-4">Company Domain Finder</h1>
      
      <div className="space-y-4">
        <input
          type="text"
          value={companyName}
          onChange={(e) => setCompanyName(e.target.value)}
          placeholder="Enter company name..."
          className="w-full px-4 py-2 border rounded"
          onKeyPress={(e) => e.key === 'Enter' && findDomain()}
        />
        
        <button
          onClick={findDomain}
          disabled={loading || !companyName}
          className="w-full bg-blue-500 text-white py-2 rounded hover:bg-blue-600 disabled:bg-gray-300"
        >
          {loading ? 'Finding...' : 'Find Domain'}
        </button>
        
        {error && (
          <div className="p-4 bg-red-50 border border-red-200 rounded text-red-700">
            Error: {error}
          </div>
        )}
        
        {result && result.data.exists && (
          <div className="p-4 bg-green-50 border border-green-200 rounded">
            <div className="font-semibold text-green-800">Domain Found!</div>
            <a
              href={result.data.domain}
              target="_blank"
              rel="noopener noreferrer"
              className="text-blue-600 hover:underline"
            >
              {result.data.domain}
            </a>
          </div>
        )}
        
        {result && !result.data.exists && (
          <div className="p-4 bg-yellow-50 border border-yellow-200 rounded text-yellow-800">
            No domain found for this company
          </div>
        )}
      </div>
    </div>
  );
}

export default CompanyDomainFinder;

The team runs it themselves now. Non-technical folks, enriching leads live at a booth, zero support tickets. That’s the kind of small tool that pays for itself in a week.

Add TypeScript for safer code

If you’re on TypeScript, type the response once and let the compiler catch your mistakes:

interface CompanyDomainResponse {
  status: number;
  code: number;
  errors: Record<string, any>;
  data: {
    exists: boolean;
    domain: string;
  };
}

async function findCompanyDomain(
  companyName: string,
  countryCode: string = 'US'
): Promise<CompanyDomainResponse> {
  const response = await axios.post<CompanyDomainResponse>(
    'https://api.companyurlfinder.com/v1/services/name_to_domain',
    {
      company_name: companyName,
      country_code: countryCode
    },
    {
      headers: {
        'x-api-key': process.env.COMPANY_URL_FINDER_API_KEY,
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    }
  );
  
  return response.data;
}

Now your editor autocompletes data.exists and yells at you if you forget to check it. For anything headed to production, I’d take that trade every time.

Frequently Asked Questions

Can I use this in React, Vue, or Angular?

Yes, any of them. The API call is identical across frameworks. Only your state handling differs.

The fetch or axios code copies straight across. What changes is where you store the result:

  • React: useState and useEffect
  • Vue: ref and reactive
  • Angular: the HttpClient service
  • Svelte: reactive declarations

In every one of them, the request still goes through your backend proxy. Same key-safety rule, no exceptions.

What’s the rate limit?

Up to 100 requests per second. That’s about 6,000 companies a minute if you ever pushed it that hard.

In normal use you won’t come close. Even an aggressive bulk job with 20 concurrent requests sits well under the ceiling. So you get real-time lookups and high-throughput pipelines without babysitting a throttle.

How do I keep my API key safe in a frontend app?

Never put the key in frontend code. Route every request through a backend proxy you control.

The flow is four steps:

  1. Your frontend calls your own endpoint (/api/find-domain)
  2. Your backend checks the request (session, origin, whatever you need)
  3. Your backend calls the API with the server-stored key
  4. Your backend hands the result back to the frontend

That keeps your key out of DevTools, out of network sniffers, and off public repos. And the Express proxy in Step 4 is exactly this pattern.

Does this work with TypeScript?

Yes, and it’s a good idea. Define an interface for the response and the compiler catches your mistakes before runtime.

The response shape is small and stable, so typing it takes a minute. See the CompanyDomainResponse interface above for a ready-to-use version.

Can I run it in serverless functions?

Yes. It runs cleanly on AWS Lambda, Vercel Functions, Cloudflare Workers, and Google Cloud Functions.

The API is stateless and quick, so it fits inside serverless timeouts without any warm-up overhead. And the Lambda handler in Step 7 works as a starting template for all four platforms with only minor tweaks.

Should I use built-in fetch or axios?

Either works. Use built-in fetch for quick scripts, axios when you want cleaner timeouts and error objects.

Node 18 and up ship fetch natively, so you can skip the dependency entirely for simple jobs. For bulk pipelines with retries and timeouts, axios saves you a bit of boilerplate. It’s a preference, not a rule.

How do I get a domain name from a URL in JavaScript?

That’s a different job, and it’s one line: new URL('https://blog.acme.com/post').hostname gives you blog.acme.com. No API needed, because the domain is already inside the string you have.

People mix these two up constantly, so here’s the line. Parsing extracts a domain from a URL you already possess. This tutorial does the opposite: it looks UP the domain when all you have is a company’s name. Parsing is string work. Lookup needs a data source behind an API.

You’ve got everything you need

Look how far you came.

You can authenticate with env vars, call the API in Node and the browser, hide your key behind an Express proxy, handle all six status codes, run bulk CSV jobs, and reach for caching, concurrency, webhooks, serverless, and React when you need them. That’s a full toolkit.

Start small. Wire up one lookup. Then the proxy. Then a batch. Each piece builds on the last, and none of it is complicated once the key is safe and the errors are handled.

Ready to build? Grab your free API key and make your first call in the next few minutes. You got this.

🚀 Try Our Company Name to Domain Service

Discover the fastest and most accurate tool to convert company names to domains. It takes less than a minute to sign up, and you can start seeing results right away.

Start Free Trial →
Previous Article

Company Name to Domain API in Python: Full Tutorial

Next Article

Company Name to Domain API in PHP: cURL + Guzzle Tutorial