EmailVerify LogoEmailVerify

BigCommerce

Email checker for BigCommerce. Verify customer emails at checkout and registration.

Integrate EmailVerify with BigCommerce to verify customer emails at checkout, reduce fraud, and improve deliverability for order confirmations and marketing emails.

Integration Methods

MethodBest ForComplexity
Script ManagerQuick setupLow
Stencil ThemeCustom themesMedium
Storefront APIHeadless storesHigh

Method 1: Script Manager Integration

Add real-time email verification using BigCommerce Script Manager.

Create Verification Script

  1. Go to StorefrontScript Manager
  2. Click Create a Script
  3. Configure:
    • Name: EmailVerify Email Verification
    • Location: Footer
    • Pages: Checkout

Script Code

<script>
(function() {
    const EMAILVERIFY_API_KEY = 'YOUR_API_KEY';

    // Wait for checkout to load
    function waitForCheckout() {
        const emailInput = document.querySelector('[data-test="customer-email"] input, #email');

        if (emailInput) {
            initVerification(emailInput);
        } else {
            setTimeout(waitForCheckout, 500);
        }
    }

    function initVerification(emailInput) {
        const statusEl = document.createElement('span');
        statusEl.className = 'bv-status';
        emailInput.parentNode.appendChild(statusEl);

        let verifyTimeout;
        let lastEmail = '';

        emailInput.addEventListener('blur', function() {
            const email = this.value;

            if (!email || email === lastEmail || !isValidFormat(email)) {
                return;
            }

            clearTimeout(verifyTimeout);

            verifyTimeout = setTimeout(function() {
                verifyEmail(email, statusEl);
                lastEmail = email;
            }, 500);
        });
    }

    async function verifyEmail(email, statusEl) {
        statusEl.textContent = 'Verifying...';
        statusEl.className = 'bv-status verifying';

        try {
            const response = await fetch('https://api.emailverify.ai/v1/verify', {
                method: 'POST',
                headers: {
                    'Authorization': 'Bearer ' + EMAILVERIFY_API_KEY,
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ email: email })
            });

            const data = await response.json();

            if (data.status === 'valid') {
                statusEl.textContent = '✓ Email verified';
                statusEl.className = 'bv-status valid';
            } else if (data.status === 'invalid') {
                statusEl.textContent = '✗ Please enter a valid email';
                statusEl.className = 'bv-status invalid';
            } else if (data.result && data.result.disposable) {
                statusEl.textContent = '✗ Please use a permanent email';
                statusEl.className = 'bv-status invalid';
            } else {
                statusEl.textContent = '';
                statusEl.className = 'bv-status';
            }
        } catch (error) {
            console.error('Verification error:', error);
            statusEl.textContent = '';
            statusEl.className = 'bv-status';
        }
    }

    function isValidFormat(email) {
        return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
    }

    // Add styles
    const style = document.createElement('style');
    style.textContent = `
        .bv-status {
            display: block;
            margin-top: 4px;
            font-size: 12px;
        }
        .bv-status.verifying { color: #666; }
        .bv-status.valid { color: #28a745; }
        .bv-status.invalid { color: #dc3545; }
    `;
    document.head.appendChild(style);

    // Initialize
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', waitForCheckout);
    } else {
        waitForCheckout();
    }
})();
</script>

Method 2: Stencil Theme Integration

For custom Stencil themes, add verification directly to your theme files.

Create Theme Component

// assets/js/theme/global/email-verification.js
import utils from '@bigcommerce/stencil-utils';

export default class EmailVerification {
    constructor() {
        this.apiKey = window.emailverifyConfig?.apiKey;
        this.emailInputs = document.querySelectorAll('input[type="email"]');
        this.cache = new Map();

        if (this.apiKey && this.emailInputs.length) {
            this.init();
        }
    }

    init() {
        this.emailInputs.forEach(input => {
            this.attachVerification(input);
        });
    }

    attachVerification(input) {
        const statusEl = document.createElement('span');
        statusEl.className = 'form-field-verification';
        input.parentNode.appendChild(statusEl);

        let timeout;

        input.addEventListener('blur', () => {
            const email = input.value.trim();

            if (!email || !this.isValidFormat(email)) {
                this.clearStatus(statusEl);
                return;
            }

            clearTimeout(timeout);
            timeout = setTimeout(() => this.verify(email, statusEl, input), 500);
        });
    }

