Comments with Staticman

The biggest problem of the blog by far were the comments.

In theory Staticman is great. The users don’t have to register. You have complete control over the HTML of your comments. The comments will be automatically committed to your GitHub repository. Each comment in its own file. So you can easily manage them.

In practice though Eduardo Bouças (the original developer) stopped working on Staticman. Others took over, but Eduardo needs to review and confirm those changes before they can be merged. I saw PRs which were not reviewed in two years and then closed again because the contributor lost interest and was not willing to solve merge conflicts anymore.

So Staticman is not perfect, but it’s still the best option I found.

My information comes from different blog posts listed at the end of this article and some GitHub issues of Staticman. Apparently everybody who starts a new blog needs some content and describes their experiences. I won’t just repeat that here, but as there was no one blog post to rule them all I’ll describe the biggest problems here.

Concept

Staticman works like this:

  1. your app posts a new comment to Staticman
  2. Staticman authenticates with GitHub and either creates a PR or merges the comment to your repo right away
  3. when the comment has been merged, GitHub will re-create the HTML and the comment will be shown

Until 2018 there was one public Staticman instance which handled comments for all blogs. But as it became more popular, the public instance could not run in a free tier anymore and this stopped working. Now you need to host your own Staticman instance. This was something I wanted to prevent, but it looks like there is no other way anymore.

Many different services

Staticman is a Node.js app. They recommend to run it on Heroku.

You also need spam protection or your blog will be flooded with spam comments. So you also need to register for reCAPTCHA.

If you want email notifications - and who doesn’t? - then you also need an account at Mailgun.

These services are all free and configuration is straight forward. But still it’s something you have to do and what can go wrong.

Configuring Staticman

Lets start with Staticman. As I wrote above, there are some people working on it, but the PRs take ages until they are merged in - if at all. As I ran into a problem where a PR existed but was not merged I ended up forking eduardoboucas/staticman. You don’t have to do that, but if there is any trouble, it is better to be able to change the Staticman code yourself.

Either way, you need to run the Node.js app somewhere. Staticman recommends Heroku and that’s also what I used. Go to heroku.com and sign up for a free account. Then click this link to deploy a new application with Staticman as template. If you forked Staticman, you can connect Heroku to your github repo on the Deploy page.

Staticman needs a RSA key to encrypt/decrypt some values. Depending on your OS you can create a RSA key with either ssh-keygen or openssl genrsa. Don’t use a passphrase. When you have that, then open the Settings page in your Heroku Dashboard and click Reveal Config Vars. Add the variable RSA_PRIVATE_KEY and set the value to the private RSA key without newlines. Keep that tab open, we will need to add more variables.

Unfortunately the Staticman docs are outdated and not very exhaustive. What took me a few days and much help from Vincent Tam is to set up the authentication between Staticman and GitHub.

The docs list three options how this can be done, but they don’t mention that you have to use option 1 with Staticman v3 and option 2 with v2. When v3 was created, they broke the githubToken authentication and it was never fixed. Option 3 is not recommended, but it should work with v2 too. V1 is deprecated and should not be used anymore.

Staticman version 3

Version 3 uses a GitHub App to authenticate. This has the advantage, that you can set strict permissions for what the App (and thus Staticman) can do.

Go to your account settings / Developer Settings on GitHub and create a New GitHub App. Most of the values can remain the default. You just have to change:

GitHub App Name anything you want
Homepage URL the url of your web site
Webhook URL https://<heroku app name>.herokuapp.com/v1/webhook
Permissions: Content Read & Write
Permissions: Pull Requests Read & Write

After the App was created first note the App Id at the top. Go back to your Heroku tab and add the var GITHUB_APP_ID with the 6-digit App id from your GitHub App.

Back in your GitHub App settings scroll down and Generate a Private Key. This will download a .pem file. Open that file and copy its contents to the GITHUB_PRIVATE_KEY config var in Heroku.

Then on GitHub select Install App in the navigation and install it to your GitHub Pages repository.

In your _config.yml you need to specify these values:

comments:
  provider: "staticman_v2"
  staticman:
    endpoint: "https://<your heroku appname>.herokuapp.com/v3/entry/github/"

The API of versions 2 and 3 are very similar. So you can set the provider to "staticman_v2". The endpoint matters.

Staticman version 2

Version 2 needed a GitHub account to perform the necessary actions. This can either be your own account (option 3) or some newly created account which you can create solely for Staticman comments (option 2). The former is not recommended because in this case Staticman can do everything in all your repositories.

This is explained pretty good on this blog and I won’t repeat it here. You don’t need to install the Heroku CLI. Just copy the personal access token of your new account and use the Heroku settings to add variable GITHUB_TOKEN there.

In your _config.yml you need to specify these values:

comments:
  provider               : "staticman_v2"
  staticman:
    endpoint: "https://<your heroku appname>.herokuapp.com/v2/entry/"

Spam protection

Once your blog is found by google it is only a question of days until you’ll get your first spam comment. Akismet has a good description about spam comments.

reCAPTCHA

