diff --git a/config/vufind/config.ini b/config/vufind/config.ini
index 53e74537f5a16151b948e74c0a500d35057f86fb..a225928723159ad19b2befb5f3814c1e92b7a02c 100644
--- a/config/vufind/config.ini
+++ b/config/vufind/config.ini
@@ -1459,7 +1459,7 @@ treeSearchLimit = 100
 ;secretKey = "https://www.google.com/recaptcha/admin/create"
 ; Valid theme values: dark, light
 ;theme      = light
-; Valid forms values: changePassword, email, feedback, newAccount, passwordRecovery, sms
+; Valid forms values: changePassword, email, feedback, newAccount, passwordRecovery, sms, userComments
 ; Use * for all supported forms
 ;forms = changePassword, email, newAccount, passwordRecovery, sms
 
diff --git a/module/VuFind/src/VuFind/Controller/AjaxController.php b/module/VuFind/src/VuFind/Controller/AjaxController.php
index 6cfe77954e7c8f008257ec8b35e3564c377f55ef..98c7b7f50d4406259e076cbc6c1bb023b725b8b2 100644
--- a/module/VuFind/src/VuFind/Controller/AjaxController.php
+++ b/module/VuFind/src/VuFind/Controller/AjaxController.php
@@ -1086,6 +1086,16 @@ class AjaxController extends AbstractBase
             );
         }
 
