Guide

Nuxt

Nuxt Integration

Vue 3 with SSR/CSR flexibility

💡 Server vs Client Rendering

Server Rendering (SSR): Add ?ssr=1 to the iframe URL for accurate view tracking. Views are counted client-side when actually rendered.

Client-Only: Use <ClientOnly> to render only in the browser. No special parameters needed.

âš ī¸ Always use ?ssr=1 for SSR to prevent double-counting!

1 Basic Component (SSR)

A simple Vue component that renders on the server for optimal performance.

<!-- components/BeaverAd.vue -->
<template>
  <div class="beaver-ad-container">
    <iframe
      src="https://your-beaver-ad.com/s/slot-id?ssr=1"
      width="280"
      height="90"
      :style="{ border: 'none', overflow: 'hidden' }"
      frameborder="0"
      scrolling="no"
      loading="lazy"
    />
  </div>
</template>

<script setup lang="ts">
// No client-side logic needed for basic SSR
// The ?ssr=1 parameter ensures accurate view tracking
</script>

SSR Mode: The ?ssr=1 parameter prevents server-side fetches from counting as views. The actual view is tracked when the iframe loads in the browser.

2 Client-Only Rendering

Use Nuxt's <ClientOnly> wrapper to prevent SSR and render only on the client.

<!-- pages/index.vue -->
<template>
  <div>
    <h1>Welcome to my site</h1>
    
    <ClientOnly>
      <BeaverAd />
      
      <template #fallback>
        <div 
          class="animate-pulse bg-stone-200 rounded"
          style="width: 280px; height: 90px"
        />
      </template>
    </ClientOnly>
  </div>
</template>

3 Lazy Load with Intersection Observer

Load ads only when visible for better performance.

<!-- components/BeaverAdLazy.vue -->
<template>
  <div ref="containerRef" class="beaver-ad-container">
    <iframe
      v-if="isVisible"
      src="https://your-beaver-ad.com/s/slot-id"
      width="280"
      height="90"
      :style="{ border: 'none', overflow: 'hidden' }"
      frameborder="0"
      scrolling="no"
    />
    <div 
      v-else 
      class="animate-pulse bg-stone-200 rounded"
      style="width: 280px; height: 90px"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';

const containerRef = ref<HTMLElement | null>(null);
const isVisible = ref(false);

onMounted(() => {
  const observer = new IntersectionObserver(
    ([entry]) => {
      if (entry.isIntersecting) {
        isVisible.value = true;
        observer.disconnect();
      }
    },
    { rootMargin: '100px' }
  );

  if (containerRef.value) {
    observer.observe(containerRef.value);
  }

  onUnmounted(() => observer.disconnect());
});
</script>