GitHub Comments System

A production-ready, serverless comments system for Cloudflare that stores each comment as a JSON file directly in your GitHub repository.

Quick Navigation

How It Works

User submits comment on page with URL /blog/my-post/
    ↓
Page URL normalized to "blog--my-post" (safe file path)
    ↓
Cloudflare validates & sanitizes
    ↓
Spam detection checks
    ↓
Comment stored as Markdown file in GitHub
    ↓
Browser fetches & renders with threading

Page ID System

Comments are associated with page URLs (not filenames):

Why URLs? This ensures comments follow the content if you rename files but keep URLs stable via permalinks.

Key Features

Own Your Data — Comments stored in GitHub, not third-party services
Spam Detection — Automatic detection with configurable thresholds
Moderation — Email alerts + approval workflow
Nested Replies — Threaded comments with visual hierarchy
Markdown — Support for bold, italic, code, links
Zero Dependencies — Pure JavaScript, no npm packages
Responsive — Mobile-friendly design
XSS Safe — HTML sanitization + entity encoding

Files Included

Source Code (in src/cloudflare/):

Documentation (in content/cloudflare/comments/):

3-Minute Overview

1. GitHub Setup

# Generate personal access token (repo scope)
# https://github.com/settings/tokens

# Create comments directory
mkdir data/comments
git add data/comments/.gitkeep
git commit -m "Add comments directory"
git push

2. Cloudflare Deployment

# Deploy comments function
wrangler publish --env production

# Set GitHub token
wrangler secret put GITHUB_TOKEN --env production

3. Frontend Integration

<!-- Add to your page -->
<div id="comments"></div>
<form id="comment-form">
  <input type="text" name="author" placeholder="Name" required />
  <input type="email" name="email" placeholder="Email" required />
  <textarea name="content" placeholder="Comment" required></textarea>
  <button type="submit">Post</button>
</form>

<script src="/path/to/standard.comment.js"></script>
<script>
  const comments = new GitHubComments({
    apiUrl: '/api/comments',
    pageId: 'blog/my-post',
    container: '#comments',
    form: '#comment-form'
  });
  comments.load().then(() => comments.render());
  comments.attachFormHandler();
</script>

File Structure

After deployment, your repo will have:

data/comments/
├── blog--my-post/
│   ├── 1729609945000-a7x9k2m1.md
│   ├── 1729609967000-b4z2k9p3.md
│   └── 1729610005000-c8m5l1q7.md
├── about/
│   └── 1729610045000-e9m2k7p5.md
└── index/
    └── 1729610100000-d2m8k4r9.md

Note: Directory names use normalized page IDs (slashes replaced with --).

Each comment: ~500–1000 bytes (small, git-friendly)

API Endpoints

POST /api/comments

Submit a new comment

{
  "pageId": "blog--my-post",
  "author": "John Doe",
  "email": "[email protected]",
  "content": "Great article!",
  "parentId": null
}

Note: pageId should be normalized (e.g., blog--my-post not blog/my-post). The {% standardComment %} shortcode handles this automatically.

GET /api/comments?pageId=blog—my-post

Fetch all comments for a page

{
  "pageId": "blog--my-post",
  "count": 3,
  "comments": [...]
}

Configuration

11ty Plugin Configuration

Configure the comments system in your eleventy.config.js:

import Standard from "@zefish/standard";

export default function (eleventyConfig) {
  eleventyConfig.addPlugin(Standard, {
    comments: {
      enabled: true,
      apiEndpoint: "/api/comments",
      commentsPath: "data/comments"  // ← Configurable GitHub storage path
    }
  });
}

Options:

Cloudflare Environment Variables

Required environment variables:

Optional:

Example: To store comments in comments/ instead of data/comments/:

  1. Set commentsPath: "comments" in your 11ty config
  2. Set GITHUB_COMMENTS_PATH=comments in Cloudflare environment variables
  3. Create comments/ directory in your GitHub repo

Use Cases

Perfect for:

Security

✅ HTML sanitization (removes XSS)
✅ Email validation
✅ GitHub token in secrets (never exposed)
✅ Spam detection with confidence scoring
✅ Rate limiting support
✅ Moderation approval workflow

Next Steps

  1. Start with Quick Start Guide (10 minutes)
  2. Set up GitHub personal access token
  3. Deploy to Cloudflare
  4. Add HTML form to your page
  5. Test comment submission
  6. Monitor moderation queue

Advantages

vs. Third-party Services (Disqus, Commento):

vs. Database Solutions (MongoDB, PostgreSQL):

Breaking Changes (v0.10.53+)

Page IDs Now Use page.url (Not page.fileSlug)

Comments are now associated with page URLs instead of file names.

Why? This ensures comments follow the content if you rename files but keep URLs stable via permalinks.

Migration: Not backward compatible. If you have existing comments from earlier versions, they used page.fileSlug. The system won’t automatically find them with the new URL-based IDs.

Options:

  1. Accept fresh start — Existing comments stay in old directories (won’t display), new comments use new structure
  2. Don’t upgrade — Stay on earlier version if you have existing comments you want to keep
  3. Manual migration — Rename directories to match new URL-based IDs (see below)

Configurable Comments Path

The comments storage path is now configurable (previously hardcoded to data/comments).

What Changed:

Action Required: Set GITHUB_COMMENTS_PATH environment variable in Cloudflare to match your chosen path.

Troubleshooting

Comments not appearing?

GitHub 401 Unauthorized?

Spam too aggressive?

Wrong pageId?

See COMMENTS-GUIDE.md for more troubleshooting.

Statistics

See Also


Version: 0.10.53
Status: ✅ Production Ready
Last Updated: October 2024