diff --git a/config/install/recaptcha.settings.yml b/config/install/recaptcha.settings.yml
index 4591931..91b97b7 100644
--- a/config/install/recaptcha.settings.yml
+++ b/config/install/recaptcha.settings.yml
@@ -6,5 +6,5 @@ widget:
   theme: 'light'
   type: 'image'
   size: ''
+  badge: 'bottomright'
   tabindex: 0
-  noscript: false
diff --git a/config/schema/recaptcha.schema.yml b/config/schema/recaptcha.schema.yml
index dcc3b57..0a95764 100644
--- a/config/schema/recaptcha.schema.yml
+++ b/config/schema/recaptcha.schema.yml
@@ -29,9 +29,9 @@ recaptcha.settings:
         size:
           type: string
           label: 'Size'
+        badge:
+          type: string
+          label: 'Badge'
         tabindex:
           type: integer
           label: 'Tabindex'
-        noscript:
-          type: boolean
-          label: 'Enable fallback for browsers with JavaScript disabled'
diff --git a/js/recaptcha.invisible.js b/js/recaptcha.invisible.js
new file mode 100644
index 0000000..59b1276
--- /dev/null
+++ b/js/recaptcha.invisible.js
@@ -0,0 +1,125 @@
+/**
+ * @file
+ * Invisible reCaptcha behaviors.
+ */
+
+/* globals grecaptcha*/
+/* eslint-disable no-unused-vars*/
+/**
+ * The submit object that was clicked.
+ *
+ * @type {object}
+ */
+var clickedSubmit;
+var clickedSubmitEvent;
+var clickedSubmitAjaxEvent;
+
+
+/**
+ * reCaptcha data-callback that submits the form.
+ *
+ */
+function recaptchaOnInvisibleSubmit() {
+  'use strict';
+  jQuery(clickedSubmit).unbind('.recaptcha');
+  if (clickedSubmitAjaxEvent) {
+    jQuery(clickedSubmit).trigger(clickedSubmitAjaxEvent);
+  }
+  else {
+    jQuery(clickedSubmit).click();
+  }
+  clickedSubmitEvent = clickedSubmit = clickedSubmitAjaxEvent = '';
+}
+
+(function ($, Drupal) {
+  'use strict';
+
+  /**
+   * Handles the submission of the form with the invisible reCaptcha.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the behavior for the invisible reCaptcha.
+   */
+  Drupal.behaviors.invisibleRecaptcha = {
+    attach: function (context) {
+      if (Drupal.hasOwnProperty('Ajax')) {
+        var originalBeforeSubmit = Drupal.Ajax.prototype.beforeSubmit;
+        Drupal.Ajax.prototype.beforeSubmit = function (form_values, element, options) {
+          if (this.event === 'mousedown' && $(this.element).data('recaptcha-submit') && grecaptcha.getResponse().length === 0) {
+            clickedSubmit = this.element;
+            options.needsRevalidate = true;
+            this.progress.type = 'none';
+            clickedSubmitAjaxEvent = this.event;
+          }
+
+          originalBeforeSubmit.apply(this, arguments);
+        };
+
+        if (!$(document).data('invisible-recaptcha-ajax-send-processed')) {
+          $(document).ajaxSend(function (event, jqxhr, settings) {
+            if (settings.needsRevalidate) {
+              jqxhr.abort();
+              $(clickedSubmit).prop('disabled', false);
+            }
+          });
+
+          $(document).data('invisible-recaptcha-ajax-send-processed', true);
+        }
+      }
+      $('form', context).each(function () {
+        var $form = $(this);
+        if ($form.find('.g-recaptcha[data-size="invisible"]').length) {
+          $form.find(':submit').data('recaptcha-submit', true).on({
+            'mousedown.recaptcha': function (e) {
+              preventFormSubmit(this, e);
+            },
+            'click.recaptcha': function (e) {
+              preventFormSubmit(this, e);
+            }
+          });
+        }
+      });
+
+      /**
+       * Prevent form submit if recaptcha is not valid.
+       *
+       *   @param {Object} elem -  Triggering element.
+       *   @param {Object} event - Triggering event.
+       */
+      function preventFormSubmit(elem, event) {
+        if (grecaptcha.getResponse().length === 0) {
+          // We need validate form, to avoid prevention of html5 validation.
+          var form = $(elem).closest('form')[0];
+          if (form && typeof form.checkValidity === 'function' && !$(form).attr('validate')) {
+            if (form.checkValidity()) {
+              event.preventDefault();
+              event.stopPropagation();
+              clickedSubmitEvent = event.type;
+              validateInvisibleCaptcha(elem);
+            }
+            else {
+              if (typeof form.reportValidity === 'function') {
+                form.reportValidity();
+              }
+            }
+          }
+          else {
+            validateInvisibleCaptcha(elem);
+          }
+        }
+      }
+
+      /**
+       * Triggers the reCaptcha to validate the form.
+       *
+       * @param {object} button - The submit button object was clicked.
+       */
+      function validateInvisibleCaptcha(button) {
+        clickedSubmit = button;
+        grecaptcha.execute();
+      }
+    }
+  };
+})(jQuery, Drupal);
diff --git a/migrations/d6_recaptcha_settings.yml b/migrations/d6_recaptcha_settings.yml
index 67283bc..a164c17 100644
--- a/migrations/d6_recaptcha_settings.yml
+++ b/migrations/d6_recaptcha_settings.yml
@@ -6,7 +6,6 @@ migration_groups:
 source:
   plugin: variable
   variables:
