Implement Visitor pulse

Visitor pulse is available as an advanced, configurable solution. This means that a lot of the options will be configurable by non-technical users and they will be able to see a default preview, but any customization will need to be done by technical users.

When a new experience is created for this solution, the technical implementation will be provided with a template for the technical user to get started. This page will give further details of the code in the template and the module it uses.

Building the experience

▸ Create and configure a new Visitor pulse experience.

Refer to Building Visitor Pulse Experiences if you are unsure how to do this

Example implementations

Here are two example implementations, both inside and outside of a modal. The default template seen in the editor will be the modal version, but you can render the solution into any DOM node. More details on the '@qubit/visitor-pulse' module are provided below.

Inside modal

function variation (options) {
  var createVisitorPulse = require('@qubit/visitor-pulse')

  // Require and create a modal inside which the solution will be shown. It will be rendered by default.
  var modal = require('@qubit/advanced-modal')({
    className: 'qubit-VisitorPulse-modal',
    windowScrollable: true
  })

  // Please see the docs for more information - 'https://docs.qubit.com/content/using-qubit/experiences-visitor-pulse-implementation'.
  var visitorPulse = createVisitorPulse({
    container: '.qubit-AdvancedModal-body', // The DOM element in which to render the component, or a unique CSS3 selector for that DOM element.
    experienceId: options.meta.experienceId,
    eventHandlers: { // Override event handlers.
      onClose: function () {
        // Set a cookie here to prevent the solution from being shown to people that have closed it, or that have already submitted.
      }
    },
    renderers: {}, // Override question type renderers.
    thankYou: { // Default options for the thank you page. Will be shown on submit unless you override the `onSubmit` handler.
      showFor: 3000,
      fadeOut: 500
    },
    solutionSettings: options.solution
  })

  // Render the solution. Note that you can pass in your own HTML string to this function to override the default template.
  // This will prevent any event listeners from being set if they don't match the default template class names. See 'Default template class names' in the docs.
  visitorPulse.render()
  options.onRemove(() => visitorPulse.destroy())
}

Outside modal

function variation (options) {
  var createVisitorPulse = require('@qubit/visitor-pulse')

  // Please see the docs for more information - 'https://docs.qubit.com/content/using-qubit/experiences-visitor-pulse-implementation'.
  var visitorPulse = createVisitorPulse({
    container: document.body, // The DOM element in which to render the component, or a unique CSS3 selector for that DOM element.
    experienceId: options.meta.experienceId,
    eventHandlers: { // Override event handlers.
      onClose: function () {
        // Set a cookie here to prevent the solution from being shown to people that have closed it, or that have already submitted.
      }
    },
    renderers: {}, // Override question type renderers.
    thankYou: { // Default options for the thank you page. Will be shown on submit unless you override the `onSubmit` handler.
      showFor: 3000,
      fadeOut: 500
    },
    solutionSettings: options.solution
  })

  // Render the solution. Note that you can pass in your own HTML string to this function to override the default template.
  // This will prevent any event listeners from being set if they don't match the default template class names. See 'Default template class names' in the docs.
  visitorPulse.render()
  options.onRemove(() => visitorPulse.destroy())
}

The @qubit/visitor-pulse module

Overriding individual renderers

This functionality is used to specify your own HTML for one or more of the question types, without having to rebuild the whole solution from scratch. Each overridden renderer should take the form of a function that returns an HTML string, passed into the solution options via the renderers object, with the key being the name of one of the following currently available question types:

  • score
  • radio
  • checkbox
  • textarea

Example:

{
  renderers: {
    // Each renderer is given the question object and the question number to
    // render. It should return an HTML string.
    textarea: function renderTextarea (question, questionNumber) {
      var placeholder = question.placeholder || 'Type your answer here'
      return [
        '<div class="a-custom-class">',
        '<img src="/a/custom/image.jpg" />',
        '<textarea class="qubit-VisitorPulse-textarea" placeholder="' + placeholder + '"></textarea>',
        '</div>'
      ].join('')
    }
  }
}

DANGER: If you override any of the renderers or the entire render method, you will most likely have to override the getResponses method, which is responsible for retrieving responses from the DOM before the events get sent.

See API for the format in which the object returned from this method should be. You should also try to use the default template class names as listed below.

Override the entire render method

You can also provide an entirely custom render method via the options: render: function () {}. This should return a valid HTML string.

Default template class names

These are the class names of the top level DOM elements for the various question types in the default solution template.

  • score: 'qubit-VisitorPulse-score'
  • radio: 'qubit-VisitorPulse-radio'
  • checkbox: 'qubit-VisitorPulse-checkContainer'
  • textarea: 'qubit-VisitorPulse-textarea'

