Enable Embedding for Testing

Your site is blocking preview embeds. Here's how to fix it — or work around it.

Test Your Embed

Want to check if your iframe is working? Enter your URL below:

Why This Happens

Most modern websites block embedding by default to prevent clickjacking attacks. This is controlled by HTTP headers like X-Frame-Options and Content-Security-Policy.

If you own the site, enabling embedding takes about 1 minute. If you don't, there are workarounds below.

For Developers (1-Minute Fix)

Add a Content-Security-Policy header that allows embedding from our domain. Choose your framework below.

Next.js

Add to your next.config.js:

/** @type {import('next').NextConfig} */
const nextConfig = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          {
            key: 'Content-Security-Policy',
            value: "frame-ancestors 'self' https://zebra.day;"
          }
        ]
      }
    ];
  }
};

module.exports = nextConfig;

Vercel

Add to your vercel.json:

{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "Content-Security-Policy",
          "value": "frame-ancestors 'self' https://zebra.day;"
        }
      ]
    }
  ]
}

Netlify

Add to your netlify.toml:

[[headers]]
  for = "/*"
  [headers.values]
    Content-Security-Policy = "frame-ancestors 'self' https://zebra.day;"

Or add a _headers file in your publish directory.

Express.js / Node.js

// Using helmet
const helmet = require('helmet');

app.use(
  helmet({
    contentSecurityPolicy: {
      directives: {
        frameAncestors: ["'self'", "https://zebra.day"]
      }
    },
    frameguard: false
  })
);

// Or manual middleware
app.use((req, res, next) => {
  res.setHeader(
    'Content-Security-Policy',
    "frame-ancestors 'self' https://zebra.day"
  );
  next();
});
Other Frameworks (Django, Rails, Laravel)

Django

# settings.py
MIDDLEWARE = [
    'myapp.middleware.FrameAncestorsMiddleware',
    # Remove XFrameOptionsMiddleware
]

# myapp/middleware.py
class FrameAncestorsMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        response['Content-Security-Policy'] = (
            "frame-ancestors 'self' https://zebra.day"
        )
        return response

Ruby on Rails

# config/initializers/content_security_policy.rb
Rails.application.config.content_security_policy do |policy|
  policy.frame_ancestors :self, "https://zebra.day"
end

Laravel

// app/Http/Middleware/SecurityHeaders.php
public function handle($request, $next)
{
    $response = $next($request);
    $response->headers->set(
        'Content-Security-Policy',
        "frame-ancestors 'self' https://zebra.day"
    );
    return $response;
}

Security Note

Only whitelist domains you trust. Using frame-ancestors * allows any site to embed yours, which can enable clickjacking attacks.

For Designers

Design tools like Figma have built-in embedding that works without any configuration.

Figma Prototypes

Figma prototypes embed directly — no code changes needed.

  1. 1. Open your Figma file
  2. 2. Click Share → set to “Anyone with the link can view”
  3. 3. Click the prototype tab and copy the prototype link
  4. 4. Paste the link when creating your test in Zebra

Prototype URL format:

https://www.figma.com/proto/FILE_KEY/...

Other Design Tools

ToolEmbed Support
FigmaWorks out of the box
FramerWorks with share link
ProtoPieWorks with cloud link
Adobe XDLimited (being phased out)

Don't Own the Site?

If you can't modify the site's headers, here are your options.

1

Convert the Website to a Figma Prototype

Use html.to.design by ‹div›RIOTS to capture any website as an editable Figma file.

  1. 1. Install the html.to.design Chrome extension
  2. 2. Navigate to the website you want to test
  3. 3. Click the extension → “Capture Page”
  4. 4. Open Figma and install the html.to.design Figma plugin
  5. 5. Import the captured file into Figma
  6. 6. Add prototype interactions if needed
  7. 7. Share the Figma prototype link in Zebra

Best for: Testing visual design, navigation, and first impressions. The prototype won't have real functionality but works great for click-through tests.

2

Screenshot Key Screens → Build in Figma

Capture full-page screenshots and assemble them as a clickable Figma prototype.

  1. 1. Use a tool like ScreenshotOne, Urlbox, or browser DevTools to capture full-page screenshots
  2. 2. Import screenshots into Figma as frames
  3. 3. Add hotspot links between frames to create navigation
  4. 4. Share the prototype link in Zebra

Best for: Quick tests when you only need a few key screens, or when html.to.design doesn't capture the page correctly.

3

Automated Capture with Playwright

For technical users: use Playwright to capture screenshots or recordings of user flows, then convert to a Figma prototype.

import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage();

// Capture a flow
await page.goto('https://target-site.com');
await page.screenshot({
  path: '01-homepage.png',
  fullPage: true
});

await page.click('button.signup');
await page.screenshot({
  path: '02-signup.png',
  fullPage: true
});

await page.fill('input[name="email"]', 'test@example.com');
await page.screenshot({
  path: '03-form-filled.png',
  fullPage: true
});

await browser.close();

Best for: Capturing complex flows with multiple states, authenticated pages, or dynamic content.

Testing Your Changes

After adding the headers, verify embedding works:

  1. 1. Deploy your changes
  2. 2. Open browser DevTools → Network tab
  3. 3. Load your site and click on the main document request
  4. 4. Check Response Headers for Content-Security-Policy
  5. 5. Verify it includes frame-ancestors 'self' https://zebra.day

Then try creating a new test in Zebra — the preview should load correctly.

Still Having Issues?

Some common gotchas:

  • CDN caching: Headers might be cached. Try purging your CDN cache or wait a few minutes.
  • Multiple CSP sources: If you have other CSP directives, make sure frame-ancestors isn't being overwritten.
  • Hosting platform defaults: Some platforms set restrictive defaults. Check your platform's security settings.
  • Localhost testing: If testing locally, embedding usually works fine — the issue is typically only on production.

Continue Reading