-    - recaptcha_noscript
     - recaptcha_site_key
     - recaptcha_size
     - recaptcha_secret_key
@@ -21,7 +20,6 @@ process:
   'widget/type': recaptcha_type
   'widget/size': recaptcha_size
   'widget/tabindex': recaptcha_tabindex
-  'widget/noscript': recaptcha_noscript
 destination:
   plugin: config
   config_name: recaptcha.settings
diff --git a/migrations/d7_recaptcha_settings.yml b/migrations/d7_recaptcha_settings.yml
index 0bd295f..480dc47 100644
--- a/migrations/d7_recaptcha_settings.yml
+++ b/migrations/d7_recaptcha_settings.yml
@@ -6,7 +6,6 @@ migration_groups:
 source:
   plugin: variable
   variables:
-    - recaptcha_noscript
     - recaptcha_site_key
     - recaptcha_size
     - recaptcha_secret_key
@@ -23,7 +22,6 @@ process:
   'widget/type': recaptcha_type
   'widget/size': recaptcha_size
   'widget/tabindex': recaptcha_tabindex
-  'widget/noscript': recaptcha_noscript
 destination:
   plugin: config
   config_name: recaptcha.settings
diff --git a/recaptcha.libraries.yml b/recaptcha.libraries.yml
index 7471b37..e334a34 100644
--- a/recaptcha.libraries.yml
+++ b/recaptcha.libraries.yml
@@ -4,3 +4,10 @@ recaptcha:
   dependencies:
     - core/drupal
     - core/jquery
+
+recaptcha.invisible:
+  js:
+    js/recaptcha.invisible.js: {}
+  dependencies:
+    - core/jquery
+    - core/drupal
diff --git a/recaptcha.module b/recaptcha.module
index f821474..ea9c58a 100644
--- a/recaptcha.module
+++ b/recaptcha.module
@@ -41,20 +41,6 @@ function recaptcha_help($route_name, RouteMatchInterface $route_match) {
   }
 }
 
-/**
- * Implements hook_theme().
- */
-function recaptcha_theme() {
-  return [
-    'recaptcha_widget_noscript' => [
-      'variables' => [
-        'widget' => NULL,
-      ],
-      'template' => 'recaptcha-widget-noscript',
-    ],
-  ];
-}
-
 /**
  * Implements hook_captcha().
  */
