Configuring Staticman Comments with Hugo
Last updated: 22 Jun 2020
UPDATE: Fix broken links to staticman’s partial, CSS and JS files.
I wanted to add comments to my blog, and Disqus seemed like a good option as the theme I’m using supports it out of the box. However, as things stand, I am happy with a solution that doesn’t require storing people’s data in third party databases and doesn’t add ads and unnecessary tracking scripts that could make the reading experience slower or cluttered.
After searching for open-source/ethical comment suppliers, I found out about Staticman, and I am giving it a try since it integrates with Hugo blogs, it uses a git repository to store and triage comments, it’s been around since 2015, and has good documentation. I just had to work around some constraints. In essence, you need to deploy your own instance of Staticman to Heroku as the official Staticman API hits its quota frequently (Heroku’s free tier is enough tho’), I wanted to keep this blog’s comments on a separate repository, and I am using Staticman API V2 since everything is hosted on GitHub (V3 supports other providers like Gitlab).
This post by Arne Petersen was of great help to put everything together. After some tweaks, my deployment works like this:
- I’m only collecting people’s names and comments
- I’m using reCaptcha 2 to avoid spam
- I only load reCaptcha’s JS script when you click the “Show Comments” button
- I accept/reject comments using pull requests.
- After accepting a comment, my blog is re-build and published automatically in Netlify using webhooks
- After someone submits a comment, they get redirected to the original blog post with a message explaining their comment will go live after approval. No AJAX or popups are required, and you can try it leaving a comment!
And the instructions:
- Create a repository for your comments in your
main
GitHub account; we will call itblog_comments
- Create a secondary GitHub account; we will call it
account2
. This is for security reasons as Arne pointed out, you are creating a Personal Access Token and keeping it in your Heroku instance which could give anyone who gets hold of it full access to your GitHub account. - Create a Personal Access Token in
account2
at https://github.com/settings/tokens. Save it because you can only see it once, and you will need it in a bit. - Invite
account2
as a collaborator toblog_comments
going tohttps://github.com/YOUR_MAIN_GITHUB_ACCOUNT/blog_comments/settings/access
- Deploy Staticman to Heroku using the purple button in the project’s README (make sure it’s in the master branch)
- Create a private key for Staticman (you can do this in your Heroku instance going to “More” -> “Run console”):
openssl genrsa –out key.pem; cat key.pem
- Add the following three Config vars to your Heroku instance in
https://dashboard.heroku.com/apps/YOUR_INSTANCE_NAME/settings
:NODE_ENV production GITHUB_TOKEN "YOUR PERSONAL ACCESS TOKEN" RSA_PRIVATE_KEY "CONTENT OF key.pem"
- If you want to use reCaptcha to avoid spam, do the following:
- Register your blog here. You can add
localhost
to the domain list to be able to test everything in your local machine. Save yoursiteKey
andsecret
- Encrypt your reCaptcha
secret
obtained before by querying your Heroku instance in this URL:https://YOUR_HEROKU_APP_NAME.herokuapp.com/v2/encrypt/YOUR_UNENCRYPTED_RECAPTCHA_SECRET
- Add this partial to your blog and call
{{ partial "staticman.html" . }}
where you want to load your comments. - Add these CSS rules to your blog.
- Add this JS script to your partials
- Add the following lines to the
params
list in your Hugo blog’sconfig.yaml
staticman: api: https://<YOUR_HEROKU_APP_NAME>.herokuapp.com/v2/entry/YOUR_MAIN_GITHUB_ACCOUNT/blog_comments/master/comments recaptcha: sitekey: "YOUR RECAPTCHA KEY" secret: "YOUR ENCRYPTED RECAPTCHA SECRET"
- Add your Staticman configuration file,
staticman.yaml
, to the root ofblog_comments
. You can use the one below or this other one as a reference if you want to collect more data like emails or personal websites.comments: allowedFields: ["name", "comment"] branch: "master" commitMessage: "New comment in {options.slug}" filename: "comment-{@timestamp}" format: "yaml" generatedFields: date: type: date options: format: "iso8601" moderation: true name: "YOUR SITES NAME" path: "{options.slug}" requiredFields: ["name", "comment"] transforms: email: md5 // Delete this if you do not want to use reCaptcha reCaptcha: enabled: true siteKey: "YOUR RECAPTCHA KEY" secret: "YOUR ENCRYPTED RECAPTCHA SECRET"
- Add your
blog_comments
repo as a submodule to your main repo in thedata/comments
folder:git submodule add https://github.com/YOUR_MAIN_GITHUB_ACCOUNT/blog-comments.git data/comments
- I use Netlify to publish my blog, so I had to modify my Netlify build command to pull the latest version of
blog_comments
to render any new comments. You can do this using Netlify’s website or by adding anetlify.toml
file to the root of your blog repo with the following lines:[build] publish = "public" command = "git submodule update --remote data/comments && hugo --gc --minify" [context.production.environment] HUGO_VERSION = "v0.68.3" HUGO_ENV = "production" HUGO_ENABLEGITINFO = "true"
- Every time someone comments on a blog post, Staticman creates a new branch and a Pull Request (PR) in
blog_comments
which you can accept or reject to publish it or not. Branches will start to pile up, so, for those PRs you reject, you have to delete their branches using GitHub’s UI manually. Still, for those PRs you accept, GitHub can automatically delete them by activating this feature. - At this point, you can submit your first comment from your computer or, commit everything to GitHub and do it online.
- Optional. If you want to avoid triggering a new Netlify build manually every time you accept a comment, you can automatize it by using Integromat’s webhooks. You could also use Zappier, but you have to switch to their paid tier.
- Got to Netlify’s
Build hooks
section inhttps://app.netlify.com/sites/YOUR_NETLIFY_DOMAIN/settings/deploys#build-hooks
and click onAdd build hook
. Save the generated URL - Create a new Scenario in Integromat
- Add a
Custom Webhook trigger
. Inside, add a newWebhook
and copy its URL. Click onDetermine data structure
- Go to
https://github.com/YOUR_MAIN_GITHUB_ACCOUNT/blog_comments/settings/hooks
. Click onAdd webhook
, inPayload URL
add the URL of the IntegromatCustom Webhook trigger
, inContent type
selectapplication/json
, and underLet me select individual events
checkPull requests
. Click onAdd Webhook
. - Submit a comment in your blog, so Staticman creates a new Pull Request in
blog_comments
, and Integromat infers its content. You should see a confirmation message in theCustom Webhook trigger
. - Add a
HTTP action
in Integromat. Connect this to theCustom Webhook trigger
- In the connection between the
HTTP action
and theCustom Webhook trigger
, add two conditions joined by anAND
operator:action
=closed
andpul_request: merged
=true
. They should be autocompleted if Integromat was able to infer the PR’s content - Click in the
HTTP action
, add the Netlify hook’s URL you got earlier to the action’sURL
field, and change itsMethod
toPOST
- Turn the scenario ON using the switch at the bottom left and set
Schedule setting
toImmediatly
- From now on, the scenario should trigger a Netlify build every time you accept a Staticman’s Pull Request
- Got to Netlify’s
Feel free to leave a comment if you have issues or questions!
11 comments
Hi, great post !
Please note that the link to the staticman partial does not work: could you make it public again (in a gist?) ?
Thank you for your content.
Thanks Jean-Philippe. I fixed the broken links to the partial, CSS and JS files. Happy to hear you found this post useful!
Hi Julio,
Thanks so much for sharing this. Please can you help with an issue I’m having?
I am stuck between step 6 and 7, and would be very grateful if you are able to share a resolution.
Heroku web console appears to generate a key, but the output does not save to a key.pem file for me to access:
Running “ls -a” after gives me this:
Thanks, Onion.
Hi Julio,
Thanks to a friend (@koralatov), I’ve been able to generate and retrieve key.pem for step 6:
openssl genrsa --out key.pem; cat key.pem
Then, “save session” at bottom-right of the console.
Hi Onion, it’s great is working now and thanks for your updates. Also, FYI, in the comming days I will publish another post on how to add support for nested comments.
Great stuff!
test comment
test comment
From France.
Thanks a lot dude !
Really great job.
Hi, thanks so much for this tutorial, it was very useful.
Looking forward to your post on nested comments.
Best
test comment