WordPress Gravity Forms Email Verification with HubSpot Integration

checkboxHQ
wordpress gravity-forms hubspot email-verification crm-integration lead-validation form-spam-prevention b2b-marketing marketing-automation contact-form api-integration zapier-alternative webhook-integration enterprise-wordpress sales-automation

Clean Your HubSpot CRM Without Losing Conversions

If you’re using Gravity Forms on WordPress to capture leads and syncing them to HubSpot, you know the challenge: fake email addresses, typos, and spam submissions clutter your CRM. But blocking submissions creates user friction and kills conversions.

This guide shows you how to verify email addresses in the background using checkboxHQ while maintaining 100% form conversion rates. Your users get instant confirmation, while you get clean, verified contacts in HubSpot.


What You’ll Build

By the end of this guide, you’ll have:

  • Non-blocking email verification - Users get instant confirmation

  • Background validation - Email verified after form submission

  • Automatic HubSpot sync with rich verification metadata

  • 6+ custom contact properties tracking email quality metrics

  • Error handling for API failures and edge cases

  • Lead scoring enhancement - Verified emails get +15-20 points

  • Production-ready setup with proper logging and monitoring

  • Zero User Friction - Forms submit instantly, verification happens silently in background


Prerequisites

Required Accounts & Tools

  1. WordPress site (5.0 or higher) with admin access
  2. Gravity Forms (2.5+ recommended) - Purchase License
  3. HubSpot account (Free tier works, Marketing Hub recommended)
  4. checkboxHQ account - Register for free
  5. Basic PHP knowledge (copy-paste friendly, but helpful to understand)

Required Plugins

  • Gravity Forms (core plugin)
  • Gravity Forms HubSpot Add-On (free from GF downloads)

Architecture Overview

Here’s how the non-blocking system works:

User fills form → Form submits immediately (<1 second)
User sees confirmation page
Background verification starts
checkboxHQ API calls (3 endpoints):
1. /verify_disposable/ (1 credit)
2. /verify_dns/ (2 credits)
3. /verify_public_provider/ (1 credit)
Results stored in WordPress database
HubSpot sync triggered with verification data
→ Contact created/updated with custom properties
→ Lead scoring applied
→ Workflows triggered

Key Benefits:

  • Zero user friction: Instant form confirmation, no waiting
  • 100% conversion rate: Never blocks legitimate users
  • Complete validation: Gets disposable, DNS, and provider data
  • Rich HubSpot data: 6+ custom properties for segmentation
  • Background processing: Verification happens while user reads confirmation

Credit Usage per Verification:

  • Total: 4 credits (1 + 2 + 1)
  • On 5,000 verifications/month plan: Can verify 1,250 leads/month

Step 1: Install and Configure Gravity Forms

1.1 Install Gravity Forms

If you haven’t already:

  1. Purchase Gravity Forms license from gravityforms.com
  2. Download the plugin ZIP file
  3. In WordPress admin: Plugins → Add New → Upload Plugin
  4. Upload gravityforms.zip and activate
  5. Enter your license key: Forms → Settings → License

1.2 Install HubSpot Add-On

  1. Go to Forms → Add-Ons
  2. Find HubSpot Add-On and click “Install”
  3. Activate the add-on
  4. Click “Settings” next to HubSpot Add-On
  5. Authenticate with your HubSpot account (OAuth flow)

Step 2: Get Your checkboxHQ API Key

2.1 Sign Up for checkboxHQ

  1. Visit checkboxhq.com/signup
  2. Create your free account (100 verifications/month included)
  3. Confirm your email address

2.2 Generate API Key

  1. Log into your checkboxHQ dashboard
  2. Navigate to API Keys section
  3. Click “Create New API Key”
  4. Name it: wordpress-gravity-forms
  5. Copy the API key

Security Note: Keep this API key secure. Never commit it to public repositories or share it in support tickets.


Step 3: Create Your Lead Capture Form

3.1 Build the Form

  1. In WordPress admin, go to Forms → New Form
  2. Name it: “Contact Us - Email Verified”
  3. Add these fields:

Required Fields:

  • Name (Type: Name - First & Last)
  • Email (Type: Email) ← This is what we’ll verify
  • Company (Type: Text)
  • Phone (Type: Phone, optional)

Optional Fields:

  • Message (Type: Textarea)
  • How did you hear about us? (Type: Dropdown)

3.2 Configure Email Field Validation

  1. Click on the Email field to edit
  2. Under General tab:
    • Check “Required”
    • Enable “Confirm Email” (optional but recommended)
  3. Under Advanced tab:
    • Add CSS Class: verify-email
    • Note the Field ID (usually 2 if it’s your second field)

3.3 Enable HubSpot Integration

  1. Click Settings (top right of form builder)
  2. Click HubSpot tab
  3. Choose “Create a new feed”
  4. Name: “Verified Lead to HubSpot”
  5. Map fields:
    • Email → HubSpot Contact Email
    • First Name → First Name
    • Last Name → Last Name
    • Company → Company Name
    • Phone → Phone Number

Important: Don’t save yet - we’ll add custom properties in Step 5.


Step 4: Add Email Verification to WordPress

4.1 Add API Key to WordPress Config

For security, store your API key in wp-config.php (not in theme files):

  1. Connect to your WordPress site via FTP/SFTP or hosting file manager
  2. Edit wp-config.php (in your WordPress root directory)
  3. Add this line above the /* That's all, stop editing! */ comment:
// checkboxHQ API Configuration
define('CHECKBOXHQ_API_KEY', 'cbx_your_actual_api_key_here');
define('CHECKBOXHQ_API_BASE_URL', 'https://api.checkboxhq.com');