@@ -89,23 +75,8 @@ function recaptcha_captcha($op, $captcha_type = '') {
 
           // Check if reCAPTCHA use globally is enabled.
           $recaptcha_src = 'https://www.google.com/recaptcha/api.js';
-          $recaptcha_src_fallback = 'https://www.google.com/recaptcha/api/fallback';
           if ($recaptcha_use_globally) {
             $recaptcha_src = 'https://www.recaptcha.net/recaptcha/api.js';
-            $recaptcha_src_fallback = 'https://www.recaptcha.net/recaptcha/api/fallback';
-          }
-
-          $noscript = '';
-          if ($config->get('widget.noscript')) {
-            $recaptcha_widget_noscript = [
-              '#theme' => 'recaptcha_widget_noscript',
-              '#widget' => [
-                'sitekey' => $recaptcha_site_key,
-                'recaptcha_src_fallback' => $recaptcha_src_fallback,
-                'language' => \Drupal::service('language_manager')->getCurrentLanguage()->getId(),
-              ],
-            ];
-            $noscript = $renderer->render($recaptcha_widget_noscript);
           }
 
           $attributes = [
@@ -118,12 +89,18 @@ function recaptcha_captcha($op, $captcha_type = '') {
           ];
           $captcha['form']['#attached']['library'][] = 'recaptcha/recaptcha';
 
+          // Set the callback for invisible captcha.
+          if ('invisible' === $config->get('widget.size')) {
+            $attributes['data-badge'] = $config->get('widget.badge');
+            $attributes['data-callback'] = 'recaptchaOnInvisibleSubmit';
+            $captcha['form']['#attached']['library'][] = 'recaptcha/recaptcha.invisible';
+          }
+
           // Filter out empty tabindex/size.
           $attributes = array_filter($attributes);
 
           $captcha['form']['recaptcha_widget'] = [
             '#markup' => '<div' . new Attribute($attributes) . '></div>',
-            '#suffix' => $noscript,
             '#attached' => [
               'html_head' => [
                 [
@@ -216,20 +193,3 @@ function recaptcha_captcha_validation($solution, $response, $element, $form_stat
   }
   return FALSE;
 }
-
-/**
- * Process variables for recaptcha-widget-noscript.tpl.php.
- *
- * @see recaptcha-widget-noscript.tpl.php
- */
-function template_preprocess_recaptcha_widget_noscript(&$variables) {
-  $variables['sitekey'] = $variables['widget']['sitekey'];
-  $variables['language'] = $variables['widget']['language'];
-  $variables['url'] = Url::fromUri($variables['widget']['recaptcha_src_fallback'], [
-    'query' => [
-      'k' => $variables['widget']['sitekey'],
-      'hl' => $variables['widget']['language'],
-    ],
-    'absolute' => TRUE,
-  ])->toString();
-}
diff --git a/src/Form/ReCaptchaAdminSettingsForm.php b/src/Form/ReCaptchaAdminSettingsForm.php
index 2029bf0..ef7c253 100644
--- a/src/Form/ReCaptchaAdminSettingsForm.php
+++ b/src/Form/ReCaptchaAdminSettingsForm.php
@@ -101,10 +101,41 @@ class ReCaptchaAdminSettingsForm extends ConfigFormBase {
       '#options' => [
         '' => $this->t('Normal (default)'),
         'compact' => $this->t('Compact'),
+        'invisible' => $this->t('Invisible'),
       ],
       '#title' => $this->t('Size'),
       '#type' => 'select',
     ];
+    $form['widget']['recaptcha_size_container_notice'] = [
+      '#type' => 'container',
+      '#states' => array(
+        'visible' => array(
+          ':input[name="recaptcha_size"]' => array('value' => 'invisible'),
+        ),
+      ),
+    ];
+    $link_to_captcha_settings = Url::fromRoute('captcha_settings')->toString();
+    $message = t('Uncheck <em>Add a description to the CAPTCHA</em> in <a href=":link_to_captcha_settings">CAPTCHA settings</a> or a fieldset with a description will be displayed to users.', [':link_to_captcha_settings' => $link_to_captcha_settings]);
+    $form['widget']['recaptcha_size_container_notice']['invisible'] = [
+      '#type' => 'markup',
+      '#markup' => '<p>' . $message . '</p>',
+    ];
+    $form['widget']['recaptcha_badge'] = [
+      '#default_value' => $config->get('widget.badge'),
+      '#description' => $this->t('Reposition the reCAPTCHA badge. "Inline" allows you to control the CSS.'),
+      '#options' => [
+        'bottomright' => $this->t('Bottom Right (default)'),
+        'bottomleft' => $this->t('Bottom Left'),
+        'inline' => $this->t('Inline'),
+      ],
+      '#title' => $this->t('Badge'),
+      '#type' => 'select',
+      '#states' => array(
+        'visible' => array(
+          ':input[name="recaptcha_size"]' => array('value' => 'invisible'),
+        ),
+      ),
+    ];
     $form['widget']['recaptcha_tabindex'] = [
       '#default_value' => $config->get('widget.tabindex'),
       '#description' => $this->t('Set the <a href=":tabindex">tabindex</a> of the widget and challenge (Default = 0). If other elements in your page use tabindex, it should be set to make user navigation easier.', [':tabindex' => Url::fromUri('https://www.w3.org/TR/html4/interact/forms.html', ['fragment' => 'adef-tabindex'])->toString()]),
@@ -113,12 +144,6 @@ class ReCaptchaAdminSettingsForm extends ConfigFormBase {
       '#type' => 'number',
       '#min' => -1,
     ];
-    $form['widget']['recaptcha_noscript'] = [
-      '#default_value' => $config->get('widget.noscript'),
-      '#description' => $this->t('If JavaScript is a requirement for your site, you should <strong>not</strong> enable this feature. With this enabled, a compatibility layer will be added to the captcha to support non-js users.'),
-      '#title' => $this->t('Enable fallback for browsers with JavaScript disabled'),
-      '#type' => 'checkbox',
-    ];
 
     return parent::buildForm($form, $form_state);
   }
@@ -136,8 +161,8 @@ class ReCaptchaAdminSettingsForm extends ConfigFormBase {
       ->set('widget.theme', $form_state->getValue('recaptcha_theme'))
       ->set('widget.type', $form_state->getValue('recaptcha_type'))
       ->set('widget.size', $form_state->getValue('recaptcha_size'))
+      ->set('widget.badge', $form_state->getValue('recaptcha_badge'))
       ->set('widget.tabindex', $form_state->getValue('recaptcha_tabindex'))
-      ->set('widget.noscript', $form_state->getValue('recaptcha_noscript'))
       ->save();
 
     parent::submitForm($form, $form_state);
diff --git a/templates/recaptcha-widget-noscript.html.twig b/templates/recaptcha-widget-noscript.html.twig
deleted file mode 100644
index b1737fe..0000000
--- a/templates/recaptcha-widget-noscript.html.twig
+++ /dev/null
@@ -1,29 +0,0 @@
-{#
-/**
- * @file recaptcha-widget-noscript.tpl.php
- * Default theme implementation to present the reCAPTCHA noscript code.
- *
- * Available variables:
- * - sitekey: Google web service site key.
- * - language: Current site language code.
- * - url: Google web service API url.
- *
- * @see template_preprocess()
- * @see template_preprocess_recaptcha_widget_noscript()
- *
- * @ingroup themeable
- */
-#}
-
-<noscript>
-  <div style="width: 302px; height: 352px;">
-    <div style="width: 302px; height: 352px; position: relative;">
-      <div style="width: 302px; height: 352px; position: absolute;">
-        <iframe src="{{ url }}" frameborder="0" scrolling="no" style="width: 302px; height:352px; border-style: none;"></iframe>
-      </div>
-      <div style="width: 250px; height: 80px; position: absolute; border-style: none; bottom: 21px; left: 25px; margin: 0px; padding: 0px; right: 25px;">
-        <textarea id="g-recaptcha-response" name="g-recaptcha-response" class="g-recaptcha-response" style="width: 250px; height: 80px; border: 1px solid #c1c1c1; margin: 0px; padding: 0px; resize: none;" value=""></textarea>
-      </div>
-    </div>
-  </div>
-</noscript>
diff --git a/tests/src/Functional/ReCaptchaBasicTest.php b/tests/src/Functional/ReCaptchaBasicTest.php
index eb40641..5acd0ee 100644
--- a/tests/src/Functional/ReCaptchaBasicTest.php
+++ b/tests/src/Functional/ReCaptchaBasicTest.php
@@ -150,21 +150,6 @@ class ReCaptchaBasicTest extends BrowserTestBase {
       'absolute' => TRUE,
     ];
     $this->assertSession()->responseContains(Html::escape(Url::fromUri('https://www.google.com/recaptcha/api.js', $options)->toString()), '[testReCaptchaOnLoginForm]: reCAPTCHA is shown on form.');
-    $this->assertSession()->responseNotContains($grecaptcha . '<noscript>', '[testReCaptchaOnLoginForm]: NoScript code is not enabled for the reCAPTCHA.');
-
-    // Test if the fall back url is properly build and noscript code added.
-    $this->config('recaptcha.settings')->set('widget.noscript', 1)->save();
-
-    $this->drupalGet('user/login');
-    $this->assertSession()->responseContains($grecaptcha . "\n" . '<noscript>', '[testReCaptchaOnLoginForm]: NoScript for reCAPTCHA is shown on form.');
-    $options = [
-      'query' => [
-        'k' => $site_key,
-        'hl' => \Drupal::service('language_manager')->getCurrentLanguage()->getId(),
-      ],
-      'absolute' => TRUE,
-    ];
-    $this->assertSession()->responseContains(Html::escape(Url::fromUri('https://www.google.com/recaptcha/api/fallback', $options)->toString()), '[testReCaptchaOnLoginForm]: Fallback URL with IFRAME has been found.');
 
     // Check if there is a reCAPTCHA with global url on the login form.
     $this->config('recaptcha.settings')->set('use_globally', TRUE)->save();
@@ -178,14 +163,6 @@ class ReCaptchaBasicTest extends BrowserTestBase {
       'absolute' => TRUE,
     ];
     $this->assertSession()->responseContains(Html::escape(Url::fromUri('https://www.recaptcha.net/recaptcha/api.js', $options)->toString()), '[testReCaptchaOnLoginForm]: Global reCAPTCHA is shown on form.');
-    $options = [
-      'query' => [
-        'k' => $site_key,
-        'hl' => \Drupal::service('language_manager')->getCurrentLanguage()->getId(),
-      ],
-      'absolute' => TRUE,
-    ];
-    $this->assertSession()->responseContains(Html::escape(Url::fromUri('https://www.recaptcha.net/recaptcha/api/fallback', $options)->toString()), '[testReCaptchaOnLoginForm]: Global fallback URL with IFRAME has been found.');
 
     // Check that data-size attribute does not exists.
     $this->config('recaptcha.settings')->set('widget.size', '')->save();
