Wix Form Email Verification API Integration (Step-by-Step)

checkboxHQ Team
Email Verification Wix Integration Wix Forms Email Validation Form Validation Wix Automations

checkboxHQ + Wix + Airtable Integration Guide

Overview

This guide demonstrates how to integrate checkboxHQ’s email verification API with Wix forms and store validated results in Airtable using a non-blocking verification approach. checkboxHQ validates emails asynchronously after form submission, ensuring a smooth user experience without delays or interruptions.

This setup is ideal for:

  • Lead capture forms that need post-submission email quality scoring
  • Newsletter signups with background verification for list hygiene
  • Contact forms that store all submissions but flag invalid emails for review
  • E-commerce sites wanting to verify customer emails without friction
  • Any workflow requiring clean email data without impacting form conversion rates

Architecture

Wix Form Submission → Immediate Success Response to User
Wix Automation (Webhook) → Serverless Function
checkboxHQ API Verification (background)
Airtable Storage (with verification results)

Key Principle: The user receives immediate confirmation of their submission. Email verification happens in the background without blocking the user’s experience.

Prerequisites

  1. checkboxHQ Account

  2. Wix

    • Wix site with Premium plan (required for Automations)
    • Form created on your site (Wix Forms)
  3. Airtable

    • Airtable account with a base created
    • Personal Access Token
  4. Serverless Platform (choose one)

    • Netlify Functions (recommended for beginners)
    • Vercel Functions
    • AWS Lambda
    • Cloudflare Workers

Step 1: Set Up Airtable Base

Create Your Base Structure

Create a table called Email Submissions with these fields:

Field NameField TypeDescription
Submission IDSingle line textUnique identifier for tracking
EmailEmailThe submitted email address
NameSingle line textSubmitter’s name (if collected)
Form NameSingle line textWhich Wix form was submitted
Submission DateCreated timeAuto-populated timestamp
StatusSingle selectOptions: Valid, Disposable Email, Invalid Domain, Verification Error, Pending Verification
Verification StatusSingle selectOptions: Pending, In Progress, Completed, Failed
Is DisposableCheckboxWhether email is from disposable provider
Is Public ProviderCheckboxWhether email is from public provider (Gmail, etc.)
Has MX RecordCheckboxWhether domain has valid MX records
Has A RecordCheckboxWhether domain has valid A records
DomainSingle line textExtracted domain from email
ProviderSingle line textEmail provider name if identified
Verified AtDate & timeWhen verification completed
Verification ErrorLong textError message if verification failed

Why this structure?

  • Initial submission creates record immediately with “Pending Verification” status
  • Background verification updates the same record with results
  • You can filter and view submissions while verification is in progress
  • No user waits for verification to complete

Get Airtable Credentials

  1. Go to airtable.com/create/tokens
  2. Create a Personal Access Token with these scopes:
    • data.records:read
    • data.records:write
  3. Note your:
    • Base ID: Found in API documentation (starts with app)
    • Table Name: Email Submissions (or your custom name)
    • Access Token: Your newly created token

Step 2: Create Serverless Function

Example: Netlify Function (Non-Blocking Pattern)

Create a file: netlify/functions/wix-verify-email.js