Replace cbx_your_actual_api_key_here with your real API key from Step 2.2.

4.2 Create Email Verification Function

Add this code to your theme’s functions.php file or a custom plugin:

Location: wp-content/themes/your-theme/functions.php

<?php
/**
* checkboxHQ Email Verification for Gravity Forms
*
* NON-BLOCKING email verification: User gets instant form confirmation,
* email verification happens in background, results sync to HubSpot
*
* This maintains conversion rates while cleaning your email list
*/
// Prevent direct access
if (!defined('ABSPATH')) exit;
/**
* Verify email using checkboxHQ API (comprehensive check)
*
* Combines disposable + DNS checks for complete validation
* Uses 3 credits total per verification (1 + 2)
*
* @param string $email Email address to verify
* @return array Verification result with all metadata
*/
function checkboxhq_verify_email_complete($email) {
// Validate email format first (basic check)
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return [
'success' => false,
'is_valid' => false,
'is_disposable' => false,
'has_mx_record' => false,
'has_a_record' => false,
'is_public_provider' => false,
'provider' => null,
'reason' => 'invalid_format',
'message' => 'Invalid email format'
];
}
// Get API credentials from wp-config.php
$api_key = defined('CHECKBOXHQ_API_KEY') ? CHECKBOXHQ_API_KEY : '';
$api_base = defined('CHECKBOXHQ_API_BASE_URL') ? CHECKBOXHQ_API_BASE_URL : 'https://api.checkboxhq.com';
// Check if API key is configured
if (empty($api_key)) {
error_log('checkboxHQ Error: API key not configured in wp-config.php');
return [
'success' => false,
'reason' => 'api_not_configured',
'message' => 'Email verification not configured'
];
}
$results = [
'success' => true,
'email' => $email,
'is_valid' => true, // Default assumption
'is_disposable' => false,
'has_mx_record' => false,
'has_a_record' => false,
'is_public_provider' => false,
'provider' => null,
'mx_records' => [],
'a_records' => []
];
// Step 1: Check if disposable email (1 credit)
$disposable_check = checkboxhq_api_call($api_base . '/api/v1/verify_disposable/', $api_key, ['email' => $email]);
if ($disposable_check && isset($disposable_check['is_disposable'])) {
$results['is_disposable'] = $disposable_check['is_disposable'];
$results['is_valid'] = $disposable_check['is_valid_format'];
$results['provider'] = $disposable_check['provider'];
}
// Step 2: Check DNS records (2 credits)
$dns_check = checkboxhq_api_call($api_base . '/api/v1/verify_dns/', $api_key, ['email' => $email]);
if ($dns_check && isset($dns_check['has_mx_record'])) {
$results['has_mx_record'] = $dns_check['has_mx_record'];
$results['has_a_record'] = $dns_check['has_a_record'];
$results['mx_records'] = $dns_check['mx_records'] ?? [];
$results['a_records'] = $dns_check['a_records'] ?? [];
// Override provider if DNS check provides more info
if (!empty($dns_check['provider'])) {
$results['provider'] = $dns_check['provider'];
}
}
// Step 3: Check if public provider (1 credit) - Optional for lead scoring
$public_check = checkboxhq_api_call($api_base . '/api/v1/verify_public_provider/', $api_key, ['email' => $email]);
if ($public_check && isset($public_check['is_public_provider'])) {
$results['is_public_provider'] = $public_check['is_public_provider'];
}
// Determine overall validity
// Email is valid if: has valid format + has MX records + NOT disposable
$results['is_deliverable'] = $results['is_valid'] && $results['has_mx_record'] && !$results['is_disposable'];
// Determine reason for invalidity
if (!$results['is_valid']) {
$results['reason'] = 'invalid_format';
} elseif ($results['is_disposable']) {
$results['reason'] = 'disposable';
} elseif (!$results['has_mx_record']) {
$results['reason'] = 'no_mx_records';
} else {
$results['reason'] = 'valid';
}
return $results;
}
/**
* Make API call to checkboxHQ endpoint
*
* @param string $endpoint Full API endpoint URL
* @param string $api_key API key for authentication
* @param array $data Request payload
* @return array|null Response data or null on error
*/
function checkboxhq_api_call($endpoint, $api_key, $data) {
$args = [
'method' => 'POST',
'timeout' => 10,
'headers' => [
'x-api-key' => $api_key, // Correct header format
'Content-Type' => 'application/json',
'User-Agent' => 'WordPress-GravityForms/' . get_bloginfo('version')
],
'body' => json_encode($data)
];
$response = wp_remote_post($endpoint, $args);
// Handle network errors
if (is_wp_error($response)) {
error_log('checkboxHQ API Error (' . $endpoint . '): ' . $response->get_error_message());
return null;
}
$status_code = wp_remote_retrieve_response_code($response);
$response_body = wp_remote_retrieve_body($response);
// Handle non-200 responses
if ($status_code !== 200) {
error_log('checkboxHQ API Error: HTTP ' . $status_code . ' - ' . $response_body);
return null;
}
return json_decode($response_body, true);
}
/**
* NON-BLOCKING: Verify email AFTER form submission
*
* User gets instant confirmation, verification happens in background
* Results are stored and synced to HubSpot
*
* @param array $entry Form entry data
* @param array $form Form configuration
*/
add_action('gform_after_submission', 'checkboxhq_verify_after_submission', 10, 2);
function checkboxhq_verify_after_submission($entry, $form) {
// Find email field
foreach ($form['fields'] as $field) {
if ($field->type !== 'email') {
continue;
}
$email = rgar($entry, $field->id);
// Skip empty emails
if (empty($email)) {
continue;
}
// Perform verification (non-blocking - happens after user sees confirmation)
$verification = checkboxhq_verify_email_complete($email);
// Store verification result in entry meta
gform_update_meta($entry['id'], 'checkboxhq_verification', $verification);
gform_update_meta($entry['id'], 'checkboxhq_verification_date', current_time('mysql'));
// Log result
error_log(sprintf(
'checkboxHQ Verification - Email: %s, Deliverable: %s, Disposable: %s, Has MX: %s, Reason: %s',
$email,
$verification['is_deliverable'] ? 'Yes' : 'No',
$verification['is_disposable'] ? 'Yes' : 'No',
$verification['has_mx_record'] ? 'Yes' : 'No',
$verification['reason'] ?? 'unknown'
));
// Only process first email field
break;
}
}
/**
* Optional: Add email validation note to entry
*
* @param array $entry Form entry data
* @param array $form Form configuration
*/
add_action('gform_after_submission', 'checkboxhq_add_entry_note', 11, 2);
function checkboxhq_add_entry_note($entry, $form) {
$verification = gform_get_meta($entry['id'], 'checkboxhq_verification');
if ($verification && isset($verification['reason'])) {
$note = 'Email Verification: ' . ucfirst($verification['reason']);
if ($verification['is_disposable']) {
$note .= ' (Disposable Email - Review Required)';
} elseif (!$verification['has_mx_record']) {
$note .= ' (No MX Records - Likely Invalid)';
} elseif ($verification['is_deliverable']) {
$note .= ' ✓ (Verified & Deliverable)';
}
GFFormsModel::add_note($entry['id'], 0, 'checkboxHQ', $note, 'checkboxhq');
}
}

Save the file and verify there are no PHP errors by visiting your site.


Step 5: Sync Verified Leads to HubSpot with Custom Properties

5.1 Create Custom Properties in HubSpot

To track email verification status in HubSpot:

  1. Log into HubSpot
  2. Go to Settings (gear icon)
  3. Navigate to Data Management → Properties
  4. Click Create property
  5. Create these contact properties:

Property 1: Email Verification Status

  • Object type: Contact
  • Group: Contact Information
  • Label: Email Verification Status
  • Field type: Dropdown select
  • Internal name: email_verification_status
  • Options: valid, disposable, no_mx_records, invalid_format
  • Description: Result of email validation check

Property 2: Email Deliverable

  • Object type: Contact
  • Group: Contact Information
  • Label: Email Deliverable
  • Field type: Single checkbox
  • Internal name: email_deliverable
  • Description: Whether the email passed full deliverability check (valid format + MX records + not disposable)

Property 3: Email Provider

  • Object type: Contact
  • Group: Contact Information
  • Label: Email Provider
  • Field type: Single-line text
  • Internal name: email_provider
  • Description: Detected email service provider (Gmail, Outlook, company domain, etc.)

Property 4: Disposable Email Flag

  • Object type: Contact
  • Group: Contact Information
  • Label: Disposable Email Flag
  • Field type: Single checkbox
  • Internal name: disposable_email_flag
  • Description: Indicates if email is from a temporary/disposable service

Property 5: Public Email Provider

  • Object type: Contact
  • Group: Contact Information
  • Label: Public Email Provider
  • Field type: Single checkbox
  • Internal name: public_email_provider
  • Description: Indicates if email is from public provider (Gmail, Yahoo, etc.) vs business domain

Property 6: Email Has MX Records

  • Object type: Contact
  • Group: Contact Information
  • Label: Email Has MX Records
  • Field type: Single checkbox
  • Internal name: email_has_mx_records
  • Description: Technical validation - domain configured to receive email

Property 7: Email Verified Date

  • Object type: Contact
  • Group: Contact Information
  • Label: Email Verified Date
  • Field type: Date picker
  • Internal name: email_verified_date
  • Description: Date when email was last verified

5.2 Map Verification Data to HubSpot

Add this code to your functions.php (below the previous code):

/**
* Add verification data to HubSpot contact properties
*
* @param array $entry Gravity Forms entry
* @param array $form Form configuration
*/
add_filter('gform_hubspot_contact_properties', 'checkboxhq_add_hubspot_properties', 10, 3);
function checkboxhq_add_hubspot_properties($properties, $entry, $form) {
// Get verification data from entry meta
$verification = gform_get_meta($entry['id'], 'checkboxhq_verification');
if ($verification && $verification['success']) {
// Add custom properties to HubSpot contact
$properties['email_verification_status'] = $verification['reason'];
$properties['email_deliverable'] = $verification['is_deliverable'] ? 'true' : 'false';
$properties['email_verified_date'] = date('Y-m-d');
// Additional enrichment data
if (!empty($verification['provider'])) {
$properties['email_provider'] = $verification['provider'];
}
// Flag disposable emails
if ($verification['is_disposable']) {
$properties['disposable_email_flag'] = 'true';
}
// Flag public providers (Gmail, Yahoo, etc.) for lead scoring
if (isset($verification['is_public_provider']) && $verification['is_public_provider']) {
$properties['public_email_provider'] = 'true';
}
// MX record status (technical validation)
$properties['email_has_mx_records'] = $verification['has_mx_record'] ? 'true' : 'false';
// Optional: Boost lead score for verified emails
if ($verification['is_deliverable']) {
if (isset($properties['hs_lead_score'])) {
$properties['hs_lead_score'] = intval($properties['hs_lead_score']) + 15;
}
// Extra points for business emails (non-public providers)
if (isset($verification['is_public_provider']) && !$verification['is_public_provider']) {
$properties['hs_lead_score'] = intval($properties['hs_lead_score']) + 5;
}
}
}
return $properties;
}

