Back to Blog
API & Developer Guides

Building a Chrome Extension with the Easy Email Finder API

Published February 19, 2026

Email Discovery Right in Your Browser

Imagine browsing Google Maps, finding an interesting business, and clicking a button to instantly see their email address. In this tutorial, you will build a Chrome extension that does exactly that, powered by the Easy Email Finder API.

Extension Architecture

Our extension has three components:

  • Content script: Injects the "Find Email" button into Google Maps pages
  • Background service worker: Handles API calls (keeps the API key secure)
  • Popup: Settings panel for API key configuration and credit balance display

Step 1: Manifest File

Create the manifest.json file that defines your extension:

{
  "manifest_version": 3,
  "name": "Easy Email Finder",
  "version": "1.0.0",
  "description": "Find business emails from Google Maps",
  "permissions": ["storage", "activeTab"],
  "host_permissions": [
    "https://easyemailfinder.com/*"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [{
    "matches": ["https://www.google.com/maps/*"],
    "js": ["content.js"],
    "css": ["content.css"]
  }],
  "action": {
    "default_popup": "popup.html",
    "default_icon": "icon.png"
  }
}

Step 2: Background Service Worker

The service worker handles all API communication, keeping your API key out of content scripts:

// background.js
const EEF_BASE = "https://easyemailfinder.com/api/v1";

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === "enrich") {
    handleEnrich(request.website).then(sendResponse);
    return true; // Keep message channel open for async response
  }
  if (request.action === "getBalance") {
    handleGetBalance().then(sendResponse);
    return true;
  }
});

async function getApiKey() {
  const data = await chrome.storage.sync.get("eef_api_key");
  return data.eef_api_key || "";
}

async function handleEnrich(website) {
  const apiKey = await getApiKey();
  if (!apiKey) {
    return { error: "API key not configured. Click the extension icon to set it up." };
  }

  try {
    const resp = await fetch(`${EEF_BASE}/enrich`, {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${apiKey}`,
        "Content-Type": "application/json"
      },
      body: JSON.stringify({ website })
    });

    if (resp.status === 401) return { error: "Invalid API key" };
    if (resp.status === 402) return { error: "No credits remaining" };
    if (resp.status === 429) return { error: "Rate limited. Try again in a moment." };

    return await resp.json();
  } catch (err) {
    return { error: "Network error. Check your connection." };
  }
}

async function handleGetBalance() {
  const apiKey = await getApiKey();
  if (!apiKey) return { credits: 0 };

  try {
    const resp = await fetch(`${EEF_BASE}/balance`, {
      headers: { "Authorization": `Bearer ${apiKey}` }
    });
    return await resp.json();
  } catch {
    return { credits: 0 };
  }
}

Step 3: Content Script

The content script detects when you are viewing a business on Google Maps and injects the "Find Email" button:

// content.js
function injectEmailButton() {
  // Check if we already injected
  if (document.querySelector('.eef-email-btn')) return;

  // Find the business website link in the Maps panel
  const websiteLink = document.querySelector('a[data-item-id="authority"]');
  if (!websiteLink) return;

  const website = websiteLink.href;

  // Create the button
  const btn = document.createElement('button');
  btn.className = 'eef-email-btn';
  btn.textContent = 'Find Email';
  btn.onclick = async () => {
    btn.textContent = 'Searching...';
    btn.disabled = true;

    chrome.runtime.sendMessage(
      { action: "enrich", website },
      (response) => {
        if (response.error) {
          btn.textContent = response.error;
          btn.style.backgroundColor = '#ef4444';
        } else if (response.email) {
          btn.textContent = response.email;
          btn.style.backgroundColor = '#22c55e';

          // Make it clickable to copy
          btn.onclick = () => {
            navigator.clipboard.writeText(response.email);
            btn.textContent = 'Copied!';
            setTimeout(() => { btn.textContent = response.email; }, 1500);
          };
        } else {
          btn.textContent = 'No email found';
          btn.style.backgroundColor = '#f59e0b';
        }
        btn.disabled = false;
      }
    );
  };

  // Insert after the website link
  websiteLink.parentElement.parentElement.after(btn);
}

// Google Maps is a single-page app, so watch for navigation changes
const observer = new MutationObserver(() => {
  setTimeout(injectEmailButton, 1000);
});

observer.observe(document.body, { childList: true, subtree: true });
injectEmailButton();

Step 4: Popup for Settings

<!-- popup.html -->
<div style="width: 300px; padding: 16px; font-family: sans-serif;">
  <h3>Easy Email Finder</h3>
  <div id="balance">Loading...</div>
  <label>API Key:</label>
  <input type="password" id="apiKey" style="width: 100%; margin: 8px 0;" />
  <button id="saveBtn">Save</button>
  <p style="font-size: 12px; margin-top: 12px;">
    Get your API key at
    <a href="https://easyemailfinder.com/developer/docs" target="_blank">
      easyemailfinder.com/developer/docs
    </a>
  </p>
</div>
<script src="popup.js"></script>
// popup.js
document.addEventListener('DOMContentLoaded', async () => {
  const data = await chrome.storage.sync.get("eef_api_key");
  document.getElementById("apiKey").value = data.eef_api_key || "";

  // Get balance
  chrome.runtime.sendMessage({ action: "getBalance" }, (resp) => {
    const credits = resp?.credits || 0;
    document.getElementById("balance").textContent =
      `Credits: ${credits} ($${(credits * 0.25).toFixed(2)})`;
  });

  document.getElementById("saveBtn").onclick = async () => {
    const key = document.getElementById("apiKey").value;
    await chrome.storage.sync.set({ eef_api_key: key });
    window.close();
  };
});

Step 5: Load and Test

Open chrome://extensions, enable Developer Mode, click "Load unpacked," and select your extension folder. Navigate to Google Maps, search for a business, and look for the "Find Email" button in the sidebar.

Security Best Practices

  • The API key is stored in Chrome's sync storage and never exposed to web pages
  • All API calls go through the background service worker, not the content script
  • The extension only activates on Google Maps pages

Publishing

To publish on the Chrome Web Store, create a developer account ($5 one-time fee), zip your extension files, and submit for review. Make sure to include a clear privacy policy since you are handling API keys.

Next Steps

Extend the extension to batch-find emails for all visible businesses on the map, add export functionality, or integrate with your CRM. For backend patterns, see our Node.js pipeline guide. For API details, visit easyemailfinder.com/developer/docs.

Ready to find business emails?

Try Easy Email Finder free — get 5 credits to start.

Start Finding Emails

Related Posts