Complete Phone Number Validation: International Formats and Standards
Master international phone number validation with comprehensive coverage of global formats, standards, and validation techniques.
Table of Contents
Table of Contents
Complete Phone Number Validation: International Formats and Standards
Phone Validation Process
Phone number validation is essential for global applications, requiring deep understanding of international formats, regional variations, and carrier-specific requirements. Proper validation ensures reliable communication while respecting local conventions.
International Phone Standards
Phone number validation relies on established international standards and regional implementations.
E.164 Standard Format
The E.164 standard defines the international public telecommunication numbering plan:
- Maximum 15 digits including country code
- No spaces, hyphens, or other formatting
- Always begins with country code
- Example: +1234567890123
ITU-T Recommendations
Country Code Assignment
- ITU-T E.164 assigns country codes
- 1-3 digit country codes
- Geographic and non-geographic codes
- Special service codes
Number Plan Structure
- Country code + National destination code + Subscriber number
- Variable length based on country
- Reserved ranges for special services
- Mobile vs. fixed-line distinctions
Regional Numbering Plans
North American Numbering Plan (NANP)
- Countries: US, Canada, Caribbean nations
- Format: +1 NXX NXX XXXX
- Area codes and exchange codes
- Overlay and split planning
European Numbering Plans
- Variable country code lengths (2-3 digits)
- Different national number formats
- Mobile number prefixes vary by country
- International dialing conventions
International Phone Formats
Advanced Validation Techniques
Modern phone validation requires sophisticated techniques beyond basic format checking.
Carrier Intelligence
Mobile Network Code (MNC) Analysis
- Identify specific mobile carriers
- Determine network capabilities
- Assess number portability status
- Validate against carrier databases
Number Type Classification
- Mobile vs. fixed-line identification
- VoIP and virtual number detection
- Premium rate number identification
- Toll-free number recognition
// Advanced phone number validation with libphonenumber
import { PhoneNumberUtil, PhoneNumberType, PhoneNumberFormat } from 'google-libphonenumber'
interface PhoneValidationResult {
isValid: boolean
isMobile: boolean
isFixedLine: boolean
countryCode: string
nationalNumber: string
formattedNumber: string
type: string
carrier?: string
errors: string[]
warnings: string[]
}
class PhoneValidator {
private phoneUtil: PhoneNumberUtil
constructor() {
this.phoneUtil = PhoneNumberUtil.getInstance()
}
async validatePhoneNumber(phoneNumber: string, defaultRegion?: string): Promise<PhoneValidationResult> {
const result: PhoneValidationResult = {
isValid: false,
isMobile: false,
isFixedLine: false,
countryCode: '',
nationalNumber: '',
formattedNumber: '',
type: '',
errors: [],
warnings: []
}
try {
// Parse the phone number
const number = this.phoneUtil.parseAndKeepRawInput(phoneNumber, defaultRegion || 'US')
// Check if the number is valid
if (!this.phoneUtil.isValidNumber(number)) {
result.errors.push('Invalid phone number format')
return result
}
result.isValid = true
// Get country code
result.countryCode = this.phoneUtil.getRegionCodeForNumber(number)
// Get national number
result.nationalNumber = this.phoneUtil.getNationalSignificantNumber(number)
// Format the number in E.164
result.formattedNumber = this.phoneUtil.format(number, PhoneNumberFormat.E164)
// Determine number type
const numberType = this.phoneUtil.getNumberType(number)
result.type = this.getNumberTypeString(numberType)
// Check if mobile or fixed line
result.isMobile = numberType === PhoneNumberType.MOBILE
result.isFixedLine = numberType === PhoneNumberType.FIXED_LINE
// Get carrier information if available
try {
const carrier = await this.getCarrierInfo(number)
result.carrier = carrier
} catch (error) {
result.warnings.push('Carrier information unavailable')
}
// Validate against regional constraints
const regionValidation = this.validateRegionalConstraints(number, result.countryCode)
if (!regionValidation.isValid) {
result.warnings.push(...regionValidation.warnings)
}
} catch (error) {
result.errors.push(`Phone validation failed: ${error.message}`)
}
return result
}
private getNumberTypeString(type: PhoneNumberType): string {
switch (type) {
case PhoneNumberType.MOBILE: return 'mobile'
case PhoneNumberType.FIXED_LINE: return 'fixed_line'
case PhoneNumberType.TOLL_FREE: return 'toll_free'
case PhoneNumberType.PREMIUM_RATE: return 'premium_rate'
case PhoneNumberType.VOIP: return 'voip'
case PhoneNumberType.UAN: return 'uan'
case PhoneNumberType.PAGER: return 'pager'
case PhoneNumberType.VOICEMAIL: return 'voicemail'
default: return 'unknown'
}
}
private async getCarrierInfo(number: any): Promise<string | undefined> {
// In production, integrate with carrier lookup APIs
// For demo purposes, return mock data
return 'Verizon Wireless'
}
private validateRegionalConstraints(number: any, countryCode: string): {
isValid: boolean
warnings: string[]
} {
const warnings: string[] = []
// Example: US numbers should have 10 digits after country code
if (countryCode === 'US') {
const nationalNumber = this.phoneUtil.getNationalSignificantNumber(number)
if (nationalNumber.length !== 10) {
warnings.push('US phone numbers should have 10 digits')
}
}
// Example: Indian mobile numbers should start with 6,7,8,9
if (countryCode === 'IN') {
const nationalNumber = this.phoneUtil.getNationalSignificantNumber(number)
if (nationalNumber.length === 10) {
const firstDigit = nationalNumber[0]
if (!['6', '7', '8', '9'].includes(firstDigit)) {
warnings.push('Indian mobile numbers should start with 6, 7, 8, or 9')
}
}
}
return { isValid: warnings.length === 0, warnings }
}
}
// Usage example
const validator = new PhoneValidator()
const result = await validator.validatePhoneNumber('+1 (555) 123-4567')
console.log(result)
/*
{
isValid: true,
isMobile: true,
isFixedLine: false,
countryCode: 'US',
nationalNumber: '5551234567',
formattedNumber: '+15551234567',
type: 'mobile',
carrier: 'Verizon Wireless',
errors: [],
warnings: []
}
*/Real-Time Validation
HLR (Home Location Register) Lookups
- Query carrier databases directly
- Verify number assignment status
- Check roaming and availability
- Assess delivery capabilities
// HLR lookup service for real-time validation
interface HLRResult {
isActive: boolean
isRoaming: boolean
isPorted: boolean
carrier: string
country: string
mccmnc: string // Mobile Country Code + Mobile Network Code
originalCarrier?: string
error?: string
}
class HLRValidator {
private hlrApiKey: string
constructor(apiKey: string) {
this.hlrApiKey = apiKey
}
async lookupPhoneNumber(phoneNumber: string): Promise<HLRResult> {
try {
// Normalize phone number to E.164
const normalizedNumber = this.normalizeToE164(phoneNumber)
// Call HLR API (example with mock response)
const hlrResponse = await this.callHLRAPI(normalizedNumber)
return {
isActive: hlrResponse.status === 'active',
isRoaming: hlrResponse.roaming || false,
isPorted: hlrResponse.ported || false,
carrier: hlrResponse.current_carrier,
country: hlrResponse.country,
mccmnc: hlrResponse.mccmnc,
originalCarrier: hlrResponse.original_carrier
}
} catch (error) {
return {
isActive: false,
isRoaming: false,
isPorted: false,
carrier: '',
country: '',
mccmnc: '',
error: error.message
}
}
}
private normalizeToE164(phoneNumber: string): string {
// Remove all non-digit characters except +
const cleaned = phoneNumber.replace(/[^d+]/g, '')
// If it doesn't start with +, assume it's a national number
if (!cleaned.startsWith('+')) {
// Add default country code (US in this example)
return '+1' + cleaned
}
return cleaned
}
private async callHLRAPI(phoneNumber: string): Promise<any> {
// In production, make actual API call to HLR provider
// Example response structure
return {
status: 'active',
roaming: false,
ported: false,
current_carrier: 'Verizon Wireless',
original_carrier: 'Verizon Wireless',
country: 'US',
mccmnc: '310004'
}
}
}
// Usage in validation pipeline
async function comprehensivePhoneValidation(phoneNumber: string): Promise<{
isValid: boolean
basicValidation: PhoneValidationResult
hlrValidation?: HLRResult
riskScore: number
}> {
const validator = new PhoneValidator()
const hlrValidator = new HLRValidator(process.env.HLR_API_KEY!)
// Basic validation
const basicValidation = await validator.validatePhoneNumber(phoneNumber)
if (!basicValidation.isValid) {
return {
isValid: false,
basicValidation,
riskScore: 100 // High risk for invalid numbers
}
}
// HLR validation for mobile numbers
let hlrValidation: HLRResult | undefined
if (basicValidation.isMobile) {
hlrValidation = await hlrValidator.lookupPhoneNumber(basicValidation.formattedNumber)
}
// Calculate risk score
let riskScore = 0
// Invalid HLR status increases risk
if (hlrValidation && !hlrValidation.isActive) {
riskScore += 50
}
// Roaming might indicate higher risk
if (hlrValidation?.isRoaming) {
riskScore += 20
}
// Ported numbers might be legitimate but warrant attention
if (hlrValidation?.isPorted) {
riskScore += 10
}
return {
isValid: basicValidation.isValid && (!hlrValidation || hlrValidation.isActive),
basicValidation,
hlrValidation,
riskScore: Math.min(100, riskScore)
}
}
// Example usage
const result = await comprehensivePhoneValidation('+1 555-123-4567')
console.log('Validation result:', result)Geographic Validation
Location Consistency
- Cross-reference with IP geolocation
- Validate against user-provided location
- Check for impossible geographic combinations
- Assess travel patterns and timing
Time Zone Analysis
- Validate against expected time zones
- Check for consistent usage patterns
- Assess communication timing
- Identify potential fraud indicators
// Geographic validation with phone number location intelligence
interface GeoValidationResult {
isConsistent: boolean
phoneLocation: {
country: string
region: string
city?: string
timezone: string
coordinates?: { lat: number; lon: number }
}
ipLocation?: {
country: string
region: string
city?: string
}
riskFactors: string[]
confidence: number // 0-100
}
class PhoneGeoValidator {
async validateGeographicConsistency(phoneNumber: string, userIP?: string): Promise<GeoValidationResult> {
const result: GeoValidationResult = {
isConsistent: true,
phoneLocation: {
country: '',
region: '',
timezone: ''
},
riskFactors: [],
confidence: 100
}
try {
// Get phone number location
const phoneLocation = await this.getPhoneLocation(phoneNumber)
result.phoneLocation = phoneLocation
// If IP is provided, cross-reference with IP location
if (userIP) {
const ipLocation = await this.getIPLocation(userIP)
result.ipLocation = ipLocation
// Check for geographic consistency
const consistency = this.checkGeographicConsistency(phoneLocation, ipLocation)
result.isConsistent = consistency.isConsistent
result.riskFactors = consistency.riskFactors
result.confidence = consistency.confidence
}
// Check time zone consistency
const timezoneValidation = await this.validateTimeZone(phoneLocation.timezone)
if (!timezoneValidation.isValid) {
result.riskFactors.push('Inconsistent timezone usage')
result.confidence -= 20
}
} catch (error) {
result.riskFactors.push('Geographic validation failed')
result.confidence = 0
}
return result
}
private async getPhoneLocation(phoneNumber: string): Promise<GeoValidationResult['phoneLocation']> {
// Extract country code from phone number
const countryCode = this.extractCountryCode(phoneNumber)
// In production, use carrier data and location APIs
const locationData: Record<string, any> = {
'1': { country: 'US', region: 'North America', timezone: 'America/New_York' },
'44': { country: 'GB', region: 'Europe', timezone: 'Europe/London' },
'86': { country: 'CN', region: 'Asia', timezone: 'Asia/Shanghai' },
'91': { country: 'IN', region: 'Asia', timezone: 'Asia/Kolkata' }
}
return locationData[countryCode] || {
country: 'Unknown',
region: 'Unknown',
timezone: 'UTC'
}
}
private async getIPLocation(ip: string): Promise<GeoValidationResult['ipLocation']> {
// In production, use IP geolocation service
return {
country: 'US',
region: 'California',
city: 'San Francisco'
}
}
private extractCountryCode(phoneNumber: string): string {
// Extract country code from international format
const cleaned = phoneNumber.replace(/[^d+]/g, '')
if (cleaned.startsWith('+')) {
// Find the country code (1-4 digits after +)
const match = cleaned.match(/+(d{1,4})/)
return match ? match[1] : ''
}
return ''
}
private checkGeographicConsistency(
phoneLocation: GeoValidationResult['phoneLocation'],
ipLocation: GeoValidationResult['ipLocation']
): { isConsistent: boolean; riskFactors: string[]; confidence: number } {
const riskFactors: string[] = []
let confidence = 100
// Same country check
if (phoneLocation.country !== ipLocation.country) {
riskFactors.push('Phone and IP locations in different countries')
confidence -= 40
}
// Same region check (if available)
if (phoneLocation.region && ipLocation.region &&
phoneLocation.region !== ipLocation.region) {
riskFactors.push('Phone and IP locations in different regions')
confidence -= 20
}
return {
isConsistent: riskFactors.length === 0,
riskFactors,
confidence: Math.max(0, confidence)
}
}
private async validateTimeZone(timezone: string): Promise<{ isValid: boolean; reason?: string }> {
// Check if current time makes sense for the timezone
const now = new Date()
const userTimezone = Intl.DateTimeFormat('en-US', {
timeZone: timezone,
timeZoneName: 'short'
}).formatToParts(now)
// Basic validation - in production, check for reasonable usage patterns
return { isValid: true }
}
}
// Usage example
const geoValidator = new PhoneGeoValidator()
const geoResult = await geoValidator.validateGeographicConsistency(
'+1 555-123-4567',
'192.168.1.1'
)
console.log('Geographic validation:', geoResult)
/*
{
isConsistent: true,
phoneLocation: { country: 'US', region: 'North America', timezone: 'America/New_York' },
ipLocation: { country: 'US', region: 'California', city: 'San Francisco' },
riskFactors: [],
confidence: 100
}
*/SMS Delivery Testing
- Test message delivery capability
- Verify number reachability
- Assess delivery timing
- Monitor delivery status
// SMS delivery testing service
interface SMSTestResult {
canReceiveSMS: boolean
deliveryTime: number // milliseconds
carrier: string
error?: string
suggestions?: string[]
}
class SMSTester {
private smsApiKey: string
constructor(apiKey: string) {
this.smsApiKey = apiKey
}
async testSMSDelivery(phoneNumber: string): Promise<SMSTestResult> {
const startTime = Date.now()
try {
// Send test SMS (ping)
const pingResult = await this.sendTestSMS(phoneNumber)
// Wait for delivery confirmation (typically 5-30 seconds)
await this.waitForDeliveryConfirmation(phoneNumber)
const deliveryTime = Date.now() - startTime
return {
canReceiveSMS: pingResult.delivered,
deliveryTime,
carrier: pingResult.carrier,
suggestions: pingResult.suggestions
}
} catch (error) {
return {
canReceiveSMS: false,
deliveryTime: Date.now() - startTime,
carrier: '',
error: error.message
}
}
}
private async sendTestSMS(phoneNumber: string): Promise<any> {
// In production, integrate with SMS testing service
// Mock response for demo
return {
delivered: true,
carrier: 'Verizon Wireless',
messageId: 'msg_12345'
}
}
private async waitForDeliveryConfirmation(phoneNumber: string): Promise<void> {
// In production, set up webhook or polling for delivery status
// For demo, simulate delay
await new Promise(resolve => setTimeout(resolve, 1000))
}
async batchTestSMS(numbers: string[]): Promise<SMSTestResult[]> {
const results: SMSTestResult[] = []
// Process in batches to avoid rate limits
const batchSize = 10
for (let i = 0; i < numbers.length; i += batchSize) {
const batch = numbers.slice(i, i + batchSize)
const batchResults = await Promise.allSettled(
batch.map(number => this.testSMSDelivery(number))
)
// Extract successful results
batchResults.forEach((result, index) => {
if (result.status === 'fulfilled') {
results.push(result.value)
} else {
results.push({
canReceiveSMS: false,
deliveryTime: 0,
carrier: '',
error: result.reason?.message || 'Test failed'
})
}
})
// Small delay between batches
if (i + batchSize < numbers.length) {
await new Promise(resolve => setTimeout(resolve, 1000))
}
}
return results
}
}
// Integration with validation pipeline
async function validatePhoneWithSMS(phoneNumber: string): Promise<{
isValid: boolean
smsTest?: SMSTestResult
overallRisk: number
}> {
const smsTester = new SMSTester(process.env.SMS_TEST_API_KEY!)
try {
// First do basic validation
const basicValidation = await comprehensivePhoneValidation(phoneNumber)
if (!basicValidation.isValid) {
return {
isValid: false,
overallRisk: 100
}
}
// If it's a mobile number, test SMS capability
if (basicValidation.basicValidation.isMobile) {
const smsTest = await smsTester.testSMSDelivery(phoneNumber)
// Calculate overall risk
let smsRisk = 0
if (!smsTest.canReceiveSMS) {
smsRisk += 60
}
if (smsTest.deliveryTime > 10000) { // > 10 seconds
smsRisk += 20
}
return {
isValid: basicValidation.isValid && smsTest.canReceiveSMS,
smsTest,
overallRisk: Math.min(100, basicValidation.riskScore + smsRisk)
}
}
return {
isValid: basicValidation.isValid,
overallRisk: basicValidation.riskScore
}
} catch (error) {
return {
isValid: false,
overallRisk: 100
}
}
}
// Usage example
const smsValidation = await validatePhoneWithSMS('+1 555-123-4567')
console.log('SMS validation result:', smsValidation)Phone Validation Techniques
Regional Considerations
Different regions have unique phone number characteristics and validation requirements.
Asia-Pacific Region
China (+86)
- 11-digit mobile numbers
- Carrier-specific prefixes
- Government regulations on validation
- WeChat integration considerations
India (+91)
- 10-digit mobile numbers after country code
- Multiple carrier networks
- Number portability complexities
- Regional language considerations
Japan (+81)
- Complex numbering plan structure
- Mobile number prefixes 070, 080, 090
- Carrier-specific services
- Cultural communication preferences
European Union
GDPR Compliance
- Privacy requirements for validation
- Consent mechanisms for processing
- Data retention limitations
- Cross-border data transfer rules
Country-Specific Formats
- Germany: Variable length numbers
- France: Geographic area codes
- UK: Complex numbering plan
- Italy: Mobile prefix variations
Americas
United States (+1)
- NANP format consistency
- Area code overlays and splits
- Carrier number portability
- Do Not Call registry compliance
Brazil (+55)
- Mobile numbers with 9th digit
- Geographic area codes
- Carrier competition effects
- Regulatory compliance requirements
Mexico (+52)
- Recent numbering plan changes
- Mobile number format updates
- Cross-border considerations
- Carrier infrastructure variations
Regional Phone Considerations
Implementation Guide
Building robust phone validation requires careful implementation and ongoing maintenance.
Validation Pipeline Architecture
Input Normalization
- Remove formatting characters
- Handle international prefixes
- Standardize to E.164 format
- Validate character sets
Multi-Stage Validation
1. Format and length validation
2. Country code verification
3. Number plan compliance
4. Carrier and type identification
5. Real-time reachability testing
Result Processing
- Confidence scoring
- Error categorization
- Recommendation generation
- Audit trail creation
Library and Tool Selection
Google libphonenumber
- Comprehensive format validation
- Regular updates for number plans
- Multi-language support
- Open source and well-maintained
Commercial APIs
- Twilio Lookup API
- Nexmo Number Insight
- Telesign Phone ID
- Custom carrier integrations
Performance Optimization
Caching Strategies
- Cache validation results by number
- Implement TTL based on number type
- Use distributed caching for scale
- Monitor cache hit rates
Batch Processing
- Process multiple numbers simultaneously
- Implement rate limiting for APIs
- Use connection pooling
- Provide progress tracking
Error Handling
Graceful Degradation
- Fallback to basic format validation
- Provide partial results when possible
- Handle API timeouts appropriately
- Maintain service availability
User Experience
- Clear error messages
- Formatting suggestions
- Alternative input methods
- Progressive validation feedback
Implementation Architecture
Quality Assurance and Testing
Validation Accuracy Testing
Test Number Databases
- Maintain test numbers for each country
- Include edge cases and special formats
- Regular updates for number plan changes
- Automated testing suites
Carrier Integration Testing
- Test with multiple carriers per country
- Validate special number types
- Check error handling scenarios
- Monitor API response times
Performance Monitoring
Key Metrics
- Validation accuracy rates
- API response times
- Error rates by country
- User satisfaction scores
Continuous Improvement
- Regular accuracy assessments
- User feedback integration
- Carrier relationship management
- Technology stack updates
Compliance and Legal Considerations
Privacy Requirements
Data Protection
- Minimize data collection and retention
- Implement appropriate security measures
- Provide user control and transparency
- Support data deletion requests
Consent Management
- Clear consent for validation activities
- Opt-out mechanisms where required
- Age verification for minors
- Cross-border data transfer compliance
Regulatory Compliance
Telecommunications Regulations
- Respect local numbering authorities
- Comply with carrier access rules
- Follow spam and privacy laws
- Maintain appropriate licenses
Industry Standards
- Follow CTIA guidelines (US)
- Comply with GSMA recommendations
- Adhere to regional best practices
- Participate in industry initiatives
Future Trends and Developments
Technology Evolution
5G Network Impact
- Enhanced number portability
- New service types and capabilities
- Improved location accuracy
- Advanced authentication methods
Rich Communication Services (RCS)
- Enhanced messaging capabilities
- Business messaging integration
- Verification and authentication
- Cross-platform compatibility
Regulatory Changes
Privacy Enhancement
- Stricter consent requirements
- Enhanced user control mechanisms
- Cross-border data restrictions
- Industry self-regulation initiatives
Number Portability Expansion
- Easier carrier switching
- Reduced validation complexity
- Enhanced user mobility
- Competitive market effects
Conclusion
Comprehensive phone number validation requires understanding international standards, regional variations, and carrier-specific requirements. Success depends on:
- Standards compliance with E.164 and regional numbering plans
- Multi-layered validation combining format, carrier, and reachability checks
- Regional expertise understanding local requirements and conventions
- Performance optimization for real-time validation needs
- Continuous maintenance keeping up with numbering plan changes
Organizations implementing robust phone validation can achieve 95%+ accuracy while ensuring global compatibility and regulatory compliance.
Validate phone numbers globally with our comprehensive Phone Validation API, featuring real-time carrier intelligence and international format support.