5.3 Update HubSpot Feed Mapping

Since verification happens AFTER submission, all contacts sync to HubSpot (with verification data):

  1. Go back to your form: Forms → Select your form → Settings → HubSpot

  2. Edit the HubSpot feed

  3. Ensure these fields are mapped:

    • Email → HubSpot Contact Email
    • First Name → First Name
    • Last Name → Last Name
    • Company → Company Name
    • Phone → Phone Number
  4. Save the feed

Note: Unlike blocking verification, we DON’T use conditional logic. All submissions sync to HubSpot with their verification status. You can then use HubSpot workflows to route verified vs unverified leads differently.


6.1 Create Lead Routing Workflow - High Quality Leads

Route verified business emails to sales immediately:

  1. Automation → Workflows → Create workflow
  2. Choose “Contact-based” workflow
  3. Name: “Hot Lead - Verified Business Email”
  4. Enrollment trigger:
    • Email Verification Status is valid
    • AND Email Deliverable is true
    • AND Public Email Provider is false (business domain, not Gmail)
  5. Actions:
    • Increase HubSpot Score by 20 points
    • Add to list: “High Quality Leads”
    • Send internal notification to sales team
    • Create task: “Hot lead - follow up within 1 hour”
    • Set lifecycle stage to “SQL” (Sales Qualified Lead)
  6. Save and activate

6.2 Create Lead Routing Workflow - Requires Review

Flag disposable/invalid emails for manual review:

  1. Automation → Workflows → Create workflow
  2. Name: “Flag Suspicious Leads”
  3. Enrollment trigger:
    • Disposable Email Flag is true
    • OR Email Has MX Records is false
  4. Actions:
    • Decrease HubSpot Score by 10 points
    • Add to list: “Needs Manual Review”
    • Send internal notification to operations team
    • Create task: “Review lead quality before contacting”
    • Add tag: “suspicious-email”
  5. Save and activate

6.3 Create Lead Scoring Workflow - Consumer Emails

Handle public email providers (Gmail, Yahoo) differently:

  1. Automation → Workflows → Create workflow
  2. Name: “Consumer Email Lead Scoring”
  3. Enrollment trigger:
    • Email Deliverable is true
    • AND Public Email Provider is true
  4. Actions:
    • Increase HubSpot Score by 10 points (lower than business emails)
    • Add to list: “Consumer Email Leads”
    • Set lifecycle stage to “MQL” (Marketing Qualified Lead)
    • Enroll in nurture sequence (longer sales cycle)
  5. Save and activate

6.4 Automated Re-verification Workflow

Re-verify old contacts periodically (optional):

  1. Automation → Workflows → Create workflow
  2. Name: “Re-verify Email Quarterly”
  3. Enrollment trigger:
    • Email Verified Date is more than 90 days ago
  4. Actions:
    • Send webhook to WordPress endpoint (trigger re-verification)
    • Update Email Verified Date to today
  5. Save and activate

Step 7: Testing Your Integration

7.1 Test with Valid Email

  1. Go to your form page on the website
  2. Fill out the form with a real email address (use your own)
  3. Click submit
  4. Expected behavior:
    • Form submits instantly (<1 second)
    • Confirmation message appears immediately
    • Check WordPress admin: Forms → Entries → View Entry
    • Look for “Email Verification” note (added within 5-10 seconds)
    • Contact appears in HubSpot within 2-3 minutes
    • Custom properties populated:
      • email_verification_status: valid
      • email_deliverable: true
      • email_has_mx_records: true

7.2 Test with Disposable Email

  1. Fill out form with a disposable email (e.g., [email protected])
  2. Click submit
  3. Expected behavior:
    • Form still submits instantly (non-blocking!)
    • User sees confirmation message
    • Entry created in Gravity Forms
    • Entry note shows: “Email Verification: Disposable (Disposable Email - Review Required)”
    • HubSpot contact created with:
      • email_verification_status: disposable
      • disposable_email_flag: true
      • email_deliverable: false

7.3 Test with Invalid Email (Typo)

  1. Fill out form with typo email (e.g., [email protected])
  2. Click submit
  3. Expected behavior:
    • Form submits instantly
    • Entry note shows: “Email Verification: No_mx_records (No MX Records - Likely Invalid)”
    • HubSpot contact created with:
      • email_verification_status: no_mx_records
      • email_has_mx_records: false
      • email_deliverable: false

7.4 Monitor Background Verification

Watch verification happen in real-time:

  1. Submit a form
  2. Immediately go to Forms → Entries
  3. Click on the latest entry
  4. Scroll to Entry Meta or Notes section
  5. Refresh page after 5-10 seconds
  6. Note should appear with verification result

7.5 Check WordPress Debug Logs

If something isn’t working:

  1. Enable WordPress debug logging in wp-config.php:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
  1. Check /wp-content/debug.log for entries like:
checkboxHQ Verification - Email: [email protected], Deliverable: Yes, Disposable: No, Has MX: Yes, Reason: valid
checkboxHQ API Error (/api/v1/verify_disposable/): HTTP 401 - Invalid API key

Step 8: Monitor and Optimize

8.1 Track Verification Metrics

Create a HubSpot report to monitor email quality:

  1. Reports → Create report → Custom report builder
  2. Data source: Contacts
  3. Add metrics:
    • Total contacts created
    • Contacts by Email Verification Status
    • Form submissions vs verified leads
  4. Date range: Last 30 days

Key metrics to watch:

  • Verification pass rate: Should be >85% for organic traffic
  • Disposable email blocks: High numbers = bot traffic or fraud
  • Invalid email blocks: High numbers = typos or fake submissions

