Guide
Next.js
Next.js Integration
Server and client-side rendering options
đź’ˇ Server vs Client Rendering
Server Component (SSR): The iframe renders on the server. Add ?ssr=1 to prevent double-counting views. Views are tracked client-side when the ad actually renders in the browser.
Client Component (CSR): The iframe renders in the browser. Standard tracking applies—each iframe load counts as a view.
⚠️ Always use ?ssr=1 for server-rendered iframes to ensure accurate analytics!
1 Server Component (Recommended)
Use this in any Server Component. No 'use client' directive needed.
// components/BeaverAd.tsx
export default function BeaverAd() {
return (
<div className="beaver-ad-container">
<iframe
src="https://example.com/ad-slot?ssr=1"
width={280}
height={90}
style={{ border: 'none', overflow: 'hidden' }}
frameBorder="0"
scrolling="no"
loading="lazy"
/>
</div>
);
} Note: The ?ssr=1 parameter tells Beaver.ad to track the view client-side instead of on the server fetch. This prevents SSR builds from inflating view counts.
2 Client Component with Lazy Loading
Use this for dynamic loading and visibility tracking.
'use client';
import { useEffect, useRef, useState } from 'react';
export default function BeaverAdClient() {
const containerRef = useRef<HTMLDivElement>(null);
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
observer.disconnect();
}
},
{ rootMargin: '100px' }
);
if (containerRef.current) {
observer.observe(containerRef.current);
}
return () => observer.disconnect();
}, []);
return (
<div ref={containerRef} className="beaver-ad-container">
{isVisible && (
<iframe
src="https://example.com/ad-slot"
width={280}
height={90}
style={{ border: 'none', overflow: 'hidden' }}
frameBorder="0"
scrolling="no"
/>
)}
</div>
);
} Client-only: No ?ssr=1 needed since the iframe only loads in the browser. Views are automatically tracked correctly.
3 Dynamic Import (Code Splitting)
Load ads asynchronously to reduce initial bundle size.
import dynamic from 'next/dynamic';
const BeaverAd = dynamic(() => import('@/components/BeaverAdClient'), {
loading: () => <div className="h-24 bg-gray-200 animate-pulse rounded" />,
ssr: false
});
export default function HomePage() {
return (
<main>
<h1>Welcome</h1>
<BeaverAd />
</main>
);
}