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

  1. Lowercasing: Convert the entire email address to lowercase.
  2. Trimming: Remove any spaces from the beginning or end of the email address.
  3. Validation:
    • The email must contain exactly one @ symbol.
    • If not, use the trimmed and lowercased email as-is.

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)

  • Remove everything after and including the first + character.
  • Remove all periods (.).

Yahoo / Ymail (yahoo.com, ymail.com)

  • Remove everything after and including the first - character.
  • Remove all periods (.).

Outlook (outlook.com)

  • Remove everything after and including the first + character.

ProtonMail (protonmail.com, protonmail.ch, pm.me)

  • Remove everything after and including the first + character.

Apple Domains (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 EmailNormalized EmailHashed 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 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;
    }
}

Examples

Raw Phone NumberNormalized Phone (E.164)Hashed Phone (SHA-256)
(212) 555-1234+12125551234b7532e84c87df1f9f6bc4097cea3fa27db1b990bdc8d1211e59586349e5cce82
415.555.2368+141555523685efe6d2b35a8b1cd9395c2f451ff4d4eb6dd9ddc6761cdefea0653d62ac24011
3105551234+13105551234a2f7381cd9b4a70cbbbe1113afa0770eed79adfba525c33b69a11f87790850e1
1-718-555-7890+17185557890d7c5b36eb18b782d398fd7e3eec015189c801b2c24d226c3689198bb5ef952d2

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:

  1. Pass the hashed email through the Pixel identify call using hashed_email
  2. 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