8.2 Set Up Email Alerts

Get notified if verification API fails:

Add this to functions.php:

/**
* Send admin alert if verification API is down
*/
add_action('checkboxhq_api_error', 'checkboxhq_send_admin_alert');
function checkboxhq_send_admin_alert($error_message) {
$admin_email = get_option('admin_email');
$subject = '[ALERT] checkboxHQ Email Verification Down';
$message = "The checkboxHQ email verification API is experiencing issues:\n\n";
$message .= "Error: " . $error_message . "\n\n";
$message .= "Forms are currently accepting all submissions (fail-open mode).\n";
$message .= "Please check your API key and account status at checkboxhq.com\n";
wp_mail($admin_email, $subject, $message);
}

Trigger this action in the checkboxhq_verify_email function when errors occur.


Advanced Configurations

Option 1: Reduce API Credit Usage (Use Only DNS Check)

If you want to save credits, use only DNS verification (2 credits instead of 4):

/**
* Lightweight verification - DNS check only
* Uses 2 credits per verification
*/
function checkboxhq_verify_email_lightweight($email) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return ['success' => false, 'reason' => 'invalid_format'];
}
$api_key = defined('CHECKBOXHQ_API_KEY') ? CHECKBOXHQ_API_KEY : '';
$api_base = defined('CHECKBOXHQ_API_BASE_URL') ? CHECKBOXHQ_API_BASE_URL : 'https://api.checkboxhq.com';
// Only call DNS verification endpoint
$dns_check = checkboxhq_api_call($api_base . '/api/v1/verify_dns/', $api_key, ['email' => $email]);
return [
'success' => true,
'email' => $email,
'is_deliverable' => $dns_check['has_mx_record'] ?? false,
'has_mx_record' => $dns_check['has_mx_record'] ?? false,
'has_a_record' => $dns_check['has_a_record'] ?? false,
'provider' => $dns_check['provider'] ?? null,
'reason' => ($dns_check['has_mx_record'] ?? false) ? 'valid' : 'no_mx_records'
];
}
// Replace in checkboxhq_verify_after_submission function:
$verification = checkboxhq_verify_email_lightweight($email);

Option 2: Priority Verification (Verify Only High-Value Forms)

Only verify specific forms to save credits:

/**
* Only verify high-priority forms (e.g., demo requests, enterprise inquiries)
*/
add_action('gform_after_submission', 'checkboxhq_selective_verification', 10, 2);
function checkboxhq_selective_verification($entry, $form) {
// Only verify these form IDs
$priority_form_ids = [1, 5, 12]; // Replace with your form IDs
if (!in_array($form['id'], $priority_form_ids)) {
return; // Skip verification for other forms
}
// Proceed with verification...
foreach ($form['fields'] as $field) {
if ($field->type === 'email') {
$email = rgar($entry, $field->id);
$verification = checkboxhq_verify_email_complete($email);
gform_update_meta($entry['id'], 'checkboxhq_verification', $verification);
break;
}
}
}

Option 3: Cache Verification Results

Avoid re-verifying the same email across multiple forms:

/**
* Cache verification results for 24 hours
*/
function checkboxhq_verify_email_cached($email) {
$cache_key = 'checkboxhq_' . md5(strtolower(trim($email)));
$cached = get_transient($cache_key);
if ($cached !== false) {
error_log('checkboxHQ: Using cached result for ' . $email);
return $cached;
}
$result = checkboxhq_verify_email_complete($email);
// Cache for 24 hours (DAY_IN_SECONDS = 86400)
set_transient($cache_key, $result, DAY_IN_SECONDS);
return $result;
}
// Update checkboxhq_verify_after_submission to use cached version:
$verification = checkboxhq_verify_email_cached($email);

Option 4: Whitelist Trusted Domains

Skip verification for known partner/customer domains:

/**
* Whitelist trusted email domains
*/
function checkboxhq_is_whitelisted_domain($email) {
$whitelisted_domains = [
'youragency.com',
'trustedpartner.com',
'enterpriseclient.com'
];
$domain = substr(strrchr($email, "@"), 1);
return in_array(strtolower($domain), $whitelisted_domains);
}
// Add to checkboxhq_verify_after_submission:
if (checkboxhq_is_whitelisted_domain($email)) {
gform_update_meta($entry['id'], 'checkboxhq_verification', [
'success' => true,
'is_deliverable' => true,
'reason' => 'whitelisted',
'provider' => 'trusted_domain'
]);
return; // Skip API call
}

Option 5: Batch Verification with WP-Cron

Verify in batches every 5 minutes to reduce server load:

/**
* Queue entries for batch verification
*/
add_action('gform_after_submission', 'checkboxhq_queue_for_batch', 10, 2);
function checkboxhq_queue_for_batch($entry, $form) {
foreach ($form['fields'] as $field) {
if ($field->type === 'email') {
$email = rgar($entry, $field->id);
// Add to verification queue
$queue = get_option('checkboxhq_verification_queue', []);
$queue[] = [
'entry_id' => $entry['id'],
'email' => $email,
'timestamp' => time()
];
update_option('checkboxhq_verification_queue', $queue);
break;
}
}
}
/**
* Process verification queue every 5 minutes
*/
add_action('checkboxhq_process_batch', 'checkboxhq_batch_verify');
function checkboxhq_batch_verify() {
$queue = get_option('checkboxhq_verification_queue', []);
if (empty($queue)) {
return;
}
// Process up to 50 at a time
$batch = array_splice($queue, 0, 50);
foreach ($batch as $item) {
$verification = checkboxhq_verify_email_complete($item['email']);
gform_update_meta($item['entry_id'], 'checkboxhq_verification', $verification);
}
// Update queue
update_option('checkboxhq_verification_queue', $queue);
}
// Schedule cron job (add to theme activation)
if (!wp_next_scheduled('checkboxhq_process_batch')) {
wp_schedule_event(time(), 'five_minutes', 'checkboxhq_process_batch');
}
// Add custom cron interval
add_filter('cron_schedules', 'checkboxhq_add_cron_interval');
function checkboxhq_add_cron_interval($schedules) {
$schedules['five_minutes'] = [
'interval' => 300,
'display' => 'Every 5 Minutes'
];
return $schedules;
}

