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

Enter the address of a page — you get the code and see the block right here. The preview uses the very snippet you copy: one container and one script.

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&amp;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

The site is closed before launch: the thread is readable anonymously, but sign-in does not work yet — a reader on your page sees a button that leads nowhere for now. Sign-in opens on launch day.

Where to paste it

The code is the same everywhere; only the place where you put it differs.

  • Static sites and custom templates Where the discussion should stand on the page: in the template of the article or the entry.
  • WordPress A custom code block in the post editor, or a code widget in the sidebar. Some editors drop the script tag on save — open the published page and check the block is there.
  • Tilda The block that inserts your own code (Others → code): paste the snippet whole, script tag included.
  • Next.js, Nuxt, React Load the script once in the site layout; the component puts the container and removes the widget when it unmounts — otherwise a route change leaves the old frame inside.
<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&amp;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&amp;theme=auto" target="_blank" rel="noopener">Open the discussion on vpvd</a>
		</div>
	);
}

Pages that change without a reload

React, Vue, Svelte, Nuxt: The script tag lives in your markup and does not survive a change of page: the container stays empty where the block was. Load the script once in the site template and call the refresh below after every transition — it walks every container on the page with the same code that runs on the first load.

// after every client-side transition:
window.vpvd.refresh();

Theme and font

Set the theme explicitly — light, dark or auto — and match your site with variables on the container: font, size, line height, accent colour and corner radius.

data-theme, --vpvd-font, --vpvd-font-size, --vpvd-line-height, --vpvd-accent, --vpvd-radius

With auto the block takes the theme of your page — the one you switch on your site, or the system setting of the reader — and the font, size and radius from the container itself. If it finds nothing, our own look stays.

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 — English
  • zh-Hans — 简体中文
  • es — Español
  • ar — العربية
  • ru — Русский
  • vi — Tiếng Việt
  • tr — Türkçe
  • fa — فارسی
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

Add this attribute and the block will tell your page that a comment appeared. The event carries one word and nothing about the reader:

data-events="on" → vpvd:commented

Comment count for a list

A list of articles needs a number, not a widget: this request returns how many replies a page has (zero if nobody has discussed it). It is open to your page, needs no cookies and knows nothing about the reader:

GET /api/nodes/count?url=…

What the code doesn't do

It doesn't read the content of your page and leaves no cookies of ours on it. Only the address from the attribute reaches our server: no page text, no names, no counters. We turn the referer off for both the script and the frame.

Check that it embedded

Open the page in a browser and run the lines below in the console — one line, one answer:

  1. the frame is in place: the loader has replaced the fallback link in the container with it
  2. the loader has run: the value below is defined and its version is 1 window.vpvd
  3. 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

Checking automatically, from a browser without a window (Firefox)? Your script does not see the page values: it runs in an isolated world and shares the page markup with it, not those values. Read the marks from the main world — insert your own script into the document and take the answer from an attribute.

Strict CSP on your site

Allow our address (https://vpvd.io) in the directives that bring the block in:

  • script-src — the script of the block comes from there
  • frame-src — the thread itself shows in our frame
  • child-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.

If the script never runs, the reader still sees a plain link to the discussion: our container holds it from the very start.

Questions

What does a reader see?

The thread of this page and a way in. Reading needs no account; writing works as a guest (the reply lives about half an hour) or after signing in inside the block. Signing in is the reader’s own decision: your site’s session is not passed to us.

What do you learn about my readers?

The page address you put into the snippet — that is all. We do not see browsing history, the text of your page or who visits it: the extension checks for a discussion locally, without asking a server. Cookies belong to the frame and only to it.

Will the comments show up in search?

No — search engines do not index what is inside a frame. The thread itself is indexed on vpvd, and the link to it sits inside the container.

What can I do as the owner of the site?

Remove the block by removing the code. Confirm that you own the address and a badge appears next to your replies — it does not let you hide other people’s replies, the moderation rules are the same for everyone. Your own rules and bans on your domain are coming with the owner panel.

How do I revoke access?

We have no access to your site: the script only places a frame. Delete the code and the block is gone. The session inside the frame lives in our own cookie and disappears with it.

Code for your page

The generator builds the code with the language and theme you pick.

Open the generator