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
| Input Email | Normalized Email | Hashed Email (SHA-256) |
|---|---|---|
| [email protected] | [email protected] | 06a240d11cc201676da976f7b49341181fd180da37cbe40a77432c0a366c80c3 |
| [email protected] | [email protected] | 4a5206b6c57519e9ad41b5358b80f7e6e33dff21a263914f343454ab0fbbb4cb |
| [email protected] | [email protected] | 121a30e5c931fc09bbfcdbd9586976e764c76ac3687ba9afcde1fb7b92c077ce |
| [email protected] | [email protected] | d5080076cd5eb196ad2ed4d15dd93113fa810c17b51813d0bb5acc2b3f266ffc |
| [email protected] | [email protected] | 528dfe1c042ae276513bd1f3b662faaee6ef3ce8b9bea03181aa94ea4592683b |
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
nullif 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;
}
}Examples
| Raw Phone Number | Normalized Phone (E.164) | Hashed Phone (SHA-256) |
|---|---|---|
| (212) 555-1234 | +12125551234 | b7532e84c87df1f9f6bc4097cea3fa27db1b990bdc8d1211e59586349e5cce82 |
| 415.555.2368 | +14155552368 | 5efe6d2b35a8b1cd9395c2f451ff4d4eb6dd9ddc6761cdefea0653d62ac24011 |
| 3105551234 | +13105551234 | a2f7381cd9b4a70cbbbe1113afa0770eed79adfba525c33b69a11f87790850e1 |
| 1-718-555-7890 | +17185557890 | d7c5b36eb18b782d398fd7e3eec015189c801b2c24d226c3689198bb5ef952d2 |
Using Hashed Emails for Attribution & CDV
Northbeam supports passing hashed emails through both the Pixel identify call and the Orders API. This allows hashed emails to be used for attribution and Customer Data Vault (CDV) matching workflows.
Pixel Identify Call
If you are already using the standard identify call, replace "email" with "hashed_email" and pass the SHA-256 hashed value instead.
Example
window.Northbeam.identify(
"hashed_email",
"1bb931a0c4488a629e0eb571988b87811c27338ad90888376567c7bce0419e5a"
);Orders API
If sending hashed customer data through the Orders API, populate the hashed_customer_email field with the same SHA-256 hashed email value.
Important
To enable hashed email attribution and CDV matching end-to-end:
- Pass the hashed email through the Pixel identify call using
hashed_email - Pass the same hashed value through the Orders API using
hashed_customer_email
Both values must:
- Be normalized prior to hashing
- Use SHA-256 hashing
- Match consistently between the Pixel and Orders API
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 1 day ago
