Integrating Termly With Nuxt 3

 Jul 11, 2024 ·  3min read

Technology Tutorials

Integrating Termly’s consent management with Nuxt 3 turns out to be harder than just inserting a script tag. Here’s a solution that resolves hydration mismatches and UI glitches, ensuring smooth functionality and user experience.


The Challenge 

When building modern web applications, consent management is crucial for compliance with privacy regulations like GDPR. Termly offers a popular solution, but integrating it with a server-side rendered (SSR) framework like Nuxt 3 presents unique challenges.

Initially, adding Termly’s script to PrioMind, our application powered by Nuxt 3, seemed straightforward:

// app.vue
<script setup lang="ts">
useHead({
  script: [
    {
      src: "https://app.termly.io/resource-blocker/[yourId]",
      defer: true,
    }
  ]
})
</script>

However, this led to several issues:

  1. Hydration mismatches, leading to appearing, then disappering of the consent banner
  2. Nuxt UI notifications rendering incorrectly
Integrating Termly with Nuxt was a bit like mixing fire and water: It didn’t mesh quite right.

Understanding the Problem 

The root of these issues lies in the conflict between server-side rendering and client-side scripting. Nuxt 3, being an SSR framework, renders the initial HTML on the server. When Termly’s script runs on the client, it injects content that wasn’t present in the server-rendered HTML, causing hydration mismatches.

Moreover, the script’s positioning and execution timing affected other UI elements, particularly Nuxt UI notifications.

The Solution 

The following is a solution that addresses these issues:

// app.vue
<script setup lang="ts">
import { ref, onMounted } from 'vue'

const termlyLoaded = ref(false)

onMounted(() => {
  if (document.querySelector('script[src*="app.termly.io/resource-blocker"]')) {
    termlyLoaded.value = true
    return
  }

  const script = document.createElement('script')
  script.src = 'https://app.termly.io/resource-blocker/[yourId]?autoBlock=on'
  script.async = true
  script.onload = () => {
    termlyLoaded.value = true
  }

  const firstScript = document.getElementsByTagName('script')[0]
  if (firstScript && firstScript.parentNode) {
    firstScript.parentNode.insertBefore(script, firstScript)
  } else {
    document.head.appendChild(script)
  }
})
</script>

<template>
  <div>
    <ClientOnly>
      <div v-if="termlyLoaded" id="termly-code-snippet-support"></div>
    </ClientOnly>
    <NuxtPage />
    <UNotifications />
  </div>
</template>

Let’s break down the key aspects of this solution:

  1. Client-side script loading: It loads the Termly script dynamically in the onMounted hook, ensuring it only happens on the client side.

  2. Early script insertion: It attempts to insert the script as early as possible in the document to address Termly’s positioning warning.

  3. Conditional rendering: It uses a termlyLoaded ref to conditionally render the Termly support div, preventing it from appearing before the script has loaded.

  4. Error handling: It includes checks and a fallback method for script insertion to handle various edge cases.

The Result 

This solution resolves the hydration mismatches, fixes the notification rendering issues, and ensures Termly loads as early as possible. The consent management banner now coexists peacefully with the rest of our Nuxt 3 application.

Lessons Learned 

  1. SSR and client-side scripts require careful handling: When integrating third-party scripts in an SSR environment, consider their execution timing and impact on hydration.

  2. Conditional rendering is powerful: Using ClientOnly and reactive variables to control rendering can prevent many hydration issues.

  3. Error handling is crucial: Always include fallback options and error checks, especially when dealing with dynamic script insertion.

Conclusion 

Integrating third-party scripts like Termly into a Nuxt 3 application can be challenging, but with a thoughtful approach, it’s possible to achieve seamless integration. By understanding the interplay between server-side rendering and client-side scripting, we can develop solutions that maintain the benefits of both while avoiding common pitfalls.

About the Author

Michael Schmidle

Founder of PrioMind. Start-up consultant, hobby music producer and blogger. Opinionated about technology, strategy, and leadership. In love with Mexico. This blog reflects my personal views.

 LinkedIn  GitHub  SoundCloud

Recommended Articles

 Nov 15, 2023 ·  2min read

Mastering Keyboard Interactions in Shadcn-Vue: A Fix for Complex UIs

In the intricate dance of UI components within Vue applications, a misstep can disrupt the rhythm. Discover how a straightforward tweak can harmonize your keyboard interactions in shadcn-vue in complex nested components. Continue…

Technology Tutorials


 Sep 26, 2023 ·  Nov 11, 2023 ·  2min read

The Better Nuxt Directus Authentication Middleware

The Nuxt Directus docs give you a basic auth middleware, but it’s got some quirks. Here’s how to bulletproof it. Continue…

Technology Tutorials


 Apr 18, 2020 ·  6min read

Accelerate Your Website—With Your Logo

Most people who care about their website’s performance probably use a website logo created by vector graphics software. Here’s how to take advantage of vectorized logos to speed up your website. Seriously. Continue…

Technology Tutorials


 Aug 18, 2019 ·  May 14, 2020 ·  6min read

Unhide Virtual Network Adapters in Windows 10

In Windows’ latest releases, Microsoft hides virtual adapters and networks by default. In some cases though, you need them to be available just like regular adapters and networks. Continue…

Technology Tutorials