Option 6: Flag But Don’t Block Suspicious Emails

Add warnings to suspicious entries without blocking submission:

/**
* Add colored flags to Gravity Forms entries list
*/
add_filter('gform_entries_field_value', 'checkboxhq_flag_suspicious_entries', 10, 4);
function checkboxhq_flag_suspicious_entries($value, $form_id, $field_id, $entry) {
// Only modify email field display
$form = GFAPI::get_form($form_id);
$field = GFFormsModel::get_field($form, $field_id);
if ($field->type !== 'email') {
return $value;
}
$verification = gform_get_meta($entry['id'], 'checkboxhq_verification');
if (!$verification) {
return $value . ' <span style="color: orange;">⏳ Verifying...</span>';
}
if ($verification['is_disposable']) {
return $value . ' <span style="color: red; font-weight: bold;">⚠️ DISPOSABLE</span>';
}
if (!$verification['has_mx_record']) {
return $value . ' <span style="color: red;">❌ Invalid</span>';
}
if ($verification['is_deliverable']) {
return $value . ' <span style="color: green;">✓ Verified</span>';
}
return $value;
}

Troubleshooting Common Issues

Issue 1: “checkboxHQ API Error: HTTP 401”

Causes:

  • API key incorrect or not set in wp-config.php
  • Using wrong header format
  • API key revoked or expired

Solutions:

  1. Verify API key in wp-config.php:
define('CHECKBOXHQ_API_KEY', 'cbx_actual_key_here');
  1. Test API directly with curl:
Terminal window
curl -X POST https://api.checkboxhq.com/api/v1/verify_disposable/ \
-H "x-api-key: cbx_your_key" \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]"}'
  1. Log into checkboxhq.com and verify API key is still active
  2. Regenerate API key if needed: Dashboard → API Keys → Regenerate

Issue 2: HubSpot Contact Not Created

Causes:

  • HubSpot Add-On not authenticated
  • Email field not mapped
  • Conditional logic blocking sync

Solutions:

  1. Go to Forms → Settings → HubSpot and re-authenticate
  2. Check field mappings in HubSpot feed configuration
  3. Disable conditional logic temporarily to test
  4. Check HubSpot API limits (10,000 requests/day on free tier)

Issue 3: Custom Properties Not Appearing in HubSpot

Causes:

  • Properties not created in HubSpot
  • Internal name mismatch
  • Add-On needs update

Solutions:

  1. Verify property internal names match exactly:
    • email_verification_status
    • email_deliverable
    • email_verified_date
  2. Check if properties are visible to API: Settings → Properties → [Property] → Field type
  3. Update Gravity Forms HubSpot Add-On to latest version

Issue 4: Verification Data Not Appearing in Entry

Causes:

  • WP-Cron not running
  • PHP execution timeout
  • Large backlog of entries to process

Solutions:

  1. Check if WP-Cron is running:
// Add to functions.php temporarily
add_action('init', function() {
error_log('Next checkboxhq_process_batch: ' . wp_next_scheduled('checkboxhq_process_batch'));
});
  1. Manually trigger verification:
// In WordPress admin, go to Tools → WP-Cron
// Or trigger manually in functions.php:
do_action('checkboxhq_process_batch');
  1. Increase PHP max_execution_time:
// In wp-config.php:
set_time_limit(300); // 5 minutes
  1. Process verification queue manually in WordPress admin

Issue 5: High Credit Usage

Causes:

  • Verifying all 3 endpoints for every email (4 credits each)
  • Bot submissions inflating verification count
  • Testing forms repeatedly

Solutions:

  1. Use lightweight verification (DNS only - 2 credits):
// See Advanced Configurations → Option 1
  1. Implement caching to avoid re-verifying same emails:
// See Advanced Configurations → Option 3
  1. Add reCAPTCHA to forms to block bots:
// Install Gravity Forms reCAPTCHA add-on
  1. Monitor credit usage:
// Check your dashboard at checkboxhq.com/billing
  1. Only verify priority forms (see Advanced Configurations → Option 2)

Security Best Practices

1. Protect Your API Key

DO:

  • Store in wp-config.php (not in database or theme files)
  • Use environment variables on staging/production
  • Rotate keys quarterly
  • Restrict key to specific domains in checkboxHQ dashboard

DON’T:

  • Hardcode in theme files
  • Commit to Git repositories
  • Share in support tickets
  • Use same key across multiple sites

2. Implement Rate Limiting

Prevent abuse by limiting verification requests:

/**
* Rate limit verification requests (max 100/hour per IP)
*/
function checkboxhq_check_rate_limit() {
$ip = $_SERVER['REMOTE_ADDR'];
$cache_key = 'checkboxhq_rate_' . md5($ip);
$requests = get_transient($cache_key) ?: 0;
if ($requests >= 100) {
return false; // Rate limit exceeded
}
set_transient($cache_key, $requests + 1, 3600); // 1 hour
return true;
}
// Add to checkboxhq_verify_email function:
if (!checkboxhq_check_rate_limit()) {
return [
'valid' => false,
'reason' => 'rate_limit',
'message' => 'Too many verification attempts. Please try again later.'
];
}

