Skip to content
CommentKit / Frameworks

Server-rendered sites

Laravel, Rails, Django, Phoenix, htmx and Alpine, and how CommentKit handles page swaps.

Page swaps

Turbo, Livewire’s wire:navigate and htmx’s hx-boost move between pages without a full reload: they fetch the next page and swap in its <body>. CommentKit is built for this. Its widget lives outside <body>, so a swap does not remove it, and it notices the new address within half a second and loads that page’s comments.

What matters is where the tag goes. These tools run scripts in the new <body> again on every visit, but run a script in <head> only once. So put the tag in <head> of your main layout. With defer it still waits for the page.

Your layout
<head>
  …
  <script src="https://commentkit.dev/cdn/v1/loader.js" data-project="pk_live_your_key" defer></script>
</head>

No data-turbo-permanent, data-turbo-track or @persist is needed. The loader address never changes, so tracking it would never reload anything.

Laravel

  • Blade: in <head> of your main layout, for example resources/views/layouts/app.blade.php or your <x-layout> component.
  • Inertia: in <head> of resources/views/app.blade.php, next to @vite and @inertiaHead. That file is sent once; Inertia swaps only the page component. Or use the React or Vue helper.
  • Livewire with wire:navigate: in <head>. Livewire replaces the body and runs its scripts again on every visit. If the tag has to stay in the body, add data-navigate-once to it.
resources/views/layouts/app.blade.php
<script src="https://commentkit.dev/cdn/v1/loader.js"
        data-project="{{ config('services.commentkit.key') }}"
        data-branch="{{ app()->environment() }}"
        defer></script>

The key is public, so writing it straight into the layout is fine too. services.commentkit.key is only an example; add it to config/services.php if you want it in .env.

Rails

In <head> of app/views/layouts/application.html.erb. Turbo Drive runs body scripts again on every visit but adds a head script only once. If the tag has to stay in the body, add data-turbo-eval="false" to it.

app/views/layouts/application.html.erb
<script src="https://commentkit.dev/cdn/v1/loader.js"
        data-project="pk_live_your_key"
        data-branch="<%= Rails.env %>"
        defer></script>

Turbo Frames and Turbo Streams change parts of the page and need nothing extra.

Django

In <head> of your base template, for example templates/base.html, which other templates {% extends %}. Pages that reload fully have nothing else to watch for; with htmx, see below.

Phoenix

In <head> of your root layout, lib/my_app_web/components/layouts/root.html.heex. LiveView navigation (navigate and patch) only updates the LiveView inside the root layout, so the tag runs once and CommentKit follows the new address.

htmx and Alpine

  • htmx: with hx-boost, links and forms swap the body and its scripts run again. Put the tag in <head>, which htmx leaves alone. Smaller swaps (hx-get into one element) need nothing extra.
  • Alpine: Alpine does not change pages, so the tag can go anywhere in your layout. CommentKit’s own controls are separate from your Alpine components.

Keep it off the live site

You do not need to do anything for regular visitors. On every address except localhost, the widget stays hidden until someone opens a client link, follows a CommentKit email, presses Ctrl/Cmd + Shift + K or is already signed in. Visitors only download a tiny loader and see nothing. Do not add data-hide-on-production="false" on a live site: it shows the button to everyone.

To leave the tag out of production completely, wrap it in a check in your layout:

Blade
@unless (app()->isProduction())
    <script src="https://commentkit.dev/cdn/v1/loader.js" data-project="pk_live_your_key" defer></script>
@endunless
ERB
<% unless Rails.env.production? %>
  <script src="https://commentkit.dev/cdn/v1/loader.js" data-project="pk_live_your_key" defer></script>
<% end %>

Clients review through a Project → Client links link to your staging address. Add that address in Project → Setup first.

Troubleshooting

  • You need to press Ctrl/Cmd + Shift + K more than once after moving between pages, or window.CommentKit changes on every visit: the tag is in <body> and runs again on each swap. Move it to <head>.
  • The previous page’s comments show for a moment after a swap: CommentKit checks the address twice a second, then loads the new page’s comments.
  • Your site sets a Content Security Policy with nonces (for example in Laravel or Rails): add the nonce to the tag and allow CommentKit as described in the CSP guide.
  • Still nothing? Open the browser console: CommentKit writes one message starting with [CommentKit] that says what went wrong (for example a website address missing from Project → Setup, or a Content Security Policy; see the CSP guide). The troubleshooting page covers the rest.