7 min read

Custom Fields & Data Mapping

Map form fields to grader inputs and define custom data transformations.

Overview

Custom field mapping allows you to connect any form field to your grader's evaluation criteria. Transform, validate, and enrich data as it flows from forms into your lead scoring system.

Field Mapping Basics

Standard Field Mappings

{
  "formField": "email_address",
  "graderField": "email",
  "required": true,
  "validation": "email"
}

Custom Field Definitions

{
  "customFields": [
    {
      "name": "budget_range", 
      "type": "select",
      "options": ["<10k", "10k-50k", "50k-100k", "100k+"],
      "scoring": {
        "<10k": 5,
        "10k-50k": 15,
        "50k-100k": 25, 
        "100k+": 35
      }
    },
    {
      "name": "timeline",
      "type": "text", 
      "transform": "extract_urgency_keywords",
      "scoring": "dynamic"
    }
  ]
}

Data Transformations

Text Processing

// Clean and standardize company names
function cleanCompanyName(input) {
  return input
    .replace(/\b(inc|llc|corp|ltd)\b/gi, '')
    .trim()
    .toLowerCase();
}

// Extract job seniority level
function extractSeniority(jobTitle) {
  const senior = ['vp', 'director', 'chief', 'head', 'senior'];
  const mid = ['manager', 'lead', 'supervisor'];
  
  if (senior.some(s => jobTitle.toLowerCase().includes(s))) {
    return 'senior';
  } else if (mid.some(m => jobTitle.toLowerCase().includes(m))) {
    return 'mid';
  }
  return 'junior';
}

Numeric Transformations

// Convert employee count ranges to numbers
const employeeMapping = {
  '1-10': 5,
  '11-50': 30,
  '51-100': 75,
  '101-500': 300,
  '500+': 1000
};

// Revenue bucketing
function bucketRevenue(revenue) {
  if (revenue < 1000000) return 'startup';
  if (revenue < 10000000) return 'growth';  
  if (revenue < 100000000) return 'midmarket';
  return 'enterprise';
}

Advanced Mapping Patterns

Conditional Mapping

{
  "field": "industry",
  "mapping": {
    "condition": "if company_size > 100",
    "then": "enterprise_industry_scoring",
    "else": "smb_industry_scoring"
  }
}

Multi-Field Derivation

// Derive lead quality from multiple fields
function deriveLeadQuality(formData) {
  let quality = 0;
  
  // Company indicators
  if (formData.website && !formData.website.includes('gmail')) {
    quality += 10;
  }
  
  // Contact completeness
  const completeness = Object.values(formData).filter(v => v).length / Object.keys(formData).length;
  quality += Math.floor(completeness * 20);
  
  return quality;
}

Validation Rules

Required Field Validation

{
  "validation": {
    "email": {"required": true, "format": "email"},
    "company": {"required": true, "min_length": 2},
    "budget": {"required": false, "type": "number", "min": 0}
  }
}

Custom Validation Functions

// Validate business email domains
function validateBusinessEmail(email) {
  const personalDomains = ['gmail.com', 'yahoo.com', 'hotmail.com'];
  const domain = email.split('@')[1];
  return !personalDomains.includes(domain);
}

// Phone number standardization
function standardizePhone(phone) {
  return phone.replace(/\D/g, '').replace(/^1/, '');
}

Data Enrichment

External API Integration

// Enrich company data via API
async function enrichCompanyData(companyName) {
  const response = await fetch(`https://api.clearbit.com/v1/companies/find?name=${companyName}`);
  const data = await response.json();
  
  return {
    industry: data.category?.industry,
    employees: data.metrics?.employees,
    revenue: data.metrics?.revenue,
    technology: data.tech?.stack
  };
}

Geographic Data Enhancement

// Add timezone and region data
function enhanceLocationData(formData) {
  if (formData.zipCode) {
    return {
      ...formData,
      timezone: getTimezoneByZip(formData.zipCode),
      salesTerritory: getTerritoryByZip(formData.zipCode),
      demographicSegment: getDemographicData(formData.zipCode)
    };
  }
  return formData;
}

Configuration Examples

HubSpot Form Mapping

{
  "source": "hubspot",
  "mappings": {
    "email": "email",
    "firstname": "firstName", 
    "lastname": "lastName",
    "company": "company",
    "jobtitle": "jobTitle",
    "phone": "phone",
    "website": "website",
    "hs_lead_status": "customField1",
    "budget_range": "customField2"
  },
  "transforms": {
    "company": "clean_company_name",
    "phone": "standardize_phone_number",
    "jobtitle": "extract_seniority_level"
  }
}

Generic Webhook Mapping

{
  "source": "webhook",  
  "flexibleMapping": true,
  "mappings": {
    "email_field": "email",
    "company_field": "company",
    "custom_budget": {
      "target": "customField1",
      "transform": "budget_to_numeric",
      "validation": "positive_number"
    }
  }
}

Testing & Validation

Field Mapping Tests

// Test field transformations
describe('Field Mappings', () => {
  test('company name cleaning', () => {
    expect(cleanCompanyName('Acme Corp LLC')).toBe('acme');
    expect(cleanCompanyName('BETA INC.')).toBe('beta');
  });
  
  test('job title seniority', () => {
    expect(extractSeniority('VP of Marketing')).toBe('senior');
    expect(extractSeniority('Marketing Manager')).toBe('mid'); 
    expect(extractSeniority('Marketing Intern')).toBe('junior');
  });
});

Best Practices

Mapping Strategy

  1. Start simple - Map core fields first (email, company, name)
  2. Add complexity gradually - Introduce transformations and validations iteratively
  3. Test thoroughly - Validate mappings with real form data
  4. Document transforms - Keep clear records of custom logic

Data Quality

  • Standardize inputs - Clean and normalize data consistently
  • Validate early - Catch data issues at ingestion time
  • Enrich selectively - Only add external data that improves scoring
  • Monitor quality - Track data completeness and accuracy metrics

Performance Considerations

  • Cache lookups - Store frequently accessed mapping rules
  • Batch enrichment - Process external API calls in groups
  • Async processing - Don't block form submission for complex transforms
  • Error handling - Gracefully handle missing or invalid data

Next Steps

After configuring field mapping: