Google Tag Manager

You can forward Persona Inquiry SDK events to Google Tag Manager’s data layer for use in analytics, conversion tracking, and other GTM-powered workflows.

This integration uses a Persona-provided GTM template that receives events from the Embedded Flow SDK and pushes them to the data layer. No changes to the Persona SDK itself are required — you only need to add a small callback to your existing SDK configuration.

Step 1: Import the Persona GTM template

Copy the template code at the bottom of this page into a file named persona-gtm-template.tpl.

Once you have the file:

  1. In your GTM workspace, go to Templates > Tag Templates > New.
  2. Click the three-dot menu in the top right and select Import.
  3. Select the .tpl file.
  4. Click Save.

Step 2: Create a tag

  1. Go to Tags > New.
  2. Under Tag Configuration, select Persona Inquiry Events as the tag type.
  3. Choose which events to forward:
    • All events — forwards every event from the SDK.
    • Lifecycle events only — forwards ready, start, complete, cancel, and error.
    • Custom selection — choose specific events to forward.
  4. Set a trigger (e.g. All Pages or Page Initialization) so the tag is active before the Persona SDK loads.
  5. Click Save, then Publish your workspace.

Step 3: Add the onEvent callback

In your existing Persona.Client configuration, add the onEvent callback:

1const client = new Persona.Client({
2 // ...your existing config
3 onEvent: (name, meta) => {
4 window.PersonaGTM?.push(name, meta);
5 },
6});

Optionally, if you want to receive all events including click, form-update, and step-transitioned, add the eventsAllowlist parameter (requires SDK 5.8.0+):

1const client = new Persona.Client({
2 // ...your existing config
3 eventsAllowlist: "all",
4 onEvent: (name, meta) => {
5 window.PersonaGTM?.push(name, meta);
6 },
7});

Step 4: Use events in GTM

Events appear in the data layer as PersonaInquiry.<eventName> (e.g. PersonaInquiry.complete). Each event includes a personaEvent object with:

  • personaEvent.name — the event name (e.g. complete, cancel, click)
  • personaEvent.metadata — the event metadata (see Client Callbacks for details on each event’s metadata)

Create a trigger

To fire another tag (e.g. Google Analytics, a conversion pixel) when an inquiry completes:

  1. Go to Triggers > New.
  2. Select Custom Event as the trigger type.
  3. Set the event name to PersonaInquiry.complete.
  4. Save the trigger and attach it to the tag you want to fire.

Create a data layer variable

To access event data in other tags:

  1. Go to Variables > User-Defined Variables > New.
  2. Select Data Layer Variable as the variable type.
  3. Set the variable name to personaEvent.metadata.inquiryId (or any other property you need).
  4. Use this variable in your other tags.

You can use Persona’s hashed PII fields to power Google Ads Enhanced Conversions without exposing raw user data in the data layer.

To get started, contact Persona support to enable hashed fields on your inquiry template. Once enabled, the complete event metadata will include a hashedFields object containing SHA-256 hashed values for the configured fields (e.g. email_address, phone_number).

To set up Enhanced Conversions in GTM:

  1. Create Data Layer Variables for each hashed field you need:
    • personaEvent.metadata.hashedFields.email_address
    • personaEvent.metadata.hashedFields.phone_number
  2. Create a Google Ads: Conversion Tracking tag.
    • Enter your Conversion ID and Conversion Label.
    • Check Include user-provided data from your website.
    • Map the user-provided data fields (Email, Phone, etc.) to the data layer variables you created above.
    • Set the trigger to PersonaInquiry.complete.

Google Ads Enhanced Conversions accepts pre-hashed SHA-256 values, so no additional transformation is needed in GTM.

Template code

Copy the contents below into a file named persona-gtm-template.tpl to import into GTM.

