This post explains why the site moved from Giscus to Waline, how comments and pageviews are hosted now, how the historical data was migrated, and how guest comments and bilingual email notifications work.
Every post now uses a new Waline comment area. Readers no longer need a GitHub account to join a discussion: they can comment as guests and optionally provide an email address if they want to be notified about replies.

Why Move Away from Giscus?
Giscus remains an excellent option for developer-focused sites. It stores comments in GitHub Discussions, requires little infrastructure, and fits naturally into open-source communities. Its main limitation for this site is that every commenter must sign in with GitHub.
The audience here is no longer limited to developers. Posts about tools, life in Malta, travel, and site updates reach readers with very different backgrounds. Requiring a GitHub account creates an unnecessary barrier to leaving a simple response.
Waline provides the features I wanted in one system:
- guest comments without mandatory registration;
- optional email addresses and reply notifications;
- comment likes, article reactions, and comment counts;
- pageview tracking through the same counter service;
- a dedicated moderation interface;
- bilingual UI text and language-aware notification emails.
A reader does not need to sign in, but the service still processes limited technical information for rate limiting, security, and moderation. Nicknames and comments are public; email addresses are not displayed in the comment list.
The New Hosting Architecture
The main blog remains a static Hugo site built by GitHub Actions and published on GitHub Pages. Sveltia CMS is the content interface, while posts and pages continue to live in the GitHub repository.
The comment system has two hosted components:
- Waline Server runs on Vercel and provides the API, administration interface, email notifications, and counters.
- Comments, users, reactions, and pageview records are stored in Neon PostgreSQL.
This does not turn the entire site into a dynamic application. GitHub Pages still serves the articles, and the browser requests Waline only when comments or counters are needed. The article itself remains available even if the comment service is temporarily unavailable.
The dashboard management menu now links separately to Sveltia CMS for content and Waline for comments. Its system panel also identifies GitHub as the content host and Vercel plus Neon as the comment infrastructure.
Matching Waline to the Existing Theme
Waline already provides an editor, comment list, sorting, Markdown, image uploads, and an emoji picker. I added a theme layer so it feels consistent with the Stack-based design:
- existing card backgrounds, borders, radii, and shadow variables;
- light and dark colour schemes;
- pageview and comment totals inside the comment notice;
- responsive behaviour for narrow screens;
- UI text selected from the current article language;
- Twitter Emoji assets for consistent rendering across systems.
The article reaction row currently offers Love, Funny, Thought-provoking, Surprising, and Sad. These use the Waline Twitter Emoji image preset rather than local emoji files from a visitor’s computer, which keeps their appearance consistent across browsers.
Migrating Pageviews from Cloudflare
The previous pageview service ran on Cloudflare Workers and D1 and already included historical GA4 data. I did not want the new comment system to reset every page to zero, so the existing counters were migrated into Waline.
The Cloudflare snapshot contained 82 raw counter keys. Some Chinese paths existed in both percent-encoded and Unicode forms, even though they referred to the same page. After URL normalization and merging, the migration produced 76 unique paths. The site-wide counter stood at 1,607 views at the time of migration.
Waline stores these values in wl_counter. A subtle issue appeared during the first API-based import: the default table uses a numeric primary key but does not enforce a unique URL. Concurrent updates could therefore create multiple rows for the same path.
The final database transaction:
- retained one counter record for each URL;
- consolidated and removed duplicates;
- added a unique URL index;
- imported historical counts with a never-decrease rule;
- checked for missing, duplicate, and under-counted paths.
The final verification reported 76 target records, no duplicate URLs, no missing URLs, and no counter below the Cloudflare source snapshot. The never-decrease rule also preserved visits that arrived while the migration was running.
Counting Every Site Page
The new counter is not limited to articles. Every non-404 page loads Waline’s lightweight pageview module in the footer. It increments the current path and a reserved path used for the site-wide total.
When an article comment area displays its pageview number, it performs a read-only request. This prevents the footer and the comment component from counting the same page load twice.
The homepage, archives, categories, tags, gallery, links, dashboard, and both language versions now use the same counter service. The old Cloudflare endpoint no longer powers the front-end count.
Email Notifications and Bilingual Templates
Mail is configured through Vercel environment variables. SMTP credentials, the application-specific password, and database connection details are stored as sensitive hosting variables; they are not committed to the Hugo repository or exposed in front-end code.
The configuration includes the SMTP service and sender, site identity, administrator notification address, and separate subjects and bodies for reply and new-comment messages.
Waline templates can read the path of the page where a comment was posted. Since Chinese content is located under /zh/, one conditional template can select the language:
|
|
Comments on Chinese pages receive Chinese email, while other pages use English. The templates include only the relevant nickname, comment text, and article link; system credentials never appear in the message body.
SMTP uses an application-specific password rather than the account’s normal login password. Waline must be redeployed after environment variables change so the production functions receive the new configuration.
Repairing Comment Ownership During Import
Comments were exported to Waline JSON before being imported into the new database. The migration retained comment text, article paths, reply relationships, timestamps, and moderation status.
Some older comments written by the site owner were missing their user association in the export. I restored only the administrator user ID and public profile metadata. The original text, page, relationships, IDs, and timestamps were not changed.
Without that repair, old owner comments could appear as ordinary guest messages, with inconsistent avatars, author labels, and moderation ownership.
Privacy and the New Comment Notice
The comment notice now says:
Guest comments are welcome. If you would like to receive reply notifications, add your email address and the system will notify you automatically when someone replies.
An email address is not required to post. When supplied, it is used for reply notifications and avatar matching and is not displayed in the public comment list.
The site’s Privacy Policy has also been updated to explain the roles of GitHub Pages, Vercel, Neon, and Waline and the information involved in posting a comment.
What Comes Next
The migration is complete, but the system still needs observation under normal use. I will monitor email delivery, mobile editing, anti-spam behaviour, counter consistency, and language-aware notifications.
If comments fail to load, a reply email does not arrive, or a counter looks wrong, you are welcome to leave a guest comment below.