SayWall
Documentation

Embedding Widgets

Add SayWall testimonial widgets to any website in minutes using Shadow DOM or legacy iframe embed.

Updated March 12, 2026

Quick Start

Get your testimonial widget live in under 5 minutes.

1
Copy your embed code

In the SayWall dashboard, go to Widgets, open your widget, and click the Embed tab. Copy the two-line snippet shown there.

2
Paste into your HTML

Paste the snippet anywhere in your page's <body>. It renders in place, so put it exactly where you want the widget to appear.

<script src="https://saywall.io/embed.min.js" async></script>
<div data-saywall-widget="YOUR_WIDGET_ID"></div>
3
See your widget appear

Save and reload your page. The widget loads asynchronously — it won't block your page render. You should see your approved testimonials appear within a second or two.

HTML vs React/Next.js

<!-- Place once in <head> or <body> -->
<script src="https://saywall.io/embed.min.js" async></script>
 
<!-- Place where you want the widget -->
<div data-saywall-widget="YOUR_WIDGET_ID"></div>

The async attribute ensures the script loads without blocking your page.

How Shadow DOM Works

SayWall widgets use Shadow DOM by default. The widget renders inside an isolated shadow tree attached to your <div>, completely separate from your page's CSS.

Why Shadow DOM? Your page styles can't accidentally break the widget, and the widget styles can't leak into your page. No CSS conflicts, ever.

When embed.min.js initialises:

  1. It fetches the widget fragment from https://saywall.io/w/YOUR_WIDGET_ID?shadow=1
  2. Attaches a shadow root to your <div>
  3. Injects the widget CSS + HTML into the shadow root
  4. Loads any required fonts or scripts (for carousel or video widgets) into the parent <head> — deduplicated if multiple widgets share the same resource

Because the shadow root is isolated, you can embed multiple widgets on the same page without any interference.

Lazy Loading

Add data-lazyload="true" to defer the widget until it enters the viewport:

<div data-saywall-widget="YOUR_WIDGET_ID" data-lazyload="true"></div>

This is useful for widgets below the fold — it skips the network request entirely until the user scrolls close to the widget. Powered by IntersectionObserver.

CSP Requirements

Content Security Policy: The Shadow DOM embed requires script-src 'unsafe-eval' in your CSP.

Add this to your Content-Security-Policy header:

script-src 'self' https://saywall.io 'unsafe-eval';

If your CSP policy prohibits unsafe-eval, use the Legacy iframe embed instead — it runs in a sandboxed iframe and does not require unsafe-eval.

Legacy iframe Embed

For sites with strict CSPs or where Shadow DOM isn't suitable, SayWall also supports a legacy iframe embed.

The iframe embed is fully supported and will continue to work. Shadow DOM is the default because it provides better visual fidelity and has no iframe-sizing quirks, but both modes are maintained.

<script src="https://saywall.io/embed.min.js" async></script>
<iframe
  data-saywall-widget
  src="https://saywall.io/w/YOUR_WIDGET_ID"
  style="border: none; width: 100%;"
  loading="lazy"
></iframe>

The script automatically detects the iframe and handles height resizing via postMessage.

Frequently Asked Questions

Start collecting testimonials for free

Set up in minutes. No credit card required.

Get started free

Need help?

Have a question or need assistance? Reach us at hello@saywall.io