3. Sanitize User Input

Always sanitize email input before API calls:

$email = sanitize_email($email_value);
$email = strtolower(trim($email));

4. Handle PII Compliantly

For GDPR/CCPA compliance:

  • Add privacy notice to form: “We verify email addresses to prevent spam”
  • Don’t log full email addresses in production
  • Delete verification metadata after 30 days
  • Provide data deletion on user request
/**
* Auto-delete verification data after 30 days
*/
add_action('gform_delete_entry', 'checkboxhq_cleanup_verification_data');
function checkboxhq_cleanup_verification_data($entry_id) {
global $wpdb;
$wpdb->delete(
$wpdb->prefix . 'gf_entry_meta',
['entry_id' => $entry_id, 'meta_key' => 'checkboxhq_verification_%'],
['%d', '%s']
);
}

Performance Optimization

1. Cache Verification Results

Avoid re-verifying the same email:

/**
* Cache verification results for 24 hours
*/
function checkboxhq_verify_email_cached($email) {
$cache_key = 'checkboxhq_verify_' . md5(strtolower($email));
$cached = get_transient($cache_key);
if ($cached !== false) {
return $cached;
}
$result = checkboxhq_verify_email($email);
set_transient($cache_key, $result, DAY_IN_SECONDS);
return $result;
}

2. Async API Calls with Action Scheduler

For background processing (requires Action Scheduler plugin):

/**
* Queue verification for background processing
*/
add_action('gform_after_submission', 'checkboxhq_queue_verification', 10, 2);
function checkboxhq_queue_verification($entry, $form) {
as_enqueue_async_action('checkboxhq_process_verification', [
'entry_id' => $entry['id'],
'form_id' => $form['id']
]);
}
add_action('checkboxhq_process_verification', 'checkboxhq_background_verify', 10, 2);
function checkboxhq_background_verify($entry_id, $form_id) {
$entry = GFAPI::get_entry($entry_id);
$form = GFAPI::get_form($form_id);
// Verify email and update HubSpot
// (code similar to synchronous version)
}

3. Optimize HubSpot API Calls

Batch updates to reduce API usage:

/**
* Batch HubSpot contact updates (run hourly)
*/
add_action('checkboxhq_batch_hubspot_sync', 'checkboxhq_sync_verified_contacts');
function checkboxhq_sync_verified_contacts() {
// Get all entries from last hour with verified emails
// Update HubSpot in batches of 100
// (implementation requires HubSpot PHP SDK)
}

Monitoring and Analytics

Key Metrics to Track

In WordPress:

  • Total form submissions
  • Verification success rate
  • Blocked disposable emails
  • Blocked invalid emails
  • API response times

In HubSpot:

  • Contacts with email_verification_status = valid
  • Lead quality (bounce rate, engagement)
  • Sales velocity for verified vs unverified leads

Create a WordPress Dashboard Widget

