Reduce the impact of third-party code (zendesk)
Asked Answered
B

3

6

enter image description here

<script
  id="ze-snippet"
  src="https://static.zdassets.com/ekr/snippet.js?key=some_zendesk_key"
/>

I'm trying to optimize my web site performance. I've faced a big impact of third-party code to my performance, I think all my bundle has a lower size than zendesk code. How can I load it without impacting on the main thread? Should I use the async or defer tags? Or which approach is better for this case?

Bifocal answered 20/10, 2019 at 8:23 Comment(2)
IIRC, I have tried using async tags in my development with the Zendesk Chat, and it just causes so many problems. I've basically come to the conclusion that there is no way for this script not to impact your performance because it simply loads so many other scripts.Looselimbed
Same here. I am loading this script in a react gatsby application. Funny thing is that if you run audits to zendesk.com, the size is 354 KB and blocking time 638 ms. I get the feeling that audits are too sensitive though, as the real feel of the loading time is actually good.Polyhymnia
P
1

This seems to be an issue that tortures so many people without a clear solution.

What I managed to do it to reduce the block time by adding this configuration.

window.zESettings = {
    webWidget: {
      chat: {
        connectOnPageLoad: false
      }
    }
  };

ref https://developer.zendesk.com/embeddables/docs/widget/settings#connectonpageload

ps I did a performance test to my zendesk helpdesk "domain.zendesk.com" and the results there were even worse

enter image description here

Polyhymnia answered 11/5, 2020 at 13:22 Comment(0)
P
1

I came across this issue recently and made this hack using a function for loading the zendesk script only when you reached certain point of the doc. I know is kind of dirty but it works:

<script defer type="text/javascript">
    (function($, win) {
        $.fn.inViewport = function(cb) {
            return this.each(function(i,el){
                function visPx(){
                    var H = $(this).height(),
                    r = el.getBoundingClientRect(), t=r.top, b=r.bottom;
                    return cb.call(el, Math.max(0, t>0? H-t : (b<H?b:H)));  
                }  visPx();
                $(win).on("resize scroll", visPx);
            });
        };
    }(jQuery, window));


$('#trigger_div').inViewport(function(px){
    if(px) {

    //zopim code

    }
});

Prisage answered 2/6, 2020 at 17:25 Comment(0)
S
1

Starting from this article https://www.newmediacampaigns.com/blog/maintaining-great-site-performanc-using-zendesk-web-widget I have implemented a solution that significantly reduces the load time by at least 3 seconds (in Google Lighthouse).

I have created a fake button in the HTML that will load the Zendesk script and open the widget when clicked. It will also load a localStorage item that will prevent this from happening on subsequent page loads.

⚠️ Warning:

The code relies heavily on how the widget is currently implemented (for example it expects a #launcher and a #webWidget element to appear on the page), so it can break as soon as the original code changes, but at least we will have an improvement in the loading times until they fix it.

Here is the most important part of the code:

HTML Button

<button class="zendesk-button">
  <span class="left-icon">
    <!-- here you insert the icon -->
  </span>
  <span class="text">Chat</span>
</button>

JavaScript code

// select the button
const zendeskButton = document.querySelector('.zendesk-button');

// add the script to the page
const loadZendeskScript = () => {
  const zenDeskScript = document.createElement("script");
  zenDeskScript.id = "ze-snippet";
  zenDeskScript.src = "https://static.zdassets.com/ekr/snippet.js?key=HERE_YOU_INSERT_YOUR_KEY";
  (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0] || document.getElementsByTagName('script')[0].parentNode).insertBefore(zenDeskScript, null);
};

// a poller that waits for a condition and executes a callback
const poller = (comparison, callback, timerStep = 250, maxTime = 5000) => {
  // why setTimeout instead of setInterval
  // https://mcmap.net/q/267764/-using-setinterval-to-do-simplistic-continuous-polling
  let currTime = 0;
  const checkCondition = () => {
    // `comparison` is a function so the condition is always up-to-date
    if (comparison() === true) {
      callback();
    } else if (currTime <= maxTime) {
      currTime += timerStep;
      setTimeout(checkCondition, timerStep);
    }
  };
  checkCondition(); // calling the function
};

// load the script and execute a callback if provided
const loadZendeskChat = callback => {
  loadZendeskScript();
  if (callback) {
    callback();
  }
};

// this function opens the chat
const openZendeskChat = () => {
  poller(
    () => {
      // check that zendesk-related functions are available
      return typeof zE !== 'undefined';
    },
    () => {
      // open the widget
      zE('webWidget', 'open');
      poller(
        () => {
          // check that the elements exist and that the opacity is already set to "1"
          const launcher = document.querySelector('#launcher');
          const webWidget = document.querySelector('#webWidget');
          return launcher !== null && webWidget !== null && webWidget.style.opacity === '1';
        },
        () => {
          // hide the fake button
          zendeskButton.style.opacity = '0';
          // save in localStorage
          localStorage.setItem('zd_hasOpened', 'true');
        }
      );
    }
  );
};

// zendesk management
if (localStorage.getItem('zd_hasOpened')) {
  // load the zendesk widget if we find that it was opened
  loadZendeskChat();
} else {
  // show the fake button if it's the first time it shows
  zendeskButton.style.opacity = '1';
}
// This will run when the .zendesk-button element is clicked
zendeskButton.addEventListener('click', () => {
  // add a 'Loading' text to the button, as the widget will take some time to load (between 1 and 2 seconds on my laptop)
  zendeskButton.querySelector('.text').innerHTML = 'Loading';
  // load the zendesk widget
  // open the widget and hide the fake button
  loadZendeskChat(openZendeskChat);
});

Regarding styles, I have pretty much copied the style in the original widget, converting ems to pixels, but one part I'd like to highlight is the focus style, because in my opinion it helps telling the user that something is happening.

.zendesk-button:focus {
  outline: none;
  box-shadow: inset 0 0 0 0.21429rem rgb(255 255 255 / 40%) !important;
}
Saltern answered 19/4, 2021 at 15:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.