Skip to content

Latest commit

 

History

History
396 lines (302 loc) · 14.7 KB

FEEDBACK.md

File metadata and controls

396 lines (302 loc) · 14.7 KB

Bucket Feedback UI

The Bucket SDK includes a UI you can use to collect feedback from user about particular features.

image

Global feedback configuration

The Bucket SDK feedback UI is configured with reasonable defaults, positioning itself as a dialog in the lower right-hand corner of the viewport, displayed in english, and with a light-mode theme.

These settings can be overwritten when initializing the Bucket SDK:

bucket.init("bucket-tracking-key", {
  feedback: {
    ui: {
      position: POSITION_CONFIG, // See positioning section
      translations: TRANSLATION_KEYS, // See internationalization section

      // Enable Live Satisfaction. Default: `true`
      enableLiveSatisfaction: boolean,

      /**
       * Do your own feedback prompt handling or override
       * default settings at runtime.
       */
      liveSatisfactionHandler: (promptMessage, handlers) => {
        // See Live Satisfaction section
      },
    },
  },
});

See also:

Live Satisfaction

Live Satisfaction is enabled by default.

When Live Satisfaction is enabled, the Bucket SDK will open and maintain a connection to the Bucket service. When a user triggers an event tracked by a feature and is eligible to be prompted for feedback, the Bucket service will send a request to the SDK instance. By default, this request will open up the Bucket feedback UI in the user's browser, but you can intercept the request and override this behaviour.

The live connection for automated feedback is established once you have identified a user with bucket.user().

Disabling Live Satisfaction

You can disable automated collection in the bucket.init()-call:

bucket.init("bucket-tracking-key", {
  feedback: {
    enableLiveSatisfaction: false,
  },
});

Overriding prompt event defaults

If you are not satisfied with the default UI behavior when an automated prompt event arrives, you can can override the global defaults or intercept and override settings at runtime like this:

bucket.init("bucket-tracking-key", {
  feedback: {
    liveSatisfactionHandler: (promptMessage, handlers) => {
      // Pass your overrides here. Everything is optional
      handlers.openFeedbackForm({
        title: promptMessage.question,

        position: POSITION_CONFIG, // See positioning section
        translations: TRANSLATION_KEYS, // See internationalization section

        // Trigger side effects with the collected data,
        // for example posting it back into your own CRM
        onAfterSubmit: (feedback) => {
          storeFeedbackInCRM({
            score: feedback.score,
            comment: feedback.comment,
          });
        },
      });
    },
  },
});

See also:

Manual feedback collection

To open up the feedback collection UI, call bucket.requestFeedback(options) with the appropriate options. This approach is particularly beneficial if you wish to retain manual control over feedback collection from your users while leveraging the convenience of the Bucket feedback UI to reduce the amount of code you need to maintain.

Examples of this could be if you want the click of a give us feedback-button or the end of a specific user flow, to trigger a pop-up displaying the feedback user interface.

bucket.requestFeeback() options

Minimal usage with defaults:

bucket.requestFeedback({
  featureId: "bucket-feature-id",
  title: "How satisfied are you with file uploads?",
});

All options:

bucket.requestFeedback({
  featureId: "bucket-feature-id", // [Required]
  userId: "your-user-id",  // [Optional] if user persistence is enabled (default in browsers),
  companyId: "users-company-or-account-id", // [Optional]
  title: "How satisfied are you with file uploads?" // [Optional]

  position: POSITION_CONFIG, // [Optional] see the positioning section
  translations: TRANSLATION_KEYS // [Optional] see the internationalization section

  // [Optional] trigger side effects with the collected data,
  // for example sending the feedback to your own CRM
  onAfterSubmit: (feedback) => {
    storeFeedbackInCRM({
      score: feedback.score,
      comment: feedback.comment
    })
  }
})

See also:

Positioning and behavior

The feedback UI can be configured to be placed and behave in 3 different ways:

Positioning configuration

Modal