/**
* Add checkboxHQ stats to WordPress dashboard
*/
add_action('wp_dashboard_setup', 'checkboxhq_add_dashboard_widget');
function checkboxhq_add_dashboard_widget() {
wp_add_dashboard_widget(
'checkboxhq_stats',
'checkboxHQ Email Verification Stats',
'checkboxhq_dashboard_widget_display'
);
}
function checkboxhq_dashboard_widget_display() {
global $wpdb;
// Query last 30 days of form submissions
$stats = $wpdb->get_results("
SELECT
COUNT(*) as total,
SUM(CASE WHEN meta_value LIKE '%valid\":true%' THEN 1 ELSE 0 END) as verified,
SUM(CASE WHEN meta_value LIKE '%disposable\":true%' THEN 1 ELSE 0 END) as disposable
FROM {$wpdb->prefix}gf_entry_meta
WHERE meta_key LIKE 'checkboxhq_verification_%'
AND entry_id IN (
SELECT id FROM {$wpdb->prefix}gf_entry
WHERE date_created >= DATE_SUB(NOW(), INTERVAL 30 DAY)
)
");
echo '<p><strong>Last 30 Days:</strong></p>';
echo '<ul>';
echo '<li>Total Verified: ' . $stats[0]->verified . '</li>';
echo '<li>Blocked Disposable: ' . $stats[0]->disposable . '</li>';
echo '<li>Success Rate: ' . round(($stats[0]->verified / $stats[0]->total) * 100, 1) . '%</li>';
echo '</ul>';
}

Cost Analysis & ROI

checkboxHQ Pricing

  • Free Tier: 100 credits/month
  • Starter: $19/month for 50,000 credits (~12,500 full verifications)
  • Growth: $39/month for 200,000 credits (~50,000 full verifications)
  • Scale: $59/month for 500,000 credits (~125,000 full verifications)

Credit Usage:

  • Full verification (disposable + DNS + public provider): 4 credits
  • Lightweight (DNS only): 2 credits
  • With caching enabled: Reduces usage by 30-50% for repeat submissions

HubSpot Cost Savings

Marketing contacts pricing (Marketing Hub):

  • 1,000 contacts = $45/month
  • 10,000 contacts = $800/month

ROI Example:

  • Current: 1,000 form submissions/month
  • 25% are fake/invalid (250 contacts)
  • HubSpot cost for fake contacts: $11.25/month (at $45/1000)
  • Plus: Sales time wasted on fake leads = ~$500/month (10 hours @ $50/hr)
  • Total waste: $511.25/month

With checkboxHQ:

  • Cost: $19/month (Starter plan for up to 12,500 verifications)
  • Blocks/flags 250 fake contacts
  • Saves sales team 10 hours/month
  • Net savings: $491.25/month
  • Annual savings: $5,895
  • ROI: 2,456%

Additional Benefits:

  • Improved email deliverability (fewer bounces)
  • Better lead scoring accuracy
  • Reduced CRM clutter
  • Enhanced marketing attribution
  • Higher sales team morale (less wasted time)

Migration Guide: Moving from Other Validators

From ZeroBounce

Replace ZeroBounce API calls:

// OLD: ZeroBounce
$response = wp_remote_get("https://api.zerobounce.net/v2/validate?api_key={$key}&email={$email}");
// NEW: checkboxHQ
$response = wp_remote_post('https://api.checkboxhq.com/v1/verify', [
'headers' => ['Authorization' => 'Bearer ' . $api_key],
'body' => json_encode(['email' => $email])
]);

From NeverBounce

Mapping response fields:

// NeverBounce response format
$result = $data['result']; // 'valid', 'invalid', 'disposable', 'catchall', 'unknown'
// checkboxHQ equivalent
$is_valid = $data['deliverable'] === true;
$is_disposable = $data['disposable'] === true;

Next Steps

1. Scale Your Integration

Once your basic setup is working:

  • Add verification to other Gravity Forms on your site
  • Implement verification on WordPress comment forms
  • Add verification to WooCommerce checkout
  • Integrate with other CRMs (Salesforce, Pipedrive)

2. Improve Lead Quality Further

Combine email verification with:

  • Phone number validation (checkboxHQ phone API)
  • Company domain verification (block free emails like Gmail)
  • Geolocation checks (flag mismatched countries)
  • Behavioral scoring (time on page before submission)

3. Automate Lead Enrichment

Use verified emails to trigger:

  • Clearbit enrichment (add company data)
  • LinkedIn Sales Navigator lookup
  • Predictive lead scoring models
  • Personalized email sequences

Additional Resources

Documentation

Support

Code Examples


Conclusion

You now have a production-grade, non-blocking email verification system that:

  • Maintains 100% conversion rates - Forms submit instantly
  • Verifies in background - Zero user friction
  • Enriches HubSpot CRM with 7 custom properties
  • Improves lead quality by identifying disposable/invalid emails
  • Reduces sales waste - Team focuses on real prospects
  • Enhances lead scoring - Verified business emails get priority
  • Protects sender reputation - Fewer bounces from bad emails
  • Provides actionable data - Segment by email quality

The Non-Blocking Advantage:

Unlike blocking verification (which can lose legitimate leads), this approach:

  • Never rejects a user during submission
  • Allows you to review flagged leads manually
  • Maintains conversion rates while cleaning your database
  • Gives sales context to prioritize outreach

What’s next?

  1. Test your integration with various email types
  2. Monitor verification stats in Gravity Forms entries
  3. Review HubSpot workflows to route leads by email quality
  4. Track ROI - measure time saved and HubSpot cost reduction
  5. Consider upgrading checkboxHQ plan as traffic grows
  6. Explore advanced features like batch verification and webhooks

Pro Tips:

  • Review “Needs Manual Review” list in HubSpot weekly
  • Train sales team to check verification status before outreach
  • Use verification data in reporting to track lead source quality
  • Set up alerts for sudden spikes in disposable email submissions (indicates bot attack)
  • Re-verify old contacts quarterly to maintain database hygiene

Frequently Asked Questions

Q: Will this slow down my form submissions?
A: No! Forms submit instantly. Verification happens in the background after the user sees the confirmation page. Zero user friction.

Q: What happens if the checkboxHQ API is down?
A: Forms continue to work normally. Verification simply won’t happen for those submissions. You can manually verify them later or re-trigger verification when the API is back up.

Q: Do I need to verify every email field on every form?
A: No. You can selectively verify only high-priority forms (see Advanced Configurations → Option 2) to save credits.

Q: How many API credits does each verification use?
A: Full verification uses 4 credits (1 for disposable check + 2 for DNS + 1 for public provider). You can use DNS-only mode for 2 credits per verification.

Q: Does this work with Gravity Forms Webhooks add-on?
A: Yes! Verification completes before webhooks fire, so verification data is included in webhook payloads.

Q: Can I customize which emails get flagged?
A: Absolutely. You control the logic - flag disposable, public providers, missing MX records, or any combination. See the verification function for customization points.

Q: Is this GDPR compliant?
A: Yes. Email verification is legitimate interest for fraud prevention. Add privacy notice: “We verify email addresses to prevent spam and ensure service quality.”

Q: Can I use this with multiple forms on my site?
A: Yes! The code automatically applies to ALL Gravity Forms with email fields. Use selective verification (Option 2) to target specific forms.

Q: What about testing in a staging environment?
A: Use a separate checkboxHQ API key for staging to keep production analytics clean. checkboxHQ offers unlimited test API keys.

Q: How do I handle contacts that were created before I added verification?
A: Create a HubSpot workflow to tag unverified contacts, then either: (a) export and bulk verify, or (b) use the re-verification workflow (Step 6.4) to verify them gradually.

Q: What’s the difference between disposable and public provider checks?
A: Disposable = temporary services like Mailinator, Guerrilla Mail (usually spam). Public provider = Gmail, Yahoo, Outlook (legitimate but consumer emails, not business). Both are valid but signal different lead quality.

Q: Can verification happen faster than 5-10 seconds?
A: Yes! The default code runs on form submission (instant). The 5-10 second timeframe accounts for API latency. Typically, verification happens in less than 1 second.


Need help? Email [email protected] for personalized assistance.