Discussion on your site
Paste the code into the page — a discussion block appears where its container is. Everything else lives inside our frame: your markup, styles and scripts stay as they are.
Try it on your page
Ready code
<div data-vpvd-thread data-url="https://example.org/article" data-lang="en" data-theme="auto"> <a href="https://vpvd.io/embed/en?url=https%3A%2F%2Fexample.org%2Farticle&theme=auto" target="_blank" rel="noopener">Open the discussion on vpvd</a> </div> <script src="https://vpvd.io/embed.js" async referrerpolicy="no-referrer"></script>
What your readers will see
Where to paste it
- Static sites and custom templates
- WordPress
- Tilda
- Next.js, Nuxt, React
<div data-vpvd-thread data-url="https://example.org/article" data-lang="en" data-theme="auto"> <a href="https://vpvd.io/embed/en?url=https%3A%2F%2Fexample.org%2Farticle&theme=auto" target="_blank" rel="noopener">Open the discussion on vpvd</a> </div> <script src="https://vpvd.io/embed.js" async referrerpolicy="no-referrer"></script>
Next.js, Nuxt, React
// components/VpvdThread.tsx — one page's discussion. Load the script once in the layout:
// <Script src="https://vpvd.io/embed.js" strategy="afterInteractive" />
'use client';
import { useEffect, useRef } from 'react';
export default function VpvdThread() {
const box = useRef<HTMLDivElement>(null);
useEffect(() => {
const el = box.current;
const vpvd = (window as any).vpvd;
if (el && vpvd) vpvd.mount(el);
return () => { if (el && vpvd) vpvd.destroy(el); };
}, []);
return (
<div ref={box} data-vpvd-thread data-url="https://example.org/article" data-lang="en" data-theme="auto">
<a href="https://vpvd.io/embed/en?url=https%3A%2F%2Fexample.org%2Farticle&theme=auto" target="_blank" rel="noopener">Open the discussion on vpvd</a>
</div>
);
} Pages that change without a reload
// after every client-side transition: window.vpvd.refresh();
Theme and font
Attributes
data-url- address of the page being discussed. The discussion is bound to it, so it has to be the same for every reader.
data-lang- the language of the block — one of the languages in the list below. Any other value gives a 404: the frame does not exist in other languages.
en— Englishzh-Hans— 简体中文es— Españolar— العربيةru— Русскийvi— Tiếng Việttr— Türkçefa— فارسی
data-theme- the block's theme: auto (as on your page), light or dark.
data-height- the height reserved for the block until the frame reports its own, in pixels, for example 200. Then the block lines up with the real height; the value lives within 120–2000. Set it if the jump is noticeable on your page: by default we reserve 160 pixels.
When a comment appears
Comment count for a list
What the code doesn't do
Check that it embedded
- the frame is in place: the loader has replaced the fallback link in the container with it
- the loader has run: the value below is defined and its version is 1
window.vpvd - the frame has reported its height: the number is no longer the reserved 160, and the block lines up with the thread
// 1
document.querySelector('iframe[data-vpvd-frame]')
// 2
window.vpvd.version
// 3
document.querySelector('iframe[data-vpvd-frame]').style.height Strict CSP on your site
script-src— the script of the block comes from thereframe-src— the thread itself shows in our framechild-src→frame-src— if your policy sets it, the frames obey it rather than the general directive: a value from a different source quietly blocks every frame on the page, ours included. Name our address here as well — or drop the directive.