Hashing Customer Data
Normalization and hashing guidelines for customer email and phone numbers
NB Orders API Guide: Normalization for Hashed Email & Phone
This document specifies normalization rules for emails and phone numbers prior to hashing for the hashed_customer_email
and hashed_customer_phone_number
fields in the NB Orders API. These rules are identical to the normalization used by integrated advertising platforms so that hashes generated by customers match 1:1 with platform-provided hashes.
Important:
• If you are sending raw emails/phone you should not send these hashed fields
• The emails and phone numbers should be first normalized and then hashed. The hashed versions should be sent via the NB API.
Hashing Output Format
- Algorithm: SHA-256
- Input: Normalized email or phone number
- Output: Lowercase hexadecimal (64 characters), no prefix
- Email: Hash the normalized email string
- Phone: Hash the E.164 string returned by normalization (include the leading
+
)
Email Normalization
Purpose
Normalize email addresses to a consistent format so that variations of the same email are treated as equivalent. This is useful for deduplication, simplified email handling and creating consistent SHA-256 hashes from emails.
General Rules
- Lowercasing: Convert the entire email address to lowercase.
- Trimming: Remove any spaces from the beginning or end of the email address.
- Validation:
- The email must contain exactly one
@
symbol. - If not, use the trimmed and lowercased email as-is.
- The email must contain exactly one
Domain-Specific Normalization Rules
Apply the following rules to the local part (the portion before the @
) based on the email's domain:
Gmail (gmail.com
)
gmail.com
)- Remove everything after and including the first
+
character. - Remove all periods (
.
).
Yahoo / Ymail (yahoo.com
, ymail.com
)
yahoo.com
, ymail.com
)- Remove everything after and including the first
-
character. - Remove all periods (
.
).
Outlook (outlook.com
)
outlook.com
)- Remove everything after and including the first
+
character.
ProtonMail (protonmail.com
, protonmail.ch
, pm.me
)
protonmail.com
, protonmail.ch
, pm.me
)- Remove everything after and including the first
+
character.
Apple Domains (icloud.com
, me.com
, mac.com
)
icloud.com
, me.com
, mac.com
)- Remove everything after and including the first
+
character.
Final Step
Recombine the cleaned local part with the domain part using @
. Use the resulting normalized email address.
Examples
Reference Implementation (JavaScript)
function emailNormalize(email) {
if (!email) {
return null;
}
// Utility functions
const stripPeriods = (value) => value.replace(/\./g, '');
const plusAddressing = (value) => value.split('+')[0];
const dashAddressing = (value) => value.split('-')[0];
// Normalize format
const normalized = email.trim().toLowerCase();
const parts = normalized.split('@');
// Invalid email format, return as-is
if (parts.length !== 2) {
return normalized;
}
let [localPart, domainPart] = parts;
let localPartRules = [];
// Domain-specific rules
switch (domainPart) {
case 'gmail.com':
localPartRules = [plusAddressing, stripPeriods];
break;
case 'yahoo.com':
case 'ymail.com':
localPartRules = [dashAddressing, stripPeriods];
break;
case 'outlook.com':
case 'protonmail.com':
case 'protonmail.ch':
case 'pm.me':
case 'icloud.com':
case 'me.com':
case 'mac.com':
localPartRules = [plusAddressing];
break;
}
// Apply all relevant rules
for (const rule of localPartRules) {
localPart = rule(localPart);
}
return `${localPart}@${domainPart}`;
}
Phone Normalization
Purpose
Format a phone number into a consistent style using the libphonenumber-js
library. This library:
- Removes any non-digit characters (like spaces, dashes, parentheses).
- Makes sure it starts with a
+
country code. If there's no country code, it adds+1
(for the US/Canada). - Returns
null
if the phone number is not valid.
Reference Implementation (JavaScript)
// Uses the libphonenumber-js library; import as follows:
// For ES6 modules (Node.js or modern bundlers)
import { parsePhoneNumber } from 'libphonenumber-js';
// OR for CommonJS (Node.js)
// const { parsePhoneNumber } = require('libphonenumber-js');
function normalizePhoneNumber(phone) {
try {
const parsed_phone = parsePhoneNumber(phone, 'US');
if (!parsed_phone || !parsed_phone.isValid()) return null;
return parsed_phone.number;
} catch (e) {
return null;
}
}
Complete Workflow Example
Here's a complete example showing normalization → hashing for both email and phone:
import crypto from 'crypto';
import { parsePhoneNumber } from 'libphonenumber-js';
// Hash a normalized string using SHA-256
function sha256Hash(input) {
return crypto.createHash('sha256').update(input, 'utf8').digest('hex');
}
// Example usage
const email = '[email protected]';
const phone = '(555) 123-4567';
const normalizedEmail = emailNormalize(email); // "[email protected]"
const hashedEmail = sha256Hash(normalizedEmail);
const normalizedPhone = normalizePhoneNumber(phone); // "+15551234567"
const hashedPhone = sha256Hash(normalizedPhone);
console.log('Hashed Email:', hashedEmail);
console.log('Hashed Phone:', hashedPhone);
Important Notes
- Always normalize before hashing
- Use SHA-256 with lowercase hexadecimal output
- Phone numbers should include the
+
when hashing - Invalid phone numbers return
null
- handle these gracefully in your implementation - These normalization rules match advertising platform standards for consistent matching
Updated about 6 hours ago