netlify/functions/wix-verify-email.js
const fetch = require('node-fetch');
exports.handler = async (event, context) => {
// Set CORS headers for Wix
const headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Methods': 'POST, OPTIONS'
};
// Handle preflight OPTIONS request
if (event.httpMethod === 'OPTIONS') {
return {
statusCode: 200,
headers,
body: ''
};
}
// Only allow POST requests
if (event.httpMethod !== 'POST') {
return {
statusCode: 405,
headers,
body: JSON.stringify({ error: 'Method not allowed' })
};
}
try {
// Parse Wix webhook payload
const payload = JSON.parse(event.body);
// Wix sends form data in this structure
const email = payload.email || payload.data?.email;
const name = payload.name || payload.data?.name || '';
const formName = payload.formName || payload.data?.formName || 'Contact Form';
const submissionId = payload.submissionId || Date.now().toString();
if (!email) {
return {
statusCode: 400,
headers,
body: JSON.stringify({ error: 'Email is required' })
};
}
// STEP 1: Immediately store submission in Airtable (user already received success)
await storeInitialSubmission(email, name, formName, submissionId);
// STEP 2: Perform verification asynchronously (fire and forget)
// Don't await - let it run in background
verifyAndUpdateAsync(email, submissionId).catch(error => {
console.error('Background verification error:', error);
// Log error but don't fail the webhook response
});
// STEP 3: Return immediate success to Wix
// User experience is not impacted by verification delay
return {
statusCode: 200,
headers,
body: JSON.stringify({
success: true,
message: 'Submission received and being processed',
submissionId: submissionId
})
};
} catch (error) {
console.error('Error:', error);
return {
statusCode: 500,
headers,
body: JSON.stringify({
error: 'Submission processing failed',
details: error.message
})
};
}
};
// Store initial submission immediately (before verification)
async function storeInitialSubmission(email, name, formName, submissionId) {
const AIRTABLE_TOKEN = process.env.AIRTABLE_TOKEN;
const AIRTABLE_BASE_ID = process.env.AIRTABLE_BASE_ID;
const AIRTABLE_TABLE_NAME = process.env.AIRTABLE_TABLE_NAME || 'Email Submissions';
const airtablePayload = {
records: [
{
fields: {
'Email': email,
'Name': name,
'Form Name': formName,
'Submission ID': submissionId,
'Status': 'Pending Verification',
'Verification Status': 'In Progress'
}
}
]
};
const response = await fetch(
`https://api.airtable.com/v0/${AIRTABLE_BASE_ID}/${encodeURIComponent(AIRTABLE_TABLE_NAME)}`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${AIRTABLE_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(airtablePayload)
}
);
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Airtable error: ${errorText}`);
}
const result = await response.json();
return result.records[0].id; // Return Airtable record ID
}
// Async verification that updates the existing record
async function verifyAndUpdateAsync(email, submissionId) {
try {
// Perform CheckBoxHQ verification
const verificationData = await verifyEmailWithCheckBox(email);
// Update the existing Airtable record with verification results
await updateAirtableRecord(submissionId, verificationData);
console.log(`Verification completed for ${email}`);
} catch (error) {
console.error(`Verification failed for ${email}:`, error);
// Update record with error status
await updateAirtableRecord(submissionId, {
verification_error: error.message,
verification_status: 'Failed'
});
}
}
// CheckBoxHQ API Integration Functions
async function verifyEmailWithCheckBox(email) {
const CHECKBOX_API_KEY = process.env.CHECKBOX_API_KEY;
// Perform all verifications (adjust based on your needs)
// 1. Disposable email check (1 credit)
const disposableCheck = await fetch('https://api.checkboxhq.com/api/v1/verify_disposable/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': CHECKBOX_API_KEY
},
body: JSON.stringify({ email })
});
if (!disposableCheck.ok) {
throw new Error(`Disposable check failed: ${disposableCheck.statusText}`);
}
const disposableData = await disposableCheck.json();
// 2. DNS verification (2 credits)
const dnsCheck = await fetch('https://api.checkboxhq.com/api/v1/verify_dns/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': CHECKBOX_API_KEY
},
body: JSON.stringify({ email })
});
if (!dnsCheck.ok) {
throw new Error(`DNS check failed: ${dnsCheck.statusText}`);
}
const dnsData = await dnsCheck.json();
// 3. Public provider check (1 credit)
const publicCheck = await fetch('https://api.checkboxhq.com/api/v1/verify_public_provider/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': CHECKBOX_API_KEY
},
body: JSON.stringify({ email })
});
if (!publicCheck.ok) {
throw new Error(`Public provider check failed: ${publicCheck.statusText}`);
}
const publicData = await publicCheck.json();
// Combine all verification results
return {
email: disposableData.email,
is_disposable: disposableData.is_disposable,
is_valid_format: disposableData.is_valid_format,
domain: disposableData.domain,
provider: disposableData.provider || dnsData.provider || publicData.provider,
has_mx_record: dnsData.has_mx_record,
has_a_record: dnsData.has_a_record,
mx_records: dnsData.mx_records,
a_records: dnsData.a_records,
is_public_provider: publicData.is_public_provider
};
}
async function updateAirtableRecord(submissionId, verificationData) {
const AIRTABLE_TOKEN = process.env.AIRTABLE_TOKEN;
const AIRTABLE_BASE_ID = process.env.AIRTABLE_BASE_ID;
const AIRTABLE_TABLE_NAME = process.env.AIRTABLE_TABLE_NAME || 'Email Submissions';
// First, find the record by Submission ID
const searchUrl = `https://api.airtable.com/v0/${AIRTABLE_BASE_ID}/${encodeURIComponent(AIRTABLE_TABLE_NAME)}?filterByFormula={Submission ID}="${submissionId}"`;
const searchResponse = await fetch(searchUrl, {
headers: {
'Authorization': `Bearer ${AIRTABLE_TOKEN}`
}
});
const searchData = await searchResponse.json();
if (!searchData.records || searchData.records.length === 0) {
throw new Error(`Record not found for submission ID: ${submissionId}`);
}
const recordId = searchData.records[0].id;
// Determine final status
let status = 'Valid';
if (verificationData.verification_error) {
status = 'Verification Error';
} else if (verificationData.is_disposable) {
status = 'Disposable Email';
} else if (!verificationData.has_mx_record) {
status = 'Invalid Domain';
}
// Update the record with verification results
const updatePayload = {
fields: {
'Is Disposable': verificationData.is_disposable || false,
'Is Public Provider': verificationData.is_public_provider || false,
'Has MX Record': verificationData.has_mx_record || false,
'Has A Record': verificationData.has_a_record || false,
'Domain': verificationData.domain || '',
'Provider': verificationData.provider || '',
'Status': status,
'Verification Status': verificationData.verification_error ? 'Failed' : 'Completed',
'Verified At': new Date().toISOString()
}
};
if (verificationData.verification_error) {
updatePayload.fields['Verification Error'] = verificationData.verification_error;
}
const updateResponse = await fetch(
`https://api.airtable.com/v0/${AIRTABLE_BASE_ID}/${encodeURIComponent(AIRTABLE_TABLE_NAME)}/${recordId}`,
{
method: 'PATCH',
headers: {
'Authorization': `Bearer ${AIRTABLE_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(updatePayload)
}
);
if (!updateResponse.ok) {
const errorText = await updateResponse.text();
throw new Error(`Airtable update error: ${errorText}`);
}
return await updateResponse.json();
}

Environment Variables

Add these to your Netlify dashboard (or equivalent):

CHECKBOX_API_KEY=your_checkbox_api_key_here
AIRTABLE_TOKEN=your_airtable_token_here
AIRTABLE_BASE_ID=appXXXXXXXXXXXXXX
AIRTABLE_TABLE_NAME=Email Submissions

Deploy the Function

  1. Create a Git repository with your function code
  2. Connect to Netlify (or your chosen platform)
  3. Deploy automatically
  4. Your function will be available at: https://yoursite.netlify.app/.netlify/functions/wix-verify-email

Step 3: Configure Wix Form

Create or Select Your Form

  1. In Wix Editor, add or select a Form element
  2. Ensure it has:
    • Email input field (required)
    • Name input field (optional but recommended)
  3. Publish your site

Set Up Wix Automation

Step-by-Step Instructions:

  1. Access Automations

    • In your Wix Dashboard, click Automations in the left sidebar
    • Click + New Automation or + Create Automation
  2. Choose Trigger

    • Select Wix Forms as your trigger
    • Choose Form is submitted
    • Select which form triggers this automation (or choose “Any form”)
    • Click Apply
  3. Add Webhook Action

    • Click the + icon to add an action
    • Select Send via webhook or HTTP Request
    • Configure the webhook:
  4. Webhook Configuration

    Target URL: https://yoursite.netlify.app/.netlify/functions/wix-verify-email
    HTTP Method: POST
    Data to Send: All keys and values
  5. Map Form Fields (if using “Customize structure”)

    Key: email Value: [Insert Variable] → Email field
    Key: name Value: [Insert Variable] → Name field
    Key: formName Value: [Insert Variable] → Form name
    Key: submissionId Value: [Insert Variable] → Submission ID
  6. Activate Automation

    • Give your automation a name (e.g., “Email Verification”)
    • Click Activate

Form Submission Flow (Non-Blocking)

When a user submits the form:

  1. User submits → Wix captures the submission
  2. Wix shows success → User sees confirmation immediately (no delay)
  3. Wix triggers automation → Sends webhook to your serverless function
  4. Function stores initial record → Creates Airtable entry with “Pending Verification”
  5. Function returns success → Webhook completes quickly (~300-500ms)
  6. Background verification starts → CheckBoxHQ APIs called asynchronously
  7. Airtable record updated → Verification results populate the existing record

Key Benefit: Steps 1-5 happen in under 1 second. Steps 6-7 happen in the background without impacting user experience or conversion rates.

Step 4: Testing Your Integration

Test Checklist

  1. Submit Test Form

    • Fill out your Wix form with a test email
    • Verify you get immediate success message
  2. Check Airtable

    • Open your Airtable base
    • Verify new record appears with “Pending Verification” status
    • Wait 5-10 seconds
    • Refresh and verify verification results appear
  3. Test Different Email Types

  4. Check Function Logs

    • Go to Netlify Functions dashboard
    • View logs for wix-verify-email
    • Verify no errors

Debugging Common Issues

Issue: Webhook not triggering

  • Verify automation is activated in Wix
  • Check webhook URL is correct (copy-paste without typos)
  • Ensure site is published (not just preview)

Issue: Records not appearing in Airtable

  • Check Airtable credentials in environment variables
  • Verify table name matches exactly (case-sensitive)
  • Check function logs for errors

Issue: Verification not completing

  • Verify checkboxHQ API key is valid
  • Check you have available credits
  • Review function logs for API errors

Step 5: Advanced Features

Enhanced Error Handling

// Add retry logic with exponential backoff
async function verifyEmailWithRetry(email, maxRetries = 3) {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await verifyEmailWithCheckBox(email);
} catch (error) {
lastError = error;
console.log(`Verification attempt ${attempt} failed for ${email}:`, error.message);
// Wait before retrying (exponential backoff)
if (attempt < maxRetries) {
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt)));
}
}
}
throw new Error(`Failed after ${maxRetries} attempts: ${lastError.message}`);
}

Webhook Signature Verification (Security)

// Add security check to verify webhook is from Wix
function verifyWixWebhook(payload, signature) {
// Wix sends webhooks as JWT tokens
// Implement JWT verification here
// See: https://dev.wix.com/docs/build-apps/develop-your-app/api-integrations/events-and-webhooks/about-webhooks
}

Conditional Verification (Cost Optimization)

// Only verify business emails (skip free providers to save credits)
async function smartVerification(email) {
const domain = email.split('@')[1];
const freeProviders = ['gmail.com', 'yahoo.com', 'hotmail.com', 'outlook.com'];
if (freeProviders.includes(domain.toLowerCase())) {
// Skip full verification for known free providers
return {
email,
is_public_provider: true,
is_disposable: false,
provider: domain,
skip_reason: 'Known free provider'
};
}
// Full verification for business emails
return await verifyEmailWithCheckBox(email);
}

Optimization Strategies

Why Non-Blocking Verification Matters

Conversion Rate Impact:

  • Blocking verification: 2-5 second delay = 10-20% form abandonment
  • Non-blocking verification: <1 second response = optimal conversion rates
  • Users get immediate confirmation while quality checks happen behind the scenes

Credit Management

checkboxHQ API endpoints consume different credits:

  • verify_disposable: 1 credit
  • verify_public_provider: 1 credit
  • verify_dns: 2 credits

Cost-Effective Strategy for Background Verification:

async function optimizedBackgroundVerification(email) {
// Strategy 1: Sequential verification (stop early if disposable)
const disposableCheck = await checkDisposable(email);
if (disposableCheck.is_disposable) {
// Stop here - no need to check DNS for disposable emails (saves 2 credits)
return {
...disposableCheck,
verification_type: 'disposable-only',
credits_used: 1
};
}
// Strategy 2: Parallel verification for non-disposable emails
const [dnsCheck, publicCheck] = await Promise.all([
checkDNS(email), // 2 credits
checkPublic(email) // 1 credit
]);
return {
...disposableCheck,
...dnsCheck,
...publicCheck,
verification_type: 'comprehensive',
credits_used: 4
};
}

Domain-Level Caching

// Cache verification results by domain to reduce API calls
const CACHE_TTL = 7 * 24 * 60 * 60 * 1000; // 7 days
async function verifyWithCache(email) {
const domain = email.split('@')[1];
// Check cache (using Redis, Upstash, or similar)
const cached = await getCachedDomainInfo(domain);
if (cached) {
console.log(`Using cached verification for domain: ${domain}`);
return { ...cached, email, from_cache: true };
}
// Not cached - perform full verification
const verification = await verifyEmailWithCheckBox(email);
// Cache domain-level results
await cacheDomainInfo(domain, verification);
return verification;
}

The checkboxHQ Philosophy: Why Non-Blocking?

User Experience First

Blocking VerificationNon-Blocking Verification (CheckBoxHQ)
User waits 2-5 secondsUser gets instant confirmation (<1s)
Form feels slow/brokenForm feels fast and responsive
10-20% form abandonmentMinimal abandonment
API timeout = failed submissionAPI issues don’t affect users
Poor mobile experienceWorks great on any connection

Business Impact

Higher Conversion Rates:

  • Every second of delay = 7% conversion loss
  • Non-blocking maintains optimal conversion rates
  • Capture the lead, verify in the background

Clean Data Without Trade-offs:

  • Still get full verification results
  • Act on results via automation
  • Better than no verification at all

Smart Actions Based on Verification

Instead of blocking users, use verification data to:

Segment your email lists - Different campaigns for business vs. public emails
Prioritize sales follow-ups - Focus on verified, non-disposable emails first
Flag for manual review - Let humans handle edge cases
Track form quality - Monitor which sources attract disposable emails
Clean before export - Filter when syncing to CRM/Email Service Provider
Trigger different workflows - Send instant confirmation to verified emails

Don’t block form submissions - This hurts conversion and user trust
Don’t make users wait - Verification delay = lost opportunities
Don’t fail forms on API errors - Always capture the lead first

Post-Verification Actions

Airtable Automations for Follow-Up

Once verification completes in the background, trigger actions based on results:

Automation 1: Send to CRM (Valid Emails Only)

Trigger: When "Status" = "Valid"
Action: Create record in your CRM or send to Zapier/Make

Automation 2: Flag for Review (Invalid Emails)

Trigger: When "Status" = "Disposable Email" OR "Invalid Domain"
Action: Send Slack notification to team for manual review

Automation 3: Segment Marketing Lists

Trigger: When "Is Public Provider" = true
Action: Add to consumer email list
When "Is Public Provider" = false AND "Status" = "Valid"
Action: Add to business/B2B email list

Integration with Email Marketing

// Add to your verification function
async function sendToEmailMarketing(email, verificationData) {
// Only send verified, non-disposable emails
if (!verificationData.is_disposable && verificationData.has_mx_record) {
const tags = [];
if (verificationData.is_public_provider) {
tags.push('consumer');
} else {
tags.push('business');
}
await fetch('https://api.youremailprovider.com/subscribe', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.EMAIL_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email,
tags: tags
})
});
}
}

Monitoring & Analytics

Track API Usage

Monitor your checkboxHQ credit usage:

async function checkAPIUsage() {
const response = await fetch('https://api.checkboxhq.com/api/v1/billing/usage', {
headers: {
'Authorization': `Bearer ${process.env.CHECKBOX_ACCESS_TOKEN}`
}
});
const usage = await response.json();
console.log(`API Usage: ${usage.requests_used}/${usage.requests_limit} (${usage.percentage_used}%)`);
// Alert if running low on credits
if (usage.percentage_used > 80) {
await sendLowCreditAlert(usage);
}
return usage;
}

Airtable Analytics Views

Create these views in Airtable:

  1. Pending Verifications: Filter by “Verification Status” = “Pending” or “In Progress”
  2. Disposable Emails: Filter by “Is Disposable” = checked
  3. Valid Business Emails: Filter by “Status” = “Valid” AND “Is Public Provider” = unchecked
  4. Verification Errors: Filter by “Status” = “Verification Error”
  5. Daily Summary: Group by “Submission Date” with counts

Troubleshooting

Common Issues

Issue: Submissions not appearing in Airtable

  • Check webhook is configured correctly in Wix Automations
  • Verify webhook URL is accessible (test with curl or Postman)
  • Check serverless function logs for errors
  • Ensure Airtable credentials are correct in environment variables

Issue: Records stuck in “In Progress” status

  • Background verification may have failed silently
  • Check function logs for errors
  • Verify checkboxHQ API key is valid and has credits
  • Ensure error handling updates records on failure

Issue: Verification taking too long

  • Normal for DNS checks (can take 5-30 seconds)
  • This doesn’t affect user experience (they already got confirmation)
  • Consider implementing caching for popular domains
  • Check if sequential verification strategy could reduce time

Issue: Wix Automation not triggering

  • Verify automation is activated (not just saved)
  • Check that form is published on live site
  • Test with actual form submission (not preview mode)
  • Premium Wix plan required for Automations

Issue: CORS errors

  • Ensure CORS headers are set in function response
  • Check Access-Control-Allow-Origin is set to * or specific domain
  • Verify OPTIONS method is handled for preflight requests

Issue: Authentication errors from checkboxHQ

  • Verify x-api-key header is correctly set
  • Check API key is active in checkboxHQ dashboard
  • Ensure environment variables are deployed (not just local)
  • API keys are case-sensitive

Issue: Airtable write failures

  • Verify Personal Access Token has write permissions
  • Check Base ID and Table Name are exactly correct
  • Ensure field names match case-sensitively
  • Check you haven’t exceeded Airtable rate limits (5 requests/second)

Debug Mode

Add detailed logging for troubleshooting:

const DEBUG = process.env.NODE_ENV !== 'production';
function log(stage, ...args) {
if (DEBUG) {
console.log(`[${new Date().toISOString()}] [${stage}]`, ...args);
}
}
// Usage in your handler
exports.handler = async (event, context) => {
log('WEBHOOK', 'Received submission:', event.body);
const email = payload.email;
log('PARSED', 'Email extracted:', email);
await storeInitialSubmission(email, name, formName, submissionId);
log('STORAGE', 'Initial record created:', submissionId);
verifyAndUpdateAsync(email, submissionId).catch(error => {
log('VERIFY-ERROR', 'Background verification failed:', error);
});
log('RESPONSE', 'Returning success to Wix');
return { statusCode: 200, body: JSON.stringify({ success: true }) };
};

Security Best Practices

1. Never Expose API Keys

// ❌ WRONG - Don't hardcode keys
const API_KEY = 'sk_live_abc123';
// ✅ CORRECT - Use environment variables
const API_KEY = process.env.CHECKBOX_API_KEY;

2. Validate Webhook Source

// Verify webhook is actually from Wix
function isValidWixWebhook(event) {
// Check user agent
const userAgent = event.headers['user-agent'];
if (!userAgent || !userAgent.includes('Wix')) {
return false;
}
// Additional verification can be added here
return true;
}

3. Rate Limiting

// Simple rate limiting by IP
const submissions = new Map();
function checkRateLimit(ip) {
const now = Date.now();
const userSubmissions = submissions.get(ip) || [];
const recentSubmissions = userSubmissions.filter(
time => now - time < 60000 // Last minute
);
if (recentSubmissions.length >= 5) {
throw new Error('Rate limit exceeded - max 5 submissions per minute');
}
submissions.set(ip, [...recentSubmissions, now]);
return true;
}

4. Input Validation

function validateEmail(email) {
// Basic format validation
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
throw new Error('Invalid email format');
}
// Length validation
if (email.length > 254) {
throw new Error('Email too long');
}
return true;
}

Cost-Benefit Analysis

Per-Submission Cost Breakdown

Infrastructure Costs (Free Tier Sufficient for Most):

  • Airtable Free: 1,200 records/month
  • Netlify Free: 125,000 function invocations/month
  • Vercel Free: 100,000 function invocations/month

Verification Costs:

Scenario 1: Basic validation (disposable + public provider)

  • checkboxHQ: 2 credits per submission
  • Best for: Basic lead quality scoring
  • Use case: Newsletter signups, content downloads

Scenario 2: Comprehensive validation (all checks)

  • checkboxHQ: 4 credits per submission (disposable + public + DNS)
  • Best for: Sales leads, high-value conversions
  • Use case: Demo requests, contact sales forms

Scenario 3: Smart sequential validation

  • checkboxHQ: 1-4 credits (adaptive based on results)
  • Check disposable first (1 credit)
  • Only check DNS if not disposable (saves 2 credits on 30-40% of submissions)
  • Best for: Cost optimization with high volume

ROI Calculation: Blocking vs Non-Blocking

Example: 1,000 Monthly Form Submissions

MetricBlocking VerificationNon-Blocking (checkboxHQ)
Form Response Time3-5 seconds<1 second
Conversion Rate8% (industry avg with delays)10% (no delay penalty)
Actual Conversions80 submissions100 submissions
Lost Opportunities20 submissions0 submissions
Customer ValueMissed $2,000+ potential revenueFull capture

The Math:

  • 2-second delay = 10-20% conversion loss
  • Non-blocking captures 100% of interested visitors
  • Lost conversion costs far exceed verification API costs

Start with comprehensive validation (4 credits):

  1. Captures all leads (no blocking)
  2. Full verification data for segmentation
  3. Optimize later based on your form quality patterns
  4. Worth the investment to maintain high conversion rates

When you reach high volume (>10,000/month):

  • Implement smart sequential validation (saves 30-40% on credits)
  • Add domain caching (saves another 20-30%)
  • Batch processing for efficiency

Alternative Platforms

Vercel Functions

api/wix-verify-email.js
export default async function handler(req, res) {
// Set CORS headers
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === 'OPTIONS') {
return res.status(200).end();
}
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
// Same logic as Netlify function
// ...
}

Cloudflare Workers

addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
// Handle CORS
if (request.method === 'OPTIONS') {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type'
}
})
}
// Same logic adapted for Cloudflare Workers
// ...
}

Next Steps

  1. Test the integration with various email types
  2. Monitor API usage in using checkboxHQ’s billing endpoint
  3. Set up alerts for low credit balance
  4. Create Airtable views to analyze submission quality
  5. Build automations with Airtable + Zapier/Make for follow-up workflows
  6. A/B test different form configurations
  7. Review analytics monthly to optimize verification strategy

Support Resources

Additional Resources