These are also useful to know when customizing the styling of the default template. Of course you can preview the solution and use the DOM inspector to see the class names of any sub-elements.

Overriding event handlers

This is for altering the behavior when a user interacts with certain elements of the solution. The value of each handler is a function.

onScoreClick

By default, this handler will select the clicked on target and de-select all of the others.

onRadioClick

By default, this handler will select the clicked on target and de-select all of the others. If the target is an 'Other' option, it will show an additional text area. If it isn't an 'Other' option, it will hide the additional text area.

onCheckboxClick

By default, this handler will toggle the selection state of the clicked on target. If the target is an 'Other' option, it will toggle the rendering of an additional text area.

onSubmit

This gets called when the user selects the submit button. Nothing will happen if the user hasn't submitted any responses. If there are responses, they will always be sent.

By default, a thank you page will be shown for 3 seconds but you can pass in alternative timing via the thankYou option. If you override this handler, your function will be called after the events are sent and the thank you page will not be rendered, nor will the solution close until you tell it to.

onClose

This handler is called after submission, or after the custom onSubmit handler is called.

Example:

{
  eventHandlers: {
    onSubmit: function (event, callback) {
      // Some behavior followed by calling the callback. `onSubmit` is the only handler where this is required.
      // Note that if you override submit, the solution won't be removed anymore by default.
      callback()
    },
    onScoreClick: function (e) {},
    onRadioClick: function (e) {},
    onCheckboxClick: function (e) {}
  }
}

API

Calling the module (passing in the options) returns an object with the following methods:

render

Renders the solution, and will be set to options.render if added, otherwise it will render the default template if no html is passed as the first parameter.

Parameter

Type

Example

Html

String

visitorPulse.render('<div>Survey</div>') // A sparse implementation

destroy

Unbinds events and remove the solution from the DOM.

send

Sends events based on the given solution options and responses.

Fires events for each question, with or without a response. It handles each question differently according to type.

Multiple choice questions, using radio buttons or checkboxes, have an event fired for each choice, regardless of whether it is selected or not.

You can see the events that get fired on submission, or from calling this API method, via window.__qubit.uv.events or window.uv.events.

Parameter

Type

Example

Experience (experienceId)

Number

This can be found on the options object that is passed into the advanced mode execution or activation code options.meta.experienceId

Survey solutionSettings (solutionSettings)

Object

The solution settings object from options.solution, passed in to the advanced mode execution or activation code

Responses (responses)

Object

A simple object with question Ids for keys and user responses for values

You can use the API method getResponses to populate this parameter if you are using the default template, or you can manually retrieve the responses from the DOM


A focus on Responses

For multiple choice type questions, using radio buttons or checkboxes, the value of Responses must be an object containing all checked/selected choices with Ids as keys and true as the value.

For checkbox type questions, where between none or all choices can be selected, all the checked choices need to be included.

You can use the API method getResponses to populate this parameter, or manually retrieve the responses from the DOM.

Example:

{
  'scoreId': 10,
  'checkboxId': {
    'checkedStandardId': true,
    'checkedOtherId': true,
    'other': 'ABCDEF'
  },
  'radioId': {
    'selectedChoiceId': true
  },
  'textareaId': 'VERY LIKELY'
}

The question and choice Ids are available in solutionSettings.json. They should be attached to the DOM elements if you override the render method, so that you can retrieve the responses in your getResponses function.

{
  "0qcJnG6rPrq": "9", // Score type question.
  "mZf1VjERn8l": { // Radio type question.
    "jQclznpyqDN": "To buy something"
  },
  "xh3njA7Ke4C": { // Radio type question where the other option was answered.
    "kRRlsYDOmqQAz": true,
    "other": "Something else"
  },
  "Y6hkKLGA6gz": { // Checkbox type question.
    "Vpc0VxOgPX7": "I like cats",
    "XDfBlXpOMGx": "I like dogs",
    "58hgyZq64gr": "I like sharks"
  },
  "kZiYDOm5yQG": "No" // Textarea type question.
}

getResponses

Get current responses from the DOM. This methods uses an implementation that works with the default template, unless you provide your own via options.getResponses.

This method also gets called when the submit button gets is selected so that the events are sent with the responses.

See the example getResponses above for the format in which the response object should be returned from this function.

Events

Whenever a visitor submits a survey, events will be generated and sent, unless you override the submit handler, in which case you should call the send function of the module directly.

You can verify that they have been sent by checking window.__qubit.uv.events or window.uv.events in the console.

Last updated: October 2021
Did you find this article useful?