Saving the Referrer URL Within A SurveyJS Response And Using It To Control the Flow Of The Survey

Introduction

It is common to link to your public surveys from various locations, such as corporate sites, social media, blogs, etc. In those cases it is often useful to know where each of your respondents came from. The most obvious solution would be to rely on Google Analytics or some other similar package, but it is also possible to extend SurveyJS so that it includes some basic referrer information with every response.

You can make things even more interesting by using the referrer URL to control the flow and behavior of your SurveyJS forms. That can be achieved by making it available to the expression engine, which the framework uses for conditional display of items and other logic.

Important privacy disclaimer

Please keep in mind that transmitting and storing the referrer URL of your visitors might be considered a violation of privacy. Make sure that your production site or application’s privacy policy reflects such activities. For more information see this article: https://developer.mozilla.org/en-US/docs/Web/Security/Referer_header:_privacy_and_security_concerns

Retrieving the referrer

Let’s start by creating a simple JavaScript function, which returns the referrer URL from the document object. In some cases document.referrer will return an empty string. The most obvious and expected case is when there is no referrer – the visitor did not come from a different site, but started their browsing session with the url of the survey.

Another case that needs to be considered is when the survey is inside an iframe. In that case the referrer value might be an empty string or it might match the URL of the parent. To handle this we will try to detect whether the survey is embedded in an iframe and try to obtain the referrer from the iframe’s parent. Please note that if the parent and iframe are under different domain names this will probably not work due to cross-site scripting safeguards.

Finally, for the purposes of this demonstration, we will return only the host name portion of the URL.

function referrerUrl() {
  var referrer;

  if (window.location !== window.parent.location) {
    // The page is in an iframe - we should get the referrer from the parent
    referrer = parent.document.referrer;
  } else {
    // The page is not in an iframe
    referrer = document.referrer;
  }

  if (referrer === "") {
    return "none";
  }

  return new URL(referrer).hostname;
}

Registering the function with the expression engine of SurveryJS

One of the biggest advantages of the SurveyJS library is that it can be easily extended. This applies to its expression engine as well.

We can register our new function by calling the following method:

Survey.FunctionFactory.Instance.register("referrerUrl", referrerUrl);

(The first parameter is the name under which the function will be registered and the second one is a reference to the function itself)

Saving the referrer value within the survey response object

Now that we have created and registered our custom function we can start using it within our survey model.

To save the value of the referrer along with the rest of our survey response data we can create a hidden text question and set its default value expression to call our new referrerUrl function:

...
{
  "type": "text",
  "name": "referrerUrl",
  "visible": false,
  "defaultValueExpression": "referrerUrl()"
}
...

Please note that by default SurveyJS does not save the values of hidden questions. We need to explicitly tell it to do so by adding the following parameter to the top level of the survey model:

{
...
   "showQuestionNumbers": "off",
   "clearInvisibleValues": "none"
}

Using the custom function with conditional display logic

SurveyJS allows for questions, pages, or panels to be hidden or displayed depending on various rules and responses to previous questions. For more information see the following article from the official documentation: https://surveyjs.io/Documentation/Library#conditions

Let’s say we have a survey model with the following three questions:

{
     "type": "radiogroup",
     "name": "question1",
     "title": "How did you find out about our survey?",
     "choices": [
      {
       "value": "item1",
       "text": "YouTube"
      },
      {
       "value": "item2",
       "text": "Twitter"
      }
     ]
    },
    {
     "type": "radiogroup",
     "name": "question2",
     "visibleIf": "{question1} = 'item1'",
     "title": "Did you find our video useful?",
     "choices": [
      {
       "value": "item1",
       "text": "Yes"
      },
      {
       "value": "item2",
       "text": "No"
      }
     ]
    },
    {
     "type": "dropdown",
     "name": "question3",
     "visibleIf": "{question1} = 'item2'",
     "title": "How long have you been using Twitter?",
     "choices": [
      {
       "value": "item1",
       "text": "Less than a year"
      },
      {
       "value": "item2",
       "text": "1 to 5 years"
      },
      {
       "value": "item3",
       "text": "More than 5 years"
      }
     ]
}

As you can see from the “visibleIf” values, the second and third questions would be visible depending on the answer to the first question.

If we knew that the visitor came from SurveySocket.com or from Twitter, then we wouldn’t need the first question altogether. Our custom referrer URL function can be used to handle that case. Please note that links within tweets go through Twitter’s URL shortener, which means the referrer url appears as “t.co”:

{
  "type": "radiogroup",
  "name": "question1",
  "visibleIf": "referrerUrl() != 't.co' && referrerUrl() != 'surveysocket.com'",
  "title": "How did you find out about our survey?",
  "choices": [
    {
      "value": "item1",
      "text": "SurveySocket"
    },
    {
      "value": "item2",
      "text": "Twitter"
    }
  ]
}

We also need to expand on the visibleIf rules for the other two questions, as follows:

...
"visibleIf": "{question1} = 'item1' || referrerUrl() = ‘surveysocket.com'"
...
"visibleIf": "{question1} = 'item2' || referrerUrl() = ‘t.co'"
...

With those changes the survey will behave normally and start with question1 if there is no referrer, or if the referrer is different than Twitter or SurveySocket. But if the referrer matches one of the two domains, the question1 will be skipped.

Here’s is the final survey model:

{
  "pages": [
    {
      "name": "page1",
      "elements": [
        {
          "type": "radiogroup",
          "name": "question1",
          "visibleIf": "referrerUrl() != 't.co' && referrerUrl() != 'surveysocket.com'",
          "title": "How did you find out about our survey?",
          "choices": [
            {
              "value": "item1",
              "text": "SurveySocket"
            },
            {
              "value": "item2",
              "text": "Twitter"
            }
          ]
        },
        {
          "type": "radiogroup",
          "name": "question2",
          "visibleIf": "{question1} = 'item1' || referrerUrl() = 'surveysocket.com'",
          "title": "Did you find the SurveySocket site useful?",
          "choices": [
            {
              "value": "item1",
              "text": "Yes"
            },
            {
              "value": "item2",
              "text": "Absolutely"
            }
          ]
        },
        {
          "type": "dropdown",
          "name": "question3",
          "visibleIf": "{question1} = 'item2' || referrerUrl() = 't.co'",
          "title": "How long have you been using Twitter?",
          "choices": [
            {
              "value": "item1",
              "text": "Less than a year"
            },
            {
              "value": "item2",
              "text": "1 to 5 years"
            },
            {
              "value": "item3",
              "text": "More than 5 years"
            }
          ]
        }
      ]
    }
  ]
}

See it in action

Visit the survey without a referrer (Bitly url shortener used)

Visit the survey with SurveySocket as a referrer

Visit the survey through Twitter


How We Can Help

We offer expert advice on architecture, provide training for SurveyJS and the Endatix backend, and assist with development and implementation of your solution. Feel free to contact us—we're passionate about software and always happy to chat!

  Contact us