persona-gtm-template.tpl
___TERMS_OF_SERVICE___
By creating or modifying this file you agree to Google Tag Manager's Community
Template Gallery Developer Terms of Service available at
https://developers.google.com/tag-manager/gallery-tos (or such other URL as
Google may provide), as modified from time to time.
___INFO___
{
"type": "TAG",
"id": "cvt_temp_public_id",
"version": 1,
"securityGroups": [],
"displayName": "Persona Inquiry Events",
"categories": [
"ANALYTICS"
],
"brand": {
"id": "brand_persona",
"displayName": "Persona",
"thumbnail": ""
},
"description": "Forwards Persona Inquiry SDK events to the GTM data layer. Use with the Persona Embedded Flow SDK to track inquiry lifecycle events like completion, cancellation, and verification steps.",
"containerContexts": [
"WEB"
]
}
___TEMPLATE_PARAMETERS___
[
{
"type": "SELECT",
"name": "eventFilter",
"displayName": "Events to forward",
"macrosInSelect": false,
"selectItems": [
{
"value": "all",
"displayValue": "All events"
},
{
"value": "lifecycle",
"displayValue": "Lifecycle events only (ready, complete, cancel, error)"
},
{
"value": "custom",
"displayValue": "Custom selection"
}
],
"simpleValueType": true,
"defaultValue": "all",
"help": "Choose which Persona SDK events are forwarded to the data layer."
},
{
"type": "GROUP",
"name": "customEvents",
"displayName": "Select events",
"groupStyle": "NO_ZIPPY",
"enablingConditions": [
{
"paramName": "eventFilter",
"paramValue": "custom",
"type": "EQUALS"
}
],
"subParams": [
{
"type": "CHECKBOX",
"name": "evt_ready",
"checkboxText": "ready",
"simpleValueType": true,
"defaultValue": true
},
{
"type": "CHECKBOX",
"name": "evt_start",
"checkboxText": "start",
"simpleValueType": true,
"defaultValue": true
},
{
"type": "CHECKBOX",
"name": "evt_complete",
"checkboxText": "complete",
"simpleValueType": true,
"defaultValue": true
},
{
"type": "CHECKBOX",
"name": "evt_cancel",
"checkboxText": "cancel",
"simpleValueType": true,
"defaultValue": true
},
{
"type": "CHECKBOX",
"name": "evt_error",
"checkboxText": "error",
"simpleValueType": true,
"defaultValue": true
},
{
"type": "CHECKBOX",
"name": "evt_document_camera_select",
"checkboxText": "document-camera-select",
"simpleValueType": true,
"defaultValue": false
},
{
"type": "CHECKBOX",
"name": "evt_document_camera_capture",
"checkboxText": "document-camera-capture",
"simpleValueType": true,
"defaultValue": false
},
{
"type": "CHECKBOX",
"name": "evt_document_upload",
"checkboxText": "document-upload",
"simpleValueType": true,
"defaultValue": false
},
{
"type": "CHECKBOX",
"name": "evt_documents_save_successful",
"checkboxText": "documents-save-successful",
"simpleValueType": true,
"defaultValue": false
},
{
"type": "CHECKBOX",
"name": "evt_documents_save_fail",
"checkboxText": "documents-save-fail",
"simpleValueType": true,
"defaultValue": false
},
{
"type": "CHECKBOX",
"name": "evt_selfie_camera_select",
"checkboxText": "selfie-camera-select",
"simpleValueType": true,
"defaultValue": false
},
{
"type": "CHECKBOX",
"name": "evt_selfie_camera_capture",
"checkboxText": "selfie-camera-capture",
"simpleValueType": true,
"defaultValue": false
},
{
"type": "CHECKBOX",
"name": "evt_selfie_record_upload",
"checkboxText": "selfie-record-upload",
"simpleValueType": true,
"defaultValue": false
},
{
"type": "CHECKBOX",
"name": "evt_load_camera_failed",
"checkboxText": "load-camera-failed",
"simpleValueType": true,
"defaultValue": false
},
{
"type": "CHECKBOX",
"name": "evt_one_time_link_sent",
"checkboxText": "one-time-link-sent",
"simpleValueType": true,
"defaultValue": false
},
{
"type": "CHECKBOX",
"name": "evt_one_time_link_start",
"checkboxText": "one-time-link-start",
"simpleValueType": true,
"defaultValue": false
},
{
"type": "CHECKBOX",
"name": "evt_one_time_link_exit",
"checkboxText": "one-time-link-exit",
"simpleValueType": true,
"defaultValue": false
},
{
"type": "CHECKBOX",
"name": "evt_page_change",
"checkboxText": "page-change",
"simpleValueType": true,
"defaultValue": false
},
{
"type": "CHECKBOX",
"name": "evt_step_transitioned",
"checkboxText": "step-transitioned",
"simpleValueType": true,
"defaultValue": false
},
{
"type": "CHECKBOX",
"name": "evt_click",
"checkboxText": "click",
"simpleValueType": true,
"defaultValue": false
},
{
"type": "CHECKBOX",
"name": "evt_form_update",
"checkboxText": "form-update",
"simpleValueType": true,
"defaultValue": false
}
]
},
{
"type": "GROUP",
"name": "advancedSettings",
"displayName": "Advanced Settings",
"groupStyle": "ZIPPY_CLOSED",
"subParams": [
{
"type": "TEXT",
"name": "eventPrefix",
"displayName": "Event name prefix",
"simpleValueType": true,
"defaultValue": "PersonaInquiry",
"help": "Prefix for data layer event names. Events will appear as prefix.eventName (e.g. PersonaInquiry.complete).",
"valueValidators": [
{
"type": "NON_EMPTY"
}
]
}
]
}
]
___SANDBOXED_JS_FOR_WEB_TEMPLATE___
const log = require('logToConsole');
const setInWindow = require('setInWindow');
const createQueue = require('createQueue');
const dataLayerPush = createQueue('dataLayer');
const eventPrefix = data.eventPrefix || 'PersonaInquiry';
const lifecycleEvents = ['ready', 'complete', 'cancel', 'error', 'start'];
const customEventMap = {
'ready': data.evt_ready,
'start': data.evt_start,
'complete': data.evt_complete,
'cancel': data.evt_cancel,
'error': data.evt_error,
'document-camera-select': data.evt_document_camera_select,
'document-camera-capture': data.evt_document_camera_capture,
'document-upload': data.evt_document_upload,
'documents-save-successful': data.evt_documents_save_successful,
'documents-save-fail': data.evt_documents_save_fail,
'selfie-camera-select': data.evt_selfie_camera_select,
'selfie-camera-capture': data.evt_selfie_camera_capture,
'selfie-record-upload': data.evt_selfie_record_upload,
'load-camera-failed': data.evt_load_camera_failed,
'one-time-link-sent': data.evt_one_time_link_sent,
'one-time-link-start': data.evt_one_time_link_start,
'one-time-link-exit': data.evt_one_time_link_exit,
'page-change': data.evt_page_change,
'step-transitioned': data.evt_step_transitioned,
'click': data.evt_click,
'form-update': data.evt_form_update,
};
const shouldForward = function (eventName) {
if (data.eventFilter === 'all') {
return true;
}
if (data.eventFilter === 'lifecycle') {
return lifecycleEvents.indexOf(eventName) > -1;
}
return !!customEventMap[eventName];
};
// Strip PII fields from metadata before pushing to the data layer.
// 'fields' contains personally identifiable information (name, DOB, address, etc.)
// and should never be sent to third-party analytics.
const piiKeys = ['fields'];
const getType = require('getType');
const stripPii = function (obj) {
if (!obj || getType(obj) !== 'object') {
return obj;
}
const clean = {};
for (var key in obj) {
if (piiKeys.indexOf(key) === -1) {
clean[key] = obj[key];
}
}
return clean;
};
const push = function (eventName, metadata) {
if (!shouldForward(eventName)) {
return;
}
log('Persona GTM: forwarding event', eventName);
const safeMetadata = stripPii(metadata);
const dlEvent = {
event: eventPrefix + '.' + eventName,
personaEvent: {
name: eventName,
metadata: safeMetadata,
},
};
dataLayerPush(dlEvent);
};
setInWindow('PersonaGTM', { push: push }, true);
log('Persona GTM: ready');
data.gtmOnSuccess();
___WEB_PERMISSIONS___
[
{
"instance": {
"key": {
"publicId": "logging",
"versionId": "1"
},
"param": [
{
"key": "environments",
"value": {
"type": 1,
"string": "debug"
}
}
]
},
"clientAnnotations": {
"isEditedByUser": true
},
"isRequired": true
},
{
"instance": {
"key": {
"publicId": "access_globals",
"versionId": "1"
},
"param": [
{
"key": "keys",
"value": {
"type": 2,
"listItem": [
{
"type": 3,
"mapKey": [
{
"type": 1,
"string": "key"
},
{
"type": 1,
"string": "read"
},
{
"type": 1,
"string": "write"
},
{
"type": 1,
"string": "execute"
}
],
"mapValue": [
{
"type": 1,
"string": "PersonaGTM"
},
{
"type": 8,
"boolean": true
},
{
"type": 8,
"boolean": true
},
{
"type": 8,
"boolean": false
}
]
},
{
"type": 3,
"mapKey": [
{
"type": 1,
"string": "key"
},
{
"type": 1,
"string": "read"
},
{
"type": 1,
"string": "write"
},
{
"type": 1,
"string": "execute"
}
],
"mapValue": [
{
"type": 1,
"string": "PersonaGTM.push"
},
{
"type": 8,
"boolean": true
},
{
"type": 8,
"boolean": true
},
{
"type": 8,
"boolean": false
}
]
},
{
"type": 3,
"mapKey": [
{
"type": 1,
"string": "key"
},
{
"type": 1,
"string": "read"
},
{
"type": 1,
"string": "write"
},
{
"type": 1,
"string": "execute"
}
],
"mapValue": [
{
"type": 1,
"string": "dataLayer"
},
{
"type": 8,
"boolean": true
},
{
"type": 8,
"boolean": true
},
{
"type": 8,
"boolean": false
}
]
}
]
}
}
]
},
"clientAnnotations": {
"isEditedByUser": true
},
"isRequired": true
}
]
___TESTS___
scenarios:
- name: sets up global and succeeds
code: |-
const mockData = {
eventFilter: 'all',
eventPrefix: 'PersonaInquiry',
};
runCode(mockData);
assertApi('setInWindow').wasCalled();
assertApi('gtmOnSuccess').wasCalled();
- name: uses custom event prefix
code: |-
const mockData = {
eventFilter: 'all',
eventPrefix: 'MyPrefix',
};
runCode(mockData);
assertApi('setInWindow').wasCalled();
assertApi('gtmOnSuccess').wasCalled();
___NOTES___
Created on 2026-03-31