In this post, we will illustrate how to lazy load your Disqus comments on your Hugo site, so that they show up only once the user scrolls down to the comment section.

This can potentially save a lot of bandwidth for someone viewing your page, since the assets downloaded by Disqus can be quite heavy.

Create Your Own Comments Partial

By default, Hugo uses an internal partial template to render Disqus comments:

 1{{- $pc := .Site.Config.Privacy.Disqus -}}
 2{{- if not $pc.Disable -}}
 3{{ if .Site.DisqusShortname }}<div id="disqus_thread"></div>
 4<script type="application/javascript">
 5  window.disqus_config = function () {
 6  {{with .Params.disqus_identifier }}this.page.identifier = '{{ . }}';{{end}}
 7  {{with .Params.disqus_title }}this.page.title = '{{ . }}';{{end}}
 8  {{with .Params.disqus_url }}this.page.url = '{{ . | html  }}';{{end}}
 9  };
10  (function() {
11    if (["localhost", "127.0.0.1"].indexOf(window.location.hostname) != -1) {
12      document.getElementById('disqus_thread').innerHTML = 'Disqus comments not available by default when the website is previewed locally.';
13      return;
14    }
15    var d = document, s = d.createElement('script'); s.async = true;
16    s.src = '//' + {{ .Site.DisqusShortname }} + '.disqus.com/embed.js';
17    s.setAttribute('data-timestamp', +new Date());
18    (d.head || d.body).appendChild(s);
19  })();
20</script>
21<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
22<a href="https://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>{{end}}
23{{- end -}}

The highlighted lines of code (Lines 15-18) add a script element that renders the Disqus comments within the div element on line 3.

We can copy this code into a new file (layouts/partials/comments.html) in our Hugo codebase. We can then use this partial wherever we’re rendering our comments:

{{/*  somewhere in layouts/_default/single.html, or wherever you render your articles  */}}
    <div>
      Some blog post text
    </div>
  </footer>

  {{- partial "comments.html" . }}
</article>

Using IntersectionObserver to Detect the Users Position on Screen

We can make use of the Intersection Observer API to get notified whenever a DOM element comes into the browsers view.

In this case, we can observe the <div id="disqus_thread"></div> element so that the comments are only loaded when the user reaches this section:

{{- $pc := .Site.Config.Privacy.Disqus -}}
{{- if not $pc.Disable -}}
{{ if .Site.DisqusShortname }}<div id="disqus_thread"></div>
<script type="application/javascript">
    window.disqus_config = function () {
    {{with .Params.disqus_identifier }}this.page.identifier = '{{ . }}';{{end}}
    {{with .Params.disqus_title }}this.page.title = '{{ . }}';{{end}}
    {{with .Params.disqus_url }}this.page.url = '{{ . | html  }}';{{end}}
    };
    (function () {
        // create a new observer, with a callback defined
        let observer = new IntersectionObserver((e) => {
          // e refers to the event fired when the element
          // intersects
          if (!e || !e[0] || !e[0].isIntersecting) {
            // if the element doesn't intersect, return 
              return
          }
          // if the element intersects, insert the disqus script
          var d = document, s = d.createElement('script'); 
          s.async = true
          s.src = '//' + {{ .Site.DisqusShortname }} + '.disqus.com/embed.js'
          s.setAttribute('data-timestamp', +new Date());
          (d.head || d.body).appendChild(s)
          // we don't want to do this again if the script is already
          // inserted, so disconnect the observer
          observer.disconnect()
        });

        // start the observer on the disqus container element
        observer.observe(document.getElementById('disqus_thread'))
    })();
</script> 
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="https://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>{{end}}
{{- end -}}

Now the comments will only load once the user reaches the comment section.

For a live demo of this in action, you can look at this very webpage, which is currently built on Hugo!

Results: UX Improvement

Implementing lazy loading for Disqus can reduce the number of downloaded assets substantially during the initial page load.

To measure this, I filtered the number of downloaded assets using the Chrome network tab:

disqus leads to a huge chunk of additional loaded assets

560 kB / 1.1 MB of data transfer and 23 / 44 requests were due to Disqus alone.

Now, these will only be downloaded when they are really needed.