A modal overlay with a backdrop that blocks interaction with the underlying page. It can be dismissed with the keyboard shortcut <ESC> or the dedicated close button in the top right corner. It is always centered on the page, capturing focus, and making it the primary interface the user needs to interact with.

image

Using a modal is the strongest possible push for feedback. You are interrupting the user's normal flow, which can cause annoyance. A good use-case for the modal is when the user finishes a linear flow that they don't perform often, for example setting up a new account.

position: {
  type: "MODAL";
}

Dialog

A dialog that appears in a specified corner of the viewport, without limiting the user's interaction with the rest of the page. It can be dismissed with the dedicated close button, but will automatically disappear after a short time period if the user does not interact with it.

image

Using a dialog is a soft push for feedback. It lets the user continue their work with a minimal amount of intrusion. The user can opt-in to respond but is not required to. A good use case for this behaviour is when a user uses a feature where the expected outcome is predictable, possibly because they have used it multiple times before. For example: Uploading a file, switching to a different view of a visualisation, visiting a specific page, or manipulating some data.

The default feedback UI behaviour is a dialog placed in the bottom right corner of the viewport.

position: {
  type: "DIALOG",
  placement: "top-left" | "top-right" | "bottom-left" | "bottom-right"
  offset?: {
    x?: string | number; // e.g. "-5rem", "10px" or 10 (pixels)
    y?: string | number;
  }
}

Popover

A popover that is anchored relative to a DOM-element (typically a button). It can be dismissed by clicking outside the popover or by pressing the dedicated close button.

image

You can use the popover mode to implement your own button to collect feedback manually.

position: {
  type: "POPOVER",
  anchor: DOMElement
}

Popover feedback button example:

<button id="feedbackButton">Tell us what you think</button>
<script>
  const button = document.getElementById("feedbackButton");
  button.addEventListener("click", (e) => {
    bucket.requestFeedback({
      featureId: "bucket-feature-id",
      userId: "your-user-id",
      title: "How do you like the popover?",
      position: {
        type: "POPOVER",
        anchor: e.currentTarget,
      },
    });
  });
</script>

Internationalization (i18n)

By default, the feedback UI is written in English. However, you can supply your own translations by passing an object to the options to either or both of the bucket.init(options) or bucket.requestFeedback(options) calls. These translations will replace the English ones used by the feedback interface. See examples below.

image

See default english localization keys for a reference of what translation keys can be supplied.

Static language configuration

If you know the language at page load, you can configure your translation keys while initializing the Bucket SDK:

bucket.init("my-tracking-key", {
  feedback: {
    ui: {
      translations: {
        DefaultQuestionLabel:
          "Dans quelle mesure êtes-vous satisfait de cette fonctionnalité ?",
        QuestionPlaceholder:
          "Comment pouvons-nous améliorer cette fonctionnalité ?",
        ScoreStatusDescription: "Choisissez une note et laissez un commentaire",
        ScoreStatusLoading: "Chargement...",
        ScoreStatusReceived: "La note a été reçue !",
        ScoreVeryDissatisfiedLabel: "Très insatisfait",
        ScoreDissatisfiedLabel: "Insatisfait",
        ScoreNeutralLabel: "Neutre",
        ScoreSatisfiedLabel: "Satisfait",
        ScoreVerySatisfiedLabel: "Très satisfait",
        SuccessMessage: "Merci d'avoir envoyé vos commentaires!",
        SendButton: "Envoyer",
      },
    },
  },
});

Runtime language configuration

If you only know the user's language after the page has loaded, you can provide translations to either the bucket.requestFeedback(options) call or the liveSatisfactionHandler option before the feedback interface opens. See examples below.

Manual feedback collection

bucket.requestFeedback({
  ... // Other options
  translations: {
    // your translation keys
  }
})

Live Satisfaction

When you are collecting feedback through the Bucket automation, you can intercept the default prompt handling and override the defaults.

If you set the prompt question in the Bucket app to be one of your own translation keys, you can even get a translated version of the question you want to ask your customer in the feedback UI.