    async verify(email, statusEl, input) {
        // Check cache
        if (this.cache.has(email)) {
            this.displayResult(this.cache.get(email), statusEl, input);
            return;
        }

        this.showLoading(statusEl);

        try {
            const response = await fetch('https://api.emailverify.ai/v1/verify', {
                method: 'POST',
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`,
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ email })
            });

            const data = await response.json();
            this.cache.set(email, data);
            this.displayResult(data, statusEl, input);

        } catch (error) {
            console.error('Email verification error:', error);
            this.clearStatus(statusEl);
        }
    }

    displayResult(data, statusEl, input) {
        input.classList.remove('is-valid', 'is-invalid');

        if (data.status === 'valid' && !data.result?.disposable) {
            statusEl.innerHTML = '<span class="icon icon--success"></span> Verified';
            statusEl.className = 'form-field-verification is-valid';
            input.classList.add('is-valid');
        } else if (data.status === 'invalid') {
            statusEl.innerHTML = '<span class="icon icon--error"></span> Invalid email';
            statusEl.className = 'form-field-verification is-invalid';
            input.classList.add('is-invalid');
        } else if (data.result?.disposable) {
            statusEl.innerHTML = '<span class="icon icon--warning"></span> Please use a permanent email';
            statusEl.className = 'form-field-verification is-invalid';
            input.classList.add('is-invalid');
        } else {
            this.clearStatus(statusEl);
        }
    }

    showLoading(statusEl) {
        statusEl.innerHTML = '<span class="spinner"></span> Verifying...';
        statusEl.className = 'form-field-verification is-loading';
    }

    clearStatus(statusEl) {
        statusEl.innerHTML = '';
        statusEl.className = 'form-field-verification';
    }

    isValidFormat(email) {
        return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
    }
}

Initialize in Theme

// assets/js/theme/global.js
import EmailVerification from './global/email-verification';

export default class Global extends PageManager {
    onReady() {
        // ... other initializations

        new EmailVerification();
    }
}

Theme Configuration

Add to config.json:

{
    "settings": {
        "emailverify_enabled": true,
        "emailverify_api_key": ""
    }
}

Schema Settings

Add to schema.json for admin configuration:

[
    {
        "name": "EmailVerify",
        "settings": [
            {
                "type": "checkbox",
                "label": "Enable Email Verification",
                "id": "emailverify_enabled"
            },
            {
                "type": "text",
                "label": "API Key",
                "id": "emailverify_api_key"
            }
        ]
    }
]

Inject Config to Template

{{!-- templates/layout/base.html --}}
<script>
    window.emailverifyConfig = {
        enabled: {{settings.emailverify_enabled}},
        apiKey: '{{settings.emailverify_api_key}}'
    };
</script>

Method 3: Storefront API Integration

For headless BigCommerce stores using the Storefront API.

Verification Service

// services/email-verification.ts
interface VerificationResult {
  email: string;
  status: 'valid' | 'invalid' | 'unknown';
  score?: number;
  isDisposable: boolean;
  isRole: boolean;
}

class EmailVerificationService {
  private apiKey: string;
  private cache: Map<string, VerificationResult> = new Map();

  constructor(apiKey: string) {
    this.apiKey = apiKey;
  }

  async verify(email: string): Promise<VerificationResult> {
    // Check cache
    const cached = this.cache.get(email);
    if (cached) {
      return cached;
    }

    try {
      const response = await fetch('https://api.emailverify.ai/v1/verify', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.apiKey}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ email }),
      });

      const data = await response.json();

      const result: VerificationResult = {
        email,
        status: data.status,
        score: data.score,
        isDisposable: data.result?.disposable ?? false,
        isRole: data.result?.role ?? false,
      };

      this.cache.set(email, result);
      return result;

    } catch (error) {
      console.error('Verification error:', error);
      return {
        email,
        status: 'unknown',
        isDisposable: false,
        isRole: false,
      };
    }
  }

  isValid(result: VerificationResult): boolean {
    return result.status === 'valid' && !result.isDisposable;
  }

  getErrorMessage(result: VerificationResult): string | null {
    if (result.status === 'invalid') {
      return 'Please enter a valid email address.';
    }
    if (result.isDisposable) {
      return 'Temporary email addresses are not accepted.';
    }
    return null;
  }
}

export const emailVerification = new EmailVerificationService(
  process.env.EMAILVERIFY_API_KEY!
);

React Checkout Component

// components/checkout/EmailInput.tsx
import { useState, useCallback } from 'react';
import { emailVerification } from '@/services/email-verification';
import { debounce } from 'lodash';

interface EmailInputProps {
  value: string;
  onChange: (value: string) => void;
  onValidationChange: (isValid: boolean) => void;
}

export function EmailInput({ value, onChange, onValidationChange }: EmailInputProps) {
  const [status, setStatus] = useState<'idle' | 'verifying' | 'valid' | 'invalid'>('idle');
  const [message, setMessage] = useState('');

  const verifyEmail = useCallback(
    debounce(async (email: string) => {
      if (!email || !email.includes('@')) {
        setStatus('idle');
        setMessage('');
        return;
      }

      setStatus('verifying');

      const result = await emailVerification.verify(email);

      if (emailVerification.isValid(result)) {
        setStatus('valid');
        setMessage('Email verified');
        onValidationChange(true);
      } else {
        setStatus('invalid');
        setMessage(emailVerification.getErrorMessage(result) || 'Verification failed');
        onValidationChange(false);
      }
    }, 500),
    [onValidationChange]
  );

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const newValue = e.target.value;
    onChange(newValue);
    verifyEmail(newValue);
  };

  return (
    <div className="form-field">
      <label htmlFor="email">Email Address</label>
      <input
        type="email"
        id="email"
        value={value}
        onChange={handleChange}
        className={`form-input ${status === 'valid' ? 'is-valid' : ''} ${status === 'invalid' ? 'is-invalid' : ''}`}
      />
      {status !== 'idle' && (
        <span className={`form-feedback ${status}`}>
          {status === 'verifying' && <Spinner />}
          {message}
        </span>
      )}
    </div>
  );
}

Next.js API Route

For server-side verification to protect your API key:

// pages/api/verify-email.ts
import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  const { email } = req.body;

  if (!email) {
    return res.status(400).json({ error: 'Email required' });
  }

  try {
    const response = await fetch('https://api.emailverify.ai/v1/verify', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.EMAILVERIFY_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ email }),
    });

    const data = await response.json();

    return res.status(200).json({
      valid: data.status === 'valid' && !data.result?.disposable,
      status: data.status,
      disposable: data.result?.disposable ?? false,
    });

  } catch (error) {
    console.error('Verification error:', error);
    return res.status(200).json({ valid: true }); // Allow on error
  }
}

Webhooks Integration

Process orders and verify emails asynchronously.

Webhook Handler

// api/webhooks/bigcommerce.js
import crypto from 'crypto';
import EmailVerify from '@emailverify/sdk';

const bv = new EmailVerify(process.env.EMAILVERIFY_API_KEY);

export default async function handler(req, res) {
    // Verify webhook signature
    const signature = req.headers['x-bc-webhook-signature'];
    const expectedSignature = crypto
        .createHmac('sha256', process.env.BC_WEBHOOK_SECRET)
        .update(JSON.stringify(req.body))
        .digest('base64');

    if (signature !== expectedSignature) {
        return res.status(401).json({ error: 'Invalid signature' });
    }

    const { scope, data } = req.body;

    if (scope === 'store/order/created') {
        await handleOrderCreated(data);
    }

    res.status(200).json({ received: true });
}

async function handleOrderCreated(data) {
    const orderId = data.id;

    // Fetch order details from BigCommerce
    const order = await fetchOrder(orderId);

    if (!order.billing_address?.email) {
        return;
    }

    // Verify email
    const result = await bv.verify({ email: order.billing_address.email });

    // Store verification result
    await storeVerificationResult(orderId, result);

    // Flag suspicious orders
    if (result.status === 'invalid' || result.is_disposable) {
        await flagOrder(orderId, {
            reason: result.status === 'invalid'
                ? 'Invalid email address'
                : 'Disposable email detected',
            verification: result,
        });
    }
}

async function fetchOrder(orderId) {
    const response = await fetch(
        `https://api.bigcommerce.com/stores/${process.env.BC_STORE_HASH}/v2/orders/${orderId}`,
        {
            headers: {
                'X-Auth-Token': process.env.BC_ACCESS_TOKEN,
                'Accept': 'application/json',
            },
        }
    );

    return response.json();
}

async function flagOrder(orderId, data) {
    // Add order note or update status
    await fetch(
        `https://api.bigcommerce.com/stores/${process.env.BC_STORE_HASH}/v2/orders/${orderId}`,
        {
            method: 'PUT',
            headers: {
                'X-Auth-Token': process.env.BC_ACCESS_TOKEN,
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                staff_notes: `⚠️ Email Verification Warning: ${data.reason}`,
            }),
        }
    );
}

Register Webhook

async function registerWebhook() {
    const response = await fetch(
        `https://api.bigcommerce.com/stores/${process.env.BC_STORE_HASH}/v3/hooks`,
        {
            method: 'POST',
            headers: {
                'X-Auth-Token': process.env.BC_ACCESS_TOKEN,
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                scope: 'store/order/created',
                destination: 'https://yoursite.com/api/webhooks/bigcommerce',
                is_active: true,
            }),
        }
    );

    return response.json();
}

Bulk Customer Verification

Verify existing customers in your store.

import EmailVerify from '@emailverify/sdk';

const bv = new EmailVerify(process.env.EMAILVERIFY_API_KEY);

async function verifyAllCustomers() {
    const customers = await fetchAllCustomers();
    const emails = customers.map(c => c.email);

    console.log(`Verifying ${emails.length} customer emails...`);

    // Submit bulk job
    const job = await bv.verifyBulk(emails);
    console.log(`Job ID: ${job.job_id}`);

    // Wait for completion
    let status;
    do {
        await sleep(5000);
        status = await bv.getBulkJobStatus(job.job_id);
        console.log(`Progress: ${status.progress_percent}%`);
    } while (status.status !== 'completed');

    // Process results
    const results = await bv.getBulkJobResults(job.job_id);

    const stats = { valid: 0, invalid: 0, disposable: 0 };

    for (const result of results.results) {
        if (result.status === 'valid') stats.valid++;
        else stats.invalid++;

        if (result.is_disposable) stats.disposable++;

        // Update customer record
        const customer = customers.find(c => c.email === result.email);
        if (customer) {
            await updateCustomerMeta(customer.id, {
                email_status: result.status,
                email_score: result.score,
            });
        }
    }

    console.log('Verification complete:', stats);
    return stats;
}

async function fetchAllCustomers() {
    const customers = [];
    let page = 1;

    while (true) {
        const response = await fetch(
            `https://api.bigcommerce.com/stores/${process.env.BC_STORE_HASH}/v3/customers?page=${page}&limit=250`,
            {
                headers: {
                    'X-Auth-Token': process.env.BC_ACCESS_TOKEN,
                },
            }
        );

        const data = await response.json();

        if (data.data.length === 0) break;

        customers.push(...data.data);
        page++;
    }

    return customers;
}

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

Best Practices

1. Protect Your API Key

Never expose your API key in client-side code. Use a proxy:

// Server-side proxy
app.post('/api/verify', async (req, res) => {
    const { email } = req.body;

    const result = await bv.verify({ email });

    // Only return necessary data
    res.json({
        valid: result.status === 'valid',
        disposable: result.is_disposable,
    });
});

2. Cache Results

const cache = new Map();
const CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours

function getCachedResult(email) {
    const cached = cache.get(email);
    if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
        return cached.result;
    }
    return null;
}

function setCachedResult(email, result) {
    cache.set(email, { result, timestamp: Date.now() });
}

3. Handle Errors Gracefully

try {
    const result = await verifyEmail(email);
    // ... handle result
} catch (error) {
    console.error('Verification failed:', error);
    // Allow checkout to proceed
    return { valid: true };
}

On this page