+        $useCaptcha = $this->recaptcha()->active('userComments');
+        $this->recaptcha()->setErrorMode('none');
+        if (!$this->formWasSubmitted('comment', $useCaptcha)) {
+            return $this->output(
+                $this->translate('recaptcha_not_passed'),
+                self::STATUS_ERROR,
+                403
+            );
+        }
+
         $table = $this->getTable('Resource');
         $resource = $table->findResource(
             $id, $this->params()->fromPost('source', DEFAULT_SEARCH_BACKEND)
diff --git a/module/VuFind/src/VuFind/Controller/Plugin/Recaptcha.php b/module/VuFind/src/VuFind/Controller/Plugin/Recaptcha.php
index 01474bdedadcee5ab1a58a7fce7f8457b0c726f7..bd3591b8fa3a7b4bc862cce43cd4bc79e48250f3 100644
--- a/module/VuFind/src/VuFind/Controller/Plugin/Recaptcha.php
+++ b/module/VuFind/src/VuFind/Controller/Plugin/Recaptcha.php
@@ -90,7 +90,7 @@ class Recaptcha extends AbstractPlugin
      */
     public function setErrorMode($mode)
     {
-        if (in_array($mode, ['flash', 'throw'])) {
+        if (in_array($mode, ['flash', 'throw', 'none'])) {
             $this->errorMode = $mode;
             return true;
         }
@@ -125,7 +125,7 @@ class Recaptcha extends AbstractPlugin
             $response = false;
         }
         $captchaPassed = $response && $response->isValid();
-        if (!$captchaPassed) {
+        if (!$captchaPassed && $this->errorMode != 'none') {
             if ($this->errorMode == 'flash') {
                 $this->getController()->flashMessenger()
                     ->addMessage('recaptcha_not_passed', 'error');
diff --git a/module/VuFind/src/VuFind/RecordTab/Factory.php b/module/VuFind/src/VuFind/RecordTab/Factory.php
index 94fd9107b49e6d5a3503275527b08e3845110f84..82e6fa835cc4deae6d1a31ccc2f15ecf1680599d 100644
--- a/module/VuFind/src/VuFind/RecordTab/Factory.php
+++ b/module/VuFind/src/VuFind/RecordTab/Factory.php
@@ -262,6 +262,13 @@ class Factory
     public static function getUserComments(ServiceManager $sm)
     {
         $capabilities = $sm->getServiceLocator()->get('VuFind\AccountCapabilities');
-        return new UserComments('enabled' === $capabilities->getCommentSetting());
+        $config = $sm->getServiceLocator()->get('VuFind\Config')->get('config');
+        $useRecaptcha = isset($config->Captcha) && isset($config->Captcha->forms)
+            && (trim($config->Captcha->forms) === '*'
+            || strpos($config->Captcha->forms, 'userComments'));
+        return new UserComments(
+            'enabled' === $capabilities->getCommentSetting(),
+            $useRecaptcha
+        );
     }
 }
diff --git a/module/VuFind/src/VuFind/RecordTab/UserComments.php b/module/VuFind/src/VuFind/RecordTab/UserComments.php
index af5d219352d6f121e1741f7b0f937ebe6e64c9da..9bbede39072f0d4a43b49e81d51829a7c7873086 100644
--- a/module/VuFind/src/VuFind/RecordTab/UserComments.php
+++ b/module/VuFind/src/VuFind/RecordTab/UserComments.php
@@ -45,14 +45,33 @@ class UserComments extends AbstractBase
      */
     protected $enabled;
 
+    /**
+     * Is this tab enabled?
+     *
+     * @var bool
+     */
+    protected $useRecaptcha;
+
     /**
      * Constructor
      *
      * @param bool $enabled is this tab enabled?
+     * @param bool $urc     use recaptcha?
      */
-    public function __construct($enabled = true)
+    public function __construct($enabled = true, $urc = false)
     {
         $this->enabled = $enabled;
+        $this->useRecaptcha = $urc;
+    }
+
+    /**
+     * Is Recaptcha active?
+     *
+     * @return bool
+     */
+    public function isRecaptchaActive()
+    {
+        return $this->useRecaptcha;
     }
 
     /**
diff --git a/module/VuFind/src/VuFind/View/Helper/Root/Recaptcha.php b/module/VuFind/src/VuFind/View/Helper/Root/Recaptcha.php
index ee5e6848dad196b34ba23c0f509f4e2bae863a9e..b919aa7e877ffa57ae2869e998c28112d920e1dd 100644
--- a/module/VuFind/src/VuFind/View/Helper/Root/Recaptcha.php
+++ b/module/VuFind/src/VuFind/View/Helper/Root/Recaptcha.php
@@ -93,14 +93,18 @@ class Recaptcha extends AbstractHelper
      * Generate <div> with ReCaptcha from render.
      *
      * @param boolean $useRecaptcha Boolean of active state, for compact templating
+     * @param boolean $wrapHtml     Include prefix and suffix?
      *
      * @return string $html
      */
-    public function html($useRecaptcha = true)
+    public function html($useRecaptcha = true, $wrapHtml = true)
     {
         if (!isset($useRecaptcha) || !$useRecaptcha) {
             return false;
         }
+        if (!$wrapHtml) {
+            return $this->recaptcha->getHtml();
+        }
         return $this->prefixHtml . $this->recaptcha->getHtml() . $this->suffixHtml;
     }
 
diff --git a/themes/bootstrap3/js/lightbox.js b/themes/bootstrap3/js/lightbox.js
index c55eca08277bd0136228e485f4f79d3afdfe2ced..c09c436a436d4b0834337cf37bf593675c35f106 100644
--- a/themes/bootstrap3/js/lightbox.js
+++ b/themes/bootstrap3/js/lightbox.js
@@ -1,4 +1,4 @@
-/*global VuFind */
+/*global grecaptcha, VuFind */
 VuFind.register('lightbox', function Lightbox() {
   // State
   var _originalUrl = false;
@@ -101,6 +101,11 @@ VuFind.register('lightbox', function Lightbox() {
     $('#modal').find('.checkbox-select-item').change(function lbSelectAllDisable() {
       $(this).closest('.modal-body').find('.checkbox-select-all').prop('checked', false);
     });
+    // Recaptcha
+    var modalCaptcha = $('#modal .g-recaptcha');
+    if (modalCaptcha.length && typeof grecaptcha !== 'undefined' && modalCaptcha.is(':empty')) {
+      grecaptcha.render(modalCaptcha[0], modalCaptcha[0].dataset);
+    }
   }
 
   var _xhr = false;
diff --git a/themes/bootstrap3/js/record.js b/themes/bootstrap3/js/record.js
index 5dd139dc00e492b20134c6feb4ea080ef00c5efd..863968bc504eef6184135ee680cd6af5988c498e 100644
--- a/themes/bootstrap3/js/record.js
+++ b/themes/bootstrap3/js/record.js
@@ -1,4 +1,4 @@
-/*global deparam, syn_get_widget, userIsLoggedIn, VuFind */
+/*global deparam, grecaptcha, syn_get_widget, userIsLoggedIn, VuFind */
 /*exported ajaxTagUpdate, recordDocReady */
 
 /**
@@ -78,6 +78,9 @@ function refreshCommentList($target, recordId, recordSource) {
       return false;
     });
     $target.find('.comment-form input[type="submit"]').button('reset');
+    if (typeof grecaptcha !== 'undefined') {
+      grecaptcha.reset();
+    }
   });
 }
 
@@ -93,6 +96,14 @@ function registerAjaxCommentRecord() {
       id: id,
       source: recordSource
     };
+    if (typeof grecaptcha !== 'undefined') {
+      try {
+        data['g-recaptcha-response'] = grecaptcha.getResponse(0);
+      } catch (e) {
+        console.error('Expected errors: placeholder element full and Invalid client ID');
+        console.error(e);
+      }
+    }
     $.ajax({
       type: 'POST',
       url: url,
@@ -107,7 +118,7 @@ function registerAjaxCommentRecord() {
     })
     .fail(function addCommentFail(response, textStatus) {
       if (textStatus === 'abort' || typeof response.responseJSON === 'undefined') { return; }
-      VuFind.lightbox.update(response.responseJSON.data);
+      VuFind.lightbox.alert(response.responseJSON.data, 'danger');
     });
     return false;
   });
diff --git a/themes/bootstrap3/templates/RecordTab/usercomments.phtml b/themes/bootstrap3/templates/RecordTab/usercomments.phtml
index 2236461e4e7eaebee54926dfbea1574f04e56314..4bd7cb6e88b426ba9feab25c73d9265f456ed44f 100644
--- a/themes/bootstrap3/templates/RecordTab/usercomments.phtml
+++ b/themes/bootstrap3/templates/RecordTab/usercomments.phtml
@@ -6,7 +6,7 @@
 <div class="comment-list">
   <?=$this->render('record/comments-list.phtml')?>
 </div>
-<form class="comment-form row" name="commentRecord" action="<?=$this->recordLink()->getActionUrl($this->driver, 'AddComment')?>" method="post">
+<form class="comment-form" name="commentRecord" action="<?=$this->recordLink()->getActionUrl($this->driver, 'AddComment')?>" method="post">
   <div class="row">
     <div class="col-sm-3 name">
       <input type="hidden" name="id" value="<?=$this->escapeHtmlAttr($this->driver->getUniqueId())?>"/>
@@ -17,6 +17,9 @@
       <? $user = $this->auth()->isLoggedIn() ?>
       <? if($user): ?>
         <textarea name="comment" class="form-control" rows="3" required></textarea><br/>
+        <? if ($this->tab->isRecaptchaActive()): ?>
+          <?=$this->recaptcha()->html(true, false) ?><br/>
+        <? endif; ?>
         <input class="btn btn-primary" data-loading-text="<?=$this->transEsc('Submitting') ?>..." type="submit" value="<?=$this->transEsc("Add your comment")?>"/>
       <? else: ?>
         <a href="<?=$this->url('myresearch-userlogin') ?>" class="btn btn-primary" data-lightbox title="Login"><i class="fa fa-sign-in" aria-hidden="true"></i> <?=$this->transEsc("You must be logged in first") ?></a>