Blog

SHA-256 in a Custom Template, with a working example

The crypto module is locked down. Here is what works, what does not, and the pattern for hashing user_data fields in bulk.

sGTM Custom Templates run in a sandboxed environment that does not have Node's full crypto API. The sha256 module is the only hashing primitive available, and it has one quirk that surprises everyone the first time.

The basic call

const sha256 = require('sha256');
const hash = sha256('jane@example.com', {outputEncoding: 'hex'});
return hash;

Returns a 64-character lowercase hex string. The outputEncoding: 'hex' option is required; without it you get a base64 string, which the destinations do not accept.

The async version

There is also sha256Async, which returns a Promise. Use this when you are hashing inside an event handler that needs to wait. Most of the time the synchronous version is fine, but if your tag template uses callLater or has multiple chained async operations, the async hash keeps the chain consistent.

Hashing user_data in bulk

A common pattern: receive a user_data object with multiple fields, hash each one, return the hashed object. The Custom Template sandbox does not have Object.entries, so you have to enumerate keys manually:

const sha256 = require('sha256');
const userData = data.userData;
const hashed = {};
const keys = ['email', 'phone', 'first_name', 'last_name', 'city', 'zip'];
for (let i = 0; i < keys.length; i++) {
  const k = keys[i];
  if (userData[k]) {
    hashed[k] = sha256(userData[k].trim().toLowerCase(), {outputEncoding: 'hex'});
  }
}
return hashed;

Note the trim().toLowerCase() step. For email this matches Meta's expected normalisation. For phone numbers you need E.164 formatting first. For names, lowercase plus trim is enough.

Testing your hash

A reference value for verification: the SHA-256 of jane@example.com (lowercase, no whitespace) is:

e0d2e7b85700e5db0dabb103e0b48aa39b96ada7b1c9a1d51b7e83b5c5f5be8b

If your template returns this, the hash is correct. If it returns anything else, check the input string for hidden whitespace or different casing.