Formstack for Salesforce – Tracking iframe Forms in Google Analytics

min read

When it comes to tracking form events in Google Analytics, some third-party form platforms integrate seamlessly, while others can be a little more challenging.

My experience with Formstack has been eye-opening and seems to fall somewhere between seamless and challenging.

Formstack for Salesforce, the extension designed specifically for the Salesforce platform, includes the ability to use several predefined JavaScript API endpoints that can be executed at key points of the form lifecycle. A really useful and powerful feature.

However, a native account (one not sending data into Salesforce) requires that you purchase their Conversion Kit before you can take advantage of any Google Analytics tracking features.

Surprisingly, once the Conversion Kit is added to your account, the only way to track the source, medium, and other standard tracking information is to add UTM parameters to your forms. Otherwise, the source/medium for these form submissions will show in Google Analytics as a self-referral (i.e. because the forms are embedded using an <iframe> and no cross-domain tracking has been applied.

I found it unusual that the native application would not include the same advanced JavaScript API capabilities that their Salesforce extension does. On the other side of the equation, the Formstack for Salesforce extension doesn’t offer any out-of-the-box solution to send data to Google Analytics either.

Recently, a client had transitioned from Contact Form 7 to Formstack for Salesforce, and had decided to implement a sitewide form using the <iframe> method. To keep things moving along (and to prevent the client from having to re-implement all their forms sitewide), I decided to investigate and find a solution to send as much event information from behind the <iframe> as possible.

The method below should, in theory, work for any situation where you would like to send event information from behind an <iframe>, as long as you have the ability to customize code on the <iframe> source page.

Understanding the JavaScript API Endpoints

Before diving into the method and code itself, let’s first take a look at the JavaScript API endpoint choices available to us.

  • FF_OnBeforeRender – Defining this function in your page will cause the Formstack rendering engine to execute your custom code before rendering the form. This might be useful if you needed to show a ‘please wait’ message to the user.
  • FF_OnAfterRender – Defining this function in your page will cause the Formstack rendering engine to execute your custom code after your form has been rendered on the page. This may be useful for displaying instructions to the submitter after the form is displayed.
  • FF_OnBeforeSave – This function will be executed after the user clicks the Send button on their form and before the Formstack rendering engine saves the form information. This is useful for custom validation not covered by Formstack’s built-in functionality.
  • FF_OnAfterSave – This is useful for any custom behavior you would like to have triggered after a form has been successfully submitted and the form information has been saved to the database.

In order to initiate our function, I will be using FF_OnAfterSave. Read on to see the five simple steps to take to use this function effectively.

1. Set up the postMessage Function

The code above can be added just before the embed code on your page (perhaps most useful for instances of a single form, i.e. a Contact Us page), or added to the ‘Custom JavaScript’ section in the Form Settings of the form editor in Salesforce. 

I recommended using the Custom JavaScript option within Salesforce.
This option allows the custom JavaScript to be applied to every instance of a form wherever that form may be embedded, which is useful for e.g. a general “Request More Information” form that might be embedded across multiple pages. Furthermore, the Custom JavaScript option is easy to manage, doesn’t require you to loop in a developer, and helps reduce the room for error.

1. To do this, open the <iframe> form in Salesforce by clicking the “Edit” icon:

2. From there click the blue “Form Settings” option:

3. Scroll down to the “Javascript Code” section and add the code above.

You can use any values for the event and form, but the one thing you must change is (You’d want to update this to be your actual domain).

Since I am initiating cross-domain communication (also called cross-origin) it’s important to define which domains can safely communicate. 

In the code above, is known as the targetOrigin. When this function is fired, if the targetOrigin does not match the protocol, domain, and port (if provided) of the targetWindow (i.e. the domain of your site), it will fail to send.

4. Once you have replaced with your own domain, and you’re happy with the event and form name, you can click “Publish”.

Understanding PostMessage and Window Objects

The one thing that is universal to both the <iframe> and the page the form is embedded on is the browser itself.

To give context to this next part, I should briefly discuss the HTML5 API method window.postMessage() I am using. When executed, this allows you to safely send cross-origin messages between Window objects. For example, between a page and a pop-up that it generated, or between a page and the <iframe> embedded within it.

By default, window.postMessage is designed to communicate to the same Window console that the postMessage was sent from. In this case that would be the  <iframe>, which wouldn’t be helpful here. Therefore, I need to alter it to instead send the postMessage to the parent Window console (i.e. the parent page where the form is embedded), using parent.postMessage.

2. Listen for the PostMessage via Google Tag Manager

Now that I am set up to send our event information via  postMessage to the parent Window, I need to use Google Tag Manager to listen for when it occurs.

I can do this using the following code, deploying it through a custom HTML tag in Google Tag Manager.

<script type="text/javascript">
    (function(window) {
        addEvent(window, 'message', function(message) {
          var data = JSON.parse(;
          var dataLayer = window.dataLayer || (window.dataLayer = []);
          if (data.event) {
              'event': data.event,
              'postMessageData': data
        // Cross-browser event listener
        function addEvent(el, evt, fn) {
          if (el.addEventListener) {
            el.addEventListener(evt, fn);
          } else if (el.attachEvent) {
            el.attachEvent('on' + evt, function(evt) {
    , evt);
          } else if (typeof el['on' + evt] === 'undefined' || el['on' + evt] === null) {
            el['on' + evt] = function(evt) {
    , evt);

In our scenario I am firing the listener on every page view because our form is accessible from every page on the site. You may want to limit this to the specific pages that your forms are on.

If you put your Google Tag Manager account in Preview mode and navigate to your site, you should see this tag firing once on the pages you have set it to do so:

3. Send the Event Data to Google Analytics

In order to send event data from the postMessage to Google Analytics I need to create a new Google Analytics Event tag in Google Tag Manager.

Update the UA tracking ID to the one you use on your site, and use the Category field to describe your form.

In our scenario, since the same form is being used across many different pages, I can use the predefined variable {{Page Path}} in the Action field to help me identify which pages the form submission came from:

4. Trigger Google Analytics on PostMessage

In order for the Google Analytics Event tag to fire, I need to set up a Custom Event trigger. Simply make sure the event name matches the one you used in the postMessage JavaScript function (e.g. iframe-submit). 

That’s the last step in Google Tag Manager. Once you’ve made all of those changes you can go ahead and Preview or, if you feel confident enough, Publish your container.

5. Configure a Goal in Google Analytics

If everything was done correctly you should now see a unique Event occur in Google Analytics with each form submission.

You should also be able to see the page that each <iframe> form was submitted from, along with other session data such as source, medium and more.

The last thing left to do is create a new Event Goal in Google Analytics (assuming these form submissions are something you’d like to track as a Goal). To do that, simply make sure the Category name matches the one used in the Google Analytics Event tag that was set up earlier in Google Tag Manager.

Hopefully, this guide has helped solve any <iframe> form tracking issue you may have had, and also provided a little insight into the powerful capabilities of Web APIs.