Installation & Configuration

Check our Platforms documentation for more platform-specific instructions.

Add the following script to <head> or to the end of <body> of the page. It registers the <hyvor-talk-comments> Web Component on your webpage.

<script async src="" type="module"></script>

Then, add the hyvor-talk-comments element to the place where you want the comments section to load. It is possible to add multiple comments sections to a single page if needed.



The following attributes are supported in the <hyvor-talk-comments> element

Attribute Value
website-id Your Hyvor Talk Website ID
page-id An identifier for the current page. Each different page-id will load a different thread. If not set, the canonical URL of the current page will be used. It is highly recommended to use a database ID (like Post ID) for this.
page-url Page URL (optional).
page-title Page title (optional). The page title is shown in notifications, emails, and in the Console. document.title is used by default
page-language Override the website’s language for this page.
page-author Email (or base64 encoded email) of the author
sso-user and sso-hash See Single Sign-on
colors light, dark, or os. See Light & Dark Mode
loading Accepts default, lazy, and manual. See loading


Instead of HTML, you may use Javascript to create the <hyvor-talk-comments> element. This allows you to set advanced properties as explained below.

const comments = document.createElement("hyvor-talk-comments");
comments.setAttribute("website-id", "YOUR_WEBSITE_ID");



hyvor-talk-comments custom element supports a couple of properties to set advanced data structures (objects) for the component. If you want to use these properties, you should create the <hyvor-talk-comments> element using Javascript or use loading="manual" and call .load() manually.

1. Settings

The settings property allows you to override website-level settings at the page level. The following is a full list of all overridable settings.

comments.settings = {
    name: 'John Doe', // website name
    custom_css: null, // or string of CSS
    auth: {
        sso_stateless_login_url: null, // or URL string  
    comments_view: {
        note: 'This is a note', // note shown above the comments
        close_after_days: 0, // close the page after X days (0 for never)
        is_keyboard_navigation_on: true,
        nested_levels: 3, // number of nested levels (the rest will be collapsed)
        display_replied_to_type: 'none' | 'deep' | 'all', // when to show 'replied to' tag
    profiles: {
        pictures: true, // show profile pictures
        profiles: true, // show profile popup
        default_picture: null, // default profile picture URL
        display_name_type: 'name', // 'name' | 'username'
        mod_alias_name: 'Moderator', // alias for moderators for company representation
        mod_alias_picture: null,
    realtime: {
        on: true, // enable realtime updates
        count: true, // show online count
        users: false, // show online users list
        typing: 'off', // show if someone is typing = 'off' | 'on_without_typer' | 'on_with_typer'
    voting: {
        type: 'both', // 'both' | 'up' | 'down'
        voters: true, // show voters list
    top_widget: 'reactions', // 'reactions' | 'ratings' | 'none'
    reactions: {
        configs: [
                type: 'superb', // 'superb' | 'love' | 'wow' | 'sad' |  'laugh' | 'angry'
                is_shown: true,
                image_url: 'image.png',
                text: 'Superb',
            // more items
        display_type: 'image', // how to display reaction = 'image' | 'text' | 'both'
    ratings: {
        star_color: '#f1c40f', // color of the rating stars
    text: {
        // if a string is set, it will be shown *regardless* of the language.
        comment_box: null,
        reply_box: null,
        no_comments: null,
        reactions: null,
        ratings: null,
        comment_count_0: null,
        comment_count_1: null,
        comment_count_multi: null,
    editor: {
        emoji: true,
        images: true,
        gifs: true,
        embeds: true, // link embedding
        mentions: true,
        code_blocks: true,
        blockquotes: true,
        inline_styles: true, // bold, italic, inline code, strike, spoiler
        links: true,
    ui: {
        width: null, // null | number - width of the comments box in pixels, 100% if null
        box_shadow: string, // box-shadow CSS property for boxes
        box_radius: string, // border-radius CSS property for boxes
        box_border_size: string, // border-size CSS property for boxes
        box_border_color: string, // border-color CSS property for the comments and other boxes
        button_radius: string, // border-radius CSS property for buttons
    light_palette: {
        accent: '#000000',
        accent_text: '#000000',
        box: '#000000',
        box_text: '#000000',
        box_text_light: '#000000',
        box_secondary: '#000000',
        box_secondary_text: '#000000',
    dark_palette: {}, // same properties as light_palette

    // comments highlighting
    highlight: {
        new: true, // whether to highlight new comments
        new_color: '#00ff00',
        // upvote-based highlighting
        upvote_1_threshold: null, // null | number
        upvote_2_threshold: 2, // null | number
        upvote_1_color: '#0000ff',
        upvote_2_color: '#ff0000',

Note that in order to make settings work, you should wait until the Web Component is defined. The easiest method is to use customElements.whenDefined.

customElements.whenDefined('hyvor-talk-comments').then(() => {
    const comments = document.createElement("hyvor-talk-comments");
    comments.settings = {}
    // then append

2. Translations

By using the translations property, you can change any string in the comments section.

const comments = document.createElement("hyvor-talk-comments");

comments.translations = {
    sort: "Order by",
    reactions_text: "What do you think about this post?",

You can find the object keys on the translation page ( Note that the cameCase keys are converted to snake_case. For example, reactionsText becomes reactions_text.


The loading attribute accepts the following values:

Using Manual Loading

The loading attribute can be set to manual to delay the rendering of the comments embed until the .load() method is called. One use case would be setting the properties of the component before rendering when using HTML-based installation.


    const comments = document.querySelector("hyvor-talk-comments");
    comments.settings = {}
    comments.translations = {}
    // now load the comments section

If you are using React/Vue/Svelte components, you can usually use refs and call load() in the onMount lifecycle method.

Content Security Policy (CSP)

If you are using a Content Security Policy (CSP) on your website, you should add the following to your CSP header:

CSP - Scripts

Hyvor Talk loads scripts from The default script, /embed/embed.js, loads the comments section. More scripts are loaded lazily when needed.

CSP - API Calls and WebSockets

If you have enabled real-time features (Console → Settings → Embed Configuration → Realtime), use the following CSP to allow the WebSockets protocol (wss:) and connections to our API endpoints and the WebSocket server.

If you have not enabled real-time features, you can use the following CSP.

CSP - Images

Hyvor Talk loads images from,, and Gravatar.

CSP - Styles

Due to the dynamic nature of the comments section, we use inline styles. So, you should allow inline styles using a nonce. Usually, you would generate a random nonce on the server-side and add it to the CSP header.

Then, you should add the nonce to the <hyvor-talk-comments> element.


If you cannot generate a nonce, you may use unsafe-inline instead. However, it is not recommended.

All together:

connect-src wss: https://*; 
img-src https://*; 
style-src-elem 'nonce-<random-nonce>'


The <hyvor-talk-comments> element exposes a mini-API with the following methods:


const comments = document.querySelector("hyvor-talk-comments");

Page Object

interface Page {
    id: number,
    created_at: number,
    identifier: string,
    url: string,
    title: string,
    is_closed: boolean,
    is_premoderation_on: boolean,
    comments_count: number,
    reactions: Record<'superb' | 'love' | 'wow' | 'sad' |  'laugh' | 'angry', number>,
    ratings: {
        average: number,
        count: number
    online_count: number

User Object

interface User {
    id: number,
    type: 'hyvor' | 'sso'
    name: string,
    username: string,
    picture_url: string | null,
    bio: string | null,
    location: string | null,
    website_url: string | null