The easiest part to introduce is reCAPTCHA. It is a service by Google, built in in Minimal Mistakes and everybody knows it from tons of other sites.

Go ahead and register here. I did this in 2018 and registered for v2. TBH I don’t know if v3 or Enterprise also work. I didn’t try myself and couldn’t find anybody confirming that. However, after you registered you get a Site key and a Secret. The Secret must be encrypted.

Both have to be inserted in the staticman.yml

  reCaptcha:
    enabled: true
    siteKey: "yourSitekey"
    secret: "yourEncryptedSecret"

And if you use Minimal Mistakes they also need to go to _config.yml

reCaptcha:
  siteKey                : "yourSitekey"
  secret                 : "yourEncryptedSecret"

Disable the submit button

Unfortunately reCAPTCHA alone is not enough. After a few days I got my first spam message.

I found this about spam protection. It basically changes the submit button to a normal button and disables it. Once the reCAPTCHA has been checked, it updates the submit button.

In comments.html add a data-callback attribute to the reCAPTCHA and disable the submit button:

  
    <div class="form-group">
      <div class="g-recaptcha"
           data-sitekey="6LdTL28UAAAAAA5yKYsc7proZtMu-54BbhvPrwpN"
           data-callback="verifyCaptcha"></div>
    </div>
  
  <div class="form-group">
    <button type="button" disabled="disabled" id="comment-form-submit" ...
  </div>

When the reCAPTCHA is checked, it executes the verifyCaptcha function. Add it to some .js file:

var verifyCaptcha = function(response) {
    if(response.length == 0) {
    } else {
        var _el=$('#comment-form-submit');
        _el.removeAttr("disabled");
        _el.addClass('button-primary dark-blue-bg');
        _el.attr('aria-disabled', 'false');
        _el.attr('type', 'submit');
    }
};

This changes the submit button back to what it should be.

I’ll see if I still get some spams. If Yes, then I have to look into Akismet too. This also does spam prevention, but as I understood it, it is still in preview in Staticman and does not really work. PRs fixing it have not been merged.

Akismet

As you might have guessed it was still not enough. It took a few days, but the spam comments came again.

Akismet is another spam prevention service. It is mainly for WordPress and it is the default there. First I read that it was not officially supported by Staticman, but when I tried, it worked at once. It is another external service though and of course it is one more moving part which could go wrong.

Akismet tries hard to get you to pay for their service. The free option is very good hidden. You have to sign up for the personal plan to “pay what you want” and then move the slider “What is Akismet worth to you?” to the left. But this is only for personal websites without ads or any other stuff which brings you some income. If you have those, you’ll need to pay.

Unfortunately you also need a wordpress.com account. Another site where you have to register.

On the Staticman side, configuring Akismet is very easy. You just need to uncomment the akismet section in your staticman.yml.

  # Akismet spam detection.
  akismet:
    enabled: true
    author: "name"
    authorEmail: "email"
  #   authorUrl: "url"    I don't use that
    content: "message"
    type: "comment"

Then in Heroku you need to define two Config Vars: AKISMET_API_KEY and AKISMET_SITE. The AKISMET_SITE is the url of your blog - the one you entered when registering with Akismet. And the AKISMET_API_KEY will be sent to you via email.

And that’s actually it. You can test if Akismet works by entereing the data described in the Akismet docs.

And the good news is: after activating Akismet, I really didn’t get any spam comments anymore.

Mailgun

Mailgun can be used to notify your users of new comments via email. By default Minimal Mistakes notifies everybody who commented on the same blog post. I changed that in order that you can send an answer to a previous comment and only those receive emails who answered to the same comment.

Registering for Mailgun is quite complicated, but their docs are very good. Just start here. You need to provide your credit card info, but they will not charge anything. One problem I had (and nobody documented) was that you can choose whether you want to create your mail domain in the US or EU. As I am from Austria I chose EU and that didn’t work. By default Staticman only works with the US domain and you can’t change the region later.

There has been a PR in 2019 which enabled you to configure the API URL, but it was not merged. Fortunately it was pretty easy to make those changes in my own fork so that I could configure the apiHost in my staticman.yml file.

I now have these settings for Mailgun in my staticman.yml:

  notifications:
    # Enable notifications
    enabled: true

    # (!) ENCRYPTED
    # Mailgun API key
    apiKey: "yourEncryptedMailgunApiKey"

    # (!) ENCRYPTED
    # Mailgun domain (encrypted)
    domain: "yourEncryptedMailgunDomain"

    # By default staticman can only send to the US mailGun API.
    # With the PR below, it can also use the EU domain.
    # See https://github.com/eduardoboucas/staticman/pull/275/files
    apiHost: "api.eu.mailgun.net"

    # emails will be sent from this address
    fromAddress: "Michaels Blog <noreply@mg.mrumpler.at>"

Threaded comments

I want to be able to reply to previous comments. By default, this is not possible in Minimal Mistakes. You can only send comments to the whole blog post. But Michael Rose did this for his own blog and Gabriel Luci built on that. Although that is quite a lot of manual work, their description is very good. So I won’t repeat it here.

Other changes

