Reading Query String Parameters into your Public Embedded Studio Apps securely

This use case discusses different ways of passing data from parent window to the public embedded app.

Methods covered:

  1. Passing Parent Window’s Encrypted Query String to the public embedded app.
  2. Passing Parent Window’s variables to the public embedded app.

Both the methods listed above make use of query strings, You can read the docs on how to create them inside the studio from here.

App Overview

For this use case, we have taken two textfields and one button. Our application will fetch the relevant encrypted query strings and decrypt them before setting those values to the textfield controls.

Setting up Query Strings

We have created two query strings namely field1 and field2 as shown below.

Parent Window Encrypted Query String

App Logic

We will set up our application logic on the screen open event.

  1. Add a delay, so that the parent app window gets some time to pass the query strings to our public embedded app. This is only applicable for screen open event, If you are binding your app logic to some other events like button click, etc. then adding a delay is not required.

  1. Add a compute variable block which will store the values of query strings into variables. In our case the variables are nameVal and emailVal.

  1. We need to decrypt the query strings value before setting them onto the textfields. This can be done by adding a JS Code Block. In the Input Parameters section, add two variables: name and email which will store the values of query string variables from the previous compute variables block.

Code

function decrypt(encryptedString, passphrase) {
    const decoded = CryptoJS.enc.Hex.parse(encryptedString)
        .toString(CryptoJS.enc.Base64);
    const decrypted = CryptoJS.AES.decrypt(decoded, passphrase)
        .toString(CryptoJS.enc.Utf8);
    return decrypted;
}
name = decrypt(name, "Secret Passphrase");
email = decrypt(email, "Secret Passphrase");
output = {
    name,
    email
}
  1. Store the JS Code Block output to variables. In our case these variables are nameValue and emailValue.

  1. Lastly, add a Set Controls Value block which will set the JS Code Block output variables to the textfield controls.

  1. Now publish the App.

Embedding the App

  1. Open the App Settings and go to Embed Settings

8

  1. Go to the IFrame section. Copy the iframe html code as it is and paste it inside your parent website.

Setup Tracking

This step is mandatory to ensure that query strings are passed from the parent app to our public embedded app.

  1. Go to the Setup Tracking Section and click on Start Tracking.

  1. Make sure the query strings created earlier show up on this screen before clicking on the proceed button.

  1. Click on the “Get Tracking Code” button.

  1. Now copy this code and paste it to your parent website just before the end of the body tag.

Parent Website

Your parent website code should look something similar to this.