bucket.init("bucket-tracking-key", {
  feedback: {
    liveSatisfactionHandler: (message, handlers) => {
      const translatedQuestion =
        i18nLookup[message.question] ?? message.question;
      handlers.openFeedbackForm({
        title: translatedQuestion,
        translations: {
          // your static translation keys
        },
      });
    },
  },
});

Custom styling

You can adapt parts of the look of the Bucket feedback UI by applying CSS custom properties to your page in your CSS :root-scope.

For example, a dark mode theme might look like this:

image
:root {
  --bucket-feedback-dialog-background-color: #1e1f24;
  --bucket-feedback-dialog-color: rgba(255, 255, 255, 0.92);
  --bucket-feedback-dialog-secondary-color: rgba(255, 255, 255, 0.3);
  --bucket-feedback-dialog-border: rgba(255, 255, 255, 0.16);
  --bucket-feedback-dialog-primary-button-background-color: #655bfa;
  --bucket-feedback-dialog-primary-button-color: white;
  --bucket-feedback-dialog-input-border-color: rgba(255, 255, 255, 0.16);
  --bucket-feedback-dialog-input-focus-border-color: rgba(255, 255, 255, 0.3);
  --bucket-feedback-dialog-error-color: #f56565;

  --bucket-feedback-dialog-rating-1-color: #ed8936;
  --bucket-feedback-dialog-rating-1-background-color: #7b341e;
  --bucket-feedback-dialog-rating-2-color: #dd6b20;
  --bucket-feedback-dialog-rating-2-background-color: #652b19;
  --bucket-feedback-dialog-rating-3-color: #787c91;
  --bucket-feedback-dialog-rating-3-background-color: #3e404c;
  --bucket-feedback-dialog-rating-4-color: #38a169;
  --bucket-feedback-dialog-rating-4-background-color: #1c4532;
  --bucket-feedback-dialog-rating-5-color: #48bb78;
  --bucket-feedback-dialog-rating-5-background-color: #22543d;

  --bucket-feedback-dialog-submitted-check-background-color: #38a169;
  --bucket-feedback-dialog-submitted-check-color: #ffffff;
}

Other examples of custom styling can be found in our development example stylesheet.

Using your own UI to collect feedback

You may have very strict design guidelines for your app and maybe the Bucket feedback UI doesn't quite work for you.

In this case, you can implement your own feedback collection mechanism, which follows your own design guidelines.

This is the data type you need to collect:

{
  /** Customer satisfaction score */
  score?: 1 | 2 | 3 | 4 | 5,
  comment?: string
}

Either score or comment must be defined in order to pass validation in the Bucket tracking API.

Manual feedback collection

Examples of a HTML-form that collects the relevant data can be found in feedback.html and feedback.jsx.

Once you have collected the feedback data, pass it along to bucket.feedback():

bucket.feedback({
  featureId: "bucket-feature-id",
  userId: "your-user-id",
  score: 5,
  comment: "Best thing I"ve ever tried!",
});

Intercepting Live Satisfaction events

When using Live Satisfaction, the Bucket service will, when specified, send a feedback prompt message to your user's instance of the Bucket SDK. This will result in the feedback UI being opened.

You can intercept this behavior and open your own custom feedback collection form:

bucket.init("bucket-tracking-key", {
  feedback: {
    liveSatisfactionHandler: async (promptMessage, handlers) => {
      // This opens your custom UI
      customFeedbackCollection({
        // The question configured in the Bucket UI for the feature
        question: promptMessage.question,
        // When the user successfully submits feedback data.
        // Use this instead of `bucket.feedback()`, otherwise
        // the feedback prompt handler will keep being called
        // with the same prompt message
        onFeedbackSubmitted: (feedback) => {
          handlers.reply(feedback);
        },
        // When the user closes the custom feedback form
        // without leaving any response.
        // It is important to feed this back, otherwise
        // the feedback prompt handler will keep being called
        // with the same prompt message
        onFeedbackDismissed: () => {
          handlers.reply(null);
        },
      });
    },
  },
});