After I did that, my comments all had an id which I could link to. As I didn’t like the standard email Staticman sends I changed that in my Staticman fork in lib/Notification.js. But unfortunately that function did not get the id of the new comment, so I also had to provide that in lib/Staticman.js. My email notifications now don’t contain a strange greeting (“Dear human”) anymore. Instead they list the name of the person who sent the new comment, the message and a direct link to the new comment.

The id in the comments also has the advantage that you can delete some comments just by deleting the file. References to other comments will still be correct.

Updated:

18 Comments

Mahesh Kumar Yadav
Mahesh Kumar Yadav at

It didn’t work, I got the message ‘Hello from Staticman version 3.0.0!’ from heroku app also. I configured github app also

Michael Rumpler
Michael Rumpler at

You have to be more specific. “It didn’t work” never helped in the whole history of IT.

What exactly does not work? What error do you get after doing what? Did you look at the Heroku logs? What errors did you find there?

Mahesh Kumar Yadav
Mahesh Kumar Yadav at

I tried to configure in my GitHub pages for ‘Staticman version 3’, as you described, I deployed the app in Heroku, created GitHub app as you said in the description. Added staticman endpoint in _config.yml. I opened the app from heroku and got the response ‘Hello from Staticman version 3.0.0!’. When I try to add comments on page, it shows the error ‘Sorry, there was an error with your submission. Please make sure all required fields have been completed and try again’. Already all fields are filled up.

Michael Rumpler
Michael Rumpler at

The required fields can be found in staticman.yml. It is called “requiredFields”. Check if it contains something which you don’t have in your comment form (_includes/comments.html). If your requiredFields contain e.g. “url”, then your comments form must also contain a respective input field with name=”fields[url]”. You can also check in the heroku log or in the browsers debugger what parameters have really been submitted.

Mahesh Kumar Yadav
Mahesh Kumar Yadav at

comment html image link https://ibb.co/HNt59JX, comment link image https://ibb.co/10psSvy heroku response image https://ibb.co/tJ2ZRy3 _config.yml https://ibb.co/27xH2c1

Michael Rumpler
Michael Rumpler at

What is in the requiredFields in your staticman.yml file? In your browser press F12 and open the Network tab. Then submit your comment form and see what is sent to the herokuapp. Compare the fields sent to heroku with the requiredFields.

Mahesh Kumar Yadav
Mahesh Kumar Yadav at

Thanks! There were errors in my staticman.yml. I fixed that. It’s working now. I want to implement ‘Reply’ of comments. How to implement? Please give me some hints. Actually, I don’t have knowledge of Jekyll, just I do with the help of the internet

Michael Rumpler
Michael Rumpler at

I already wrote above in Threaded comments please read the two posts of Michael Rose and Gabriel Luci. They explain in detail what you have to do. But you do have to understand how Jekyll works. It’s not that hard. I didn’t know it before either.

kai

Hello, I was wondering if you have any advice on getting akismet working.

I created an akismet personal account and have an api key.

I have my own instance of staticman, at “https://.herokuapp.com".

Now, according to https://github.com/eduardoboucas/staticman/issues/83, the AKISMET_SITE variable should be the same as where staticman is hosted, thus “https://.herokuapp.com".

Elsewhere I see that AKISMET_SITE variable is just a personal domain, “mydomain.com”.

For you is it your staticman heroku url, or is it your personal domain? I cannot get it working with either, trying to use the recommended akismet spam comment.

Thanks for the blog post.

Ben

Hello, I have been trying to figure this out, but am running into issues. I have created a GitHub app and have my own instance of Staticman on Heroku. When I go to the root URL of my Heroko Staticman, I get the “Hello from Staticman version 3.0.0!” message. In my site configs, when I use the v3/entry it doesn’t work. When I change it to v2/entry in my site config, it does work. It seems like my Github app and Heroku are communicating as expected since I get a pull request with v2/entry, but I do not know why v3 doesn’t work. I feel like I am missing something obvious, but cannot figure it out and various documentation on Staticman is older than the Github App configuration, so it’s hard to put the pieces together sometimes. I built my Heroku instance from the Master branch of the Staticman repository, if that is helpful.

Ben

After more testing, looking at source code, and thinking, it seems I needed to add “/GitHub” to the end of the “v3/entry” API url to cause it to work. So “v2/entry” works and now “v3/entry/github” also works. I don’t recall seeing that documented any where.

Michael Rumpler
Michael Rumpler at

Yes, that also took me a while. First I thought that v3 does not work at all. But I do have the endpoint urls in the code sections above.

Ben

Ah, yes. I am seeing the “GitHub” addition in the URLs on your website and others now. I think since the URL looked so similar between v2 and v3, I didn’t notice the addition of “GitHub” to the URL for v3. Thank you for your help and for sharing your experience with this article and your source code. It is very helpful!

Ben

I was able to get v3 up and running and comments result in a pull request in GitHub, but when I either merge or close the pull request, my Heroku app crashes. Do you know what would cause this?

Leave a comment

Your email address will not be published. Required fields are marked *

Loading...