Code

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Encrypted Query String Demo</title>
    <style>
        body {
            height: 95vh;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        iframe {
            border: 2px solid;
        }
    </style>
</head>

<body>
    <iframe class="studio-embed" src="https://apigenie.io/GllnbBJ76ADFOR2tqArBv8m6L6nkvqhHmjEPIvn2B3CgZ?type=emd"
        frameborder="0" style="background: transparent; " width="450" height="533">
    </iframe>

    <script type="text/javascript">
        function DHQLead() { }
        DHQLead.utmPValObj = DHQLead.utmPValObj || {};

        DHQLead.utmPNameArr = new Array('field1', 'field2'
        );
        DHQLead.prototype.dfutm_getLeadVal = function (pName) {
            var qStr = '';
            try {
                qStr = window.top.location.search.substring(1);
            } catch (e) {
                qStr = '';
            }
            var pNameTemp = pName + '=';
            var pValue = '';
            if (typeof qStr !== "undefined" && qStr !== null && qStr.length > 0) {
                var begin = qStr.indexOf(pNameTemp);
                if (begin != -1) {
                    begin = begin + pNameTemp.length;
                    end = qStr.indexOf('&', begin);
                    if (end == -1) {
                        end = qStr.length;
                    }
                    pValue = qStr.substring(begin, end);
                }
            }
            if (pValue == undefined || pValue == '') {
                pValue = this.zfutm_gC(pName);
            }
            if (typeof pValue !== "undefined" && pValue !== null) {
                pValue = pValue.replace(/\+/g, ' ');
            }
            return pValue;
        };
        DHQLead.prototype.zfutm_gC = function (name) {
            name = name.replace(/[\[\]]/g, '\\$&');
            var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
                results = regex.exec(window.location.href);
            if (!results) return null;
            if (!results[2]) return '';
            return decodeURIComponent(results[2].replace(/\+/g, ' '));
        };
        DHQLead.prototype.futm_iframeSprt = function () {
            var zf_frame = document.getElementsByTagName("iframe");
            for (var i = 0; i < zf_frame.length; ++i) {
                if ((zf_frame[i].src).indexOf('type') > 0) {
                    var zf_src = zf_frame[i].src;
                    for (var prmIdx = 0; prmIdx < DHQLead.utmPNameArr.length; prmIdx++) {
                        var utmPm = DHQLead.utmPNameArr[prmIdx];
                        var utmVal = this.dfutm_getLeadVal(DHQLead.utmPNameArr[prmIdx]);
                        if (typeof utmVal !== "undefined" && utmVal !== null) {
                            if (zf_src.indexOf('?') > 0) {
                                zf_src = zf_src + '&' + utmPm + '=' + utmVal;
                            } else {
                                zf_src = zf_src + '?' + utmPm + '=' + utmVal;
                            }
                        }
                    }
                    if (zf_frame[i].src.length < zf_src.length) {
                        zf_frame[i].src = zf_src;
                    }
                }
            }
        };
        var futm_zfLead = new DHQLead();
        window.onload = function () {
            futm_zfLead.futm_iframeSprt();
        }
    </script>
</body>

</html>

Output


 

Note: Make sure the encrypted query strings are encoded to be url friendly. In this use case, we have used base64 encoding. And instead of decrypting encrypted query string parameters on the client side in JS Code, you can further make it secure by using your backend API for decrypting this parameters.

Parent Window Variables

App Logic

  1. Perform the steps 1 and 2 from the Parent Window Encrypted Query String’s App Logic section.

  2. Add a Set Controls Value block which will set the Compute block output variables to the textfield controls.

  1. Now publish the App.

Embedding the App

To embed the studio app into our parent website, we need to copy the iframe code from the embed settings option. You can have a look at how to do this from here.

Code

window.onload = function () {
    const queryStrings = {
        "field1": sessionStorage.getItem('name'),
        "field2": localStorage.getItem('email'),
        // "field3": document.querySelector("#element").value,
        // "field4": document.getElementById("element").innerText
        // "field5": "{{USER.EMAIL}}"
    }
    function formURL(queryStrings) {
        return Object.keys(queryStrings)
            .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(queryStrings[key])}`)
            .join('&');
    }

    const iFrameWindows = document.getElementsByTagName("iframe");
    for (let i = 0; i < iFrameWindows.length; i++) {
        if ((iFrameWindows[i].src).indexOf('type') > 0) {
            iFrameWindows[i].src = `${iFrameWindows[i].src}&${formURL(queryStrings)}`;
        }
    }
}

Code Explanation

This is the javascript code that goes inside your parent app. Inside the window onload function there is a javascript object by the name “queryStrings”, the keys in the object correspond to the query string parameters created inside the studio and values for these keys can be any literal value or variables. Make sure the object key name matches exactly with the studio query parameters or else it won’t work.

Parent Website

Your parent website code should look something similar to this.

Code

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Global Variables Query String Demo</title>
    <style>
        body {
            height: 95vh;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        iframe {
            border: 2px solid;
        }
    </style>
</head>

<body>
    <iframe class="studio-embed" src="https://apigenie.io/2yD5MdtOd3N5PG842bbg2fIZIr2xHhdLjKOxCWTktHjMC?type=emd"
        frameborder="0" style="background: transparent; " width="450" height="533"></iframe>

    <script type="text/javascript">
        window.onload = function () {
            const queryStrings = {
                "field1": sessionStorage.getItem('name'),
                "field2": localStorage.getItem('email')
                // "field3": document.querySelector("#element").value,
                // "field4": document.getElementById("element").innerText
                // "field5": "{{USER.EMAIL}}"
            }
            function formURL(queryStrings) {
                return Object.keys(queryStrings)
                    .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(queryStrings[key])}`)
                    .join('&');
            }

            const iFrameWindows = document.getElementsByTagName("iframe");
            for (let i = 0; i < iFrameWindows.length; i++) {
                if ((iFrameWindows[i].src).indexOf('type') > 0) {
                    iFrameWindows[i].src = `${iFrameWindows[i].src}&${formURL(queryStrings)}`;
                }
            }
        }
    </script>
</body>

</html>

Output