Setting self-describing event in Google Tag Manager

Hi! I’m trying to set a self-describing event in Google Tag Manager. I’ve already created the schema for the self-describing event and uploaded it into my Iglu server.

When setting a self-describing event it’s said that we need to configure the “data” parameter to send the data for each field of the self-describing event as described in this document: Self-describing events | Snowplow Documentation.

I tried setting up this parameter through a Google Tag Manager variable using custom JavaScript (shown below).

function() {
  var how_did_you_hear_select_element = document.getElementById("how_did_you_hear_element_id");
  var country_select_element = document.getElementById("country_element_id");
  var state_select_element = document.getElementById("state_element_id");
  
  var first_name = document.querySelector('input[name=names[first_name]]').value || "";
  var last_name = document.querySelector('input[name=names[last_name]]').value || "";
  var phone = document.querySelector('input[name=phone]').value || "";  
  var email = document.querySelector('input[name=email]').value || "";  
  var how_did_you_hear = how_did_you_hear_select_element.options[how_did_you_hear_select_element.selectedIndex].text || "";  
  var how_did_you_hear_additional_text = document.querySelector('input[name=how_did_you_hear_additional_text]').value || "";
  var country_list = country_select_element.options[country_select_element.selectedIndex].text || "";
  var state = state_select_element.options[state_select_element.selectedIndex].text || "";
  

  return {
    data: {
      first_name: first_name,
      last_name: last_name, 
      phone: phone,
      email: email,
      how_did_you_hear: how_did_you_hear,
      how_did_you_hear_additional_text: how_did_you_hear_additional_text,
      country_list: country_list,
      state: state
    }
  };
}

I’m capturing form submissions with my self-describing event and the input data from the form. However, when I submit the form from my website, and I look at the enrich server logs, it goes to the bad stream. When looking into the bad output in S3 it shows that it was a ValidationError because the data for each field of the event is missing, so I’m assuming my parameter configuration did not work. I’m unable to find a clear answer on how to set this parameter correctly using Google Tag Manager.

If anyone can help me, I’ll appreciate it! Thanks!

What is the payload that you receive in the bad stream?

Given capturing form values is such a common use case we have a plugin that does this out of the box and captures all values as part of the submit_form event that you may find helpful. You can enable this in your initialisation snippet by including the plugin and then calling snowplow('enableFormTracking'); to enable the form tracking.

The error that shows up in the payload is the following: {"error":"ValidationError","dataReports":[{"message":"$.email: is missing but it is required","path":"$","keyword":"required","targets":["email"]},{"message":"$.phone: is missing but it is required","path":"$","keyword":"required","targets":["phone"]},{"message":"$: should have a minimum of 1 properties","path":"$","keyword":"minProperties","targets":["1"]}]}}]}.

I’m using a self describing event instead of the out of the box plugin because I want to capture those events in a better format, separating them in their own columns. I also didn’t find a way to filter this form tracking plugin to only capture submit form type of tracking in Google Tag Manager, it saves change and focus form which I don’t want to save in my database.

I think the most likely cause is that there may be something incorrect with these selectors based on your form and how it functions. Depending on how your form works a common method is to push the values to the dataLayer and then use this to trigger the tag however it’s hard to know exactly what is going wrong without knowing how the form behaves.

e.g.,

document.querySelector('input[name=email]').value) || ""
will raise a TypeError if the element does not exist in the DOM vs something like
document.querySelector('input[name=email]')?.value
which will instead return an empty string.

It may be that the rest of your code works but you are receiving errors for these fields if the selectors are incorrect (or don’t exist in the DOM at the time the code is run etc).

Are you using the GTM templates or using code tags? If it’s direct tags you can use

snowplow('enableFormTracking', {
    options: {
        events: ['submit_form']
    },
});

to only capture submits.