Google reCAPTCHA v3 is an invisible type of captcha where the user doesn’t have to interact. It tracks the user behavior on the site and returns a score between 0 to 1 with the response.
This score is use for validation on the server side.
In this tutorial, I show how you can add Google reCAPTCHA v3 to your form in CodeIgniter 4.

Contents
- Get Google reCaptcha keys
- Create variables in .env
- Enable CSRF
- Create custom validation for reCaptcha v3
- Create Controller
- Routes
- Create View
- Output
- Conclusion
1. Get Google reCaptcha keys
You can skip this step if you already registered for Google reCAPTCHA v3 and have site and secret keys.
- Navigate to the following link and login into your account if not logged in.
- Following page will display.

- Here, enter label, select reCAPTCHA v3 from the reCAPTCHA type, enter your domain name without https e.g. makitweb.com. You can also specify
localhostif you want to test it on your local system. - Check the
Accept the reCAPTCHA Terms of Serviceand click the Submit button.

- Copy the site and secret keys.

2. Create variables in .env
- Open
.envfile which is available at the project root.
NOTE – If dot (.) not added at the start then rename the file to .env.
- Here, define 2 variables for storing the captcha site and secret keys –
GOOGLE_RECAPTCHAV3_SITEKEY = 6LdP-nIhAAAAAA6rzq7BTh_jKqIYeKMoaALxkKte GOOGLE_RECAPTCHAV3_SECRETKEY = 6LdV-nIhAAAAAL-uFI4w9kQUaqMkeU2K3KojlXyE
3. Enable CSRF
- Again open
.envfile. - Remove # from the start of the
security.tokenName,security.headerName,security.cookieName,security.expires,andsecurity.regenerate. - I update the
security.tokenNamevalue with'csrf_hash_name'. With this name read CSRF hash. You can update it with any other value. - If you don’t want to regenerate CSRF hash after each request then set
security.regenerate = false.
security.tokenName = 'csrf_hash_name' security.headerName = 'X-CSRF-TOKEN' security.cookieName = 'csrf_cookie_name' security.expires = 7200 security.regenerate = true
- Open
app/Config/Filters.phpfile. - Uncomment
'csrf'in'before'if commented.
// Always applied before every request
public $globals = [
'before' => [
// 'honeypot',
'csrf',
// 'invalidchars',
],
'after' => [
'toolbar',
// 'honeypot',
// 'secureheaders',
],
];
4. Create custom validation for reCaptcha v3
Create a rule to verify reCaptcha v3 response.
- Create a new
CaptchaValidation.phpfile inapp/Config/folder. - Create a
CaptchaValidationclass. - In the class create
verifyrecaptchaV3()method. Here, the method name is also a rule name. - Read the secret key from
.envfile and assign it to$secretkey. - Send request to –
https://www.google.com/recaptcha/api/siteverify?secret=".$secretkey."&response=".$str."&remoteip=".$_SERVER['REMOTE_ADDR']
- Here, pass secret key, recaptcha response, and IP address.
- It returns a JSON response.
- If
$responseData->successistrueand$responseData->scoreis>0.6 then returntrueotherwise, assign error message in$errorand returnfalse.
NOTE – You can update value of
$scorefrom 0.6 to any other value. Make sure to set it between 0.5 to 1.
Completed Code
<?php
namespace Config;
class CaptchaValidation{
public function verifyrecaptchaV3(string $str, ?string &$error = null): bool
{
$secretkey = getenv('GOOGLE_RECAPTCHAV3_SECRETKEY');
if(($str) && !empty($str)) {
$response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=".$secretkey."&response=".$str."&remoteip=".$_SERVER['REMOTE_ADDR']);
$responseData = json_decode($response);
$score = 0.6; // 0 - 1
if($responseData->success && $responseData->score > $score) { // Verified
return true;
}
}
$error = "Invalid captacha";
return false;
}
}
To use the above-created validation rule need to define it in the Validation.php file.
- Open
app/Config/Validation.phpfile. - Include
Config\CaptchaValidationclass. - Specify
CaptchaValidation::classin$ruleSetsArray.
Completed Code
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Validation\CreditCardRules;
use CodeIgniter\Validation\FileRules;
use CodeIgniter\Validation\FormatRules;
use CodeIgniter\Validation\Rules;
use Config\CaptchaValidation; // Custom reCAPTCHA v3 validation
class Validation extends BaseConfig
{
// --------------------------------------------------------------------
// Setup
// --------------------------------------------------------------------
/**
* Stores the classes that contain the
* rules that are available.
*
* @var string[]
*/
public $ruleSets = [
Rules::class,
FormatRules::class,
FileRules::class,
CreditCardRules::class,
CaptchaValidation::class, // Custom reCAPTCHA v3 validation
];
/**
* Specifies the views that are used to display the
* errors.
*
* @var array<string, string>
*/
public $templates = [
'list' => 'CodeIgniter\Validation\Views\list',
'single' => 'CodeIgniter\Validation\Views\single',
];
// --------------------------------------------------------------------
// Rules
// --------------------------------------------------------------------
}
5. Create Controller
Create PagesController Controller –
php spark make:controller PagesController
- Open
app/Controllers/PagesController.phpfile. - Create 2 methods –
- index() – Load
indexview. - submitContactUs() – This method calls on form submit.
- index() – Load
Validate the submitted values. Here, for validating recaptcha specify – 'recaptch_response' => 'required|verifyrecaptchaV3',.
verifyrecaptchaV3 is a custom validation rule created in the previous step.
If <form > is not validated then return to the page with error messages otherwise store the success message in SESSION flash and redirect to route('/').
Completed Code
<?php
namespace App\Controllers;
use App\Controllers\BaseController;
class PagesController extends BaseController
{
public function index(){
return view('index');
}
public function submitContactUs(){
// Validation
$input = $this->validate([
'name' => 'required',
'email' => 'required',
'subject' => 'required',
'message' => 'required',
'recaptcha_response' => 'required|verifyrecaptchaV3',
],[
'recaptcha_response' => [
'required' => 'Please verify captcha',
],
]);
if (!$input) { // Not valid
$data['validation'] = $this->validator;
return redirect()->back()->withInput()->with('validation', $this->validator);
}else{
// Set Session
session()->setFlashdata('message', 'Request Submitted Successfully!');
session()->setFlashdata('alert-class', 'alert-success');
}
return redirect()->route('/');
}
}
6. Routes
- Open
app/Config/Routes.phpfile. - Here, create 2 routes –
- /
- page/submitContactUs – Handle form submit.
$routes->get('/', 'PagesController::index');
$routes->post('page/submitContactUs', 'PagesController::submitContactUs');
7. Create View
- Create
index.phpfile inapp/Views/folder. - Include recaptcha js in
<head >section –
<!-- reCAPTCHA JS-->
<script src="https://www.google.com/recaptcha/api.js?render=<?= getenv('GOOGLE_RECAPTCHAV3_SITEKEY') ?>"></script>
Here, also specify sitekey.
- Create a contact form and set
actionURL to<?=site_url('page/submitContactUs')?>. DefineonSubmitevent on<form >that callsonSubmit(event). - Display an error message if
<form>element is not validated. In the<form >also display an error message if recaptcha is not validated. - Create a hidden element
#recaptcha_responseto store recapatcha token response on<form >submit. - Create a submit button.
Script
- Create
onSubmit()function that calls on<form >submit. - Call
grecaptcha.executeonsubmitaction to get a token. - Assign the token to the hidden element
#recaptcha_response. - Submit the
<form >.
Completed Code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>How to add Google reCAPTCHA v3 in CodeIgniter 4</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" >
<!-- reCAPTCHA JS-->
<script src="https://www.google.com/recaptcha/api.js?render=<?= getenv('GOOGLE_RECAPTCHAV3_SITEKEY') ?>"></script>
<!-- Include script -->
<script type="text/javascript">
function onSubmit(e) {
e.preventDefault();
grecaptcha.ready(function() {
grecaptcha.execute("<?= getenv('GOOGLE_RECAPTCHAV3_SITEKEY') ?>", {action: 'submit'}).then(function(token) {
// Store recaptcha response
document.getElementById("recaptcha_response").value = token;
// Submit form
document.getElementById("contactForm").submit();
});
});
}
</script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 mt-5" style="margin: 0 auto;">
<?php
// Display Response
if(session()->has('message')){
?>
<div class="alert <?= session()->getFlashdata('alert-class') ?>">
<?= session()->getFlashdata('message') ?>
</div>
<?php
}
?>
<h2 class="mb-4">Contact US</h2>
<?php $validation = \Config\Services::validation(); ?>
<form id="contactForm" method="post" action="<?=site_url('page/submitContactUs')?>" onSubmit="onSubmit(event)">
<?= csrf_field(); ?>
<!-- Recaptcha Error -->
<?php if( $validation->getError('recaptcha_response') ) {?>
<div class="alert alert-danger">
<?= $validation->getError('recaptcha_response'); ?>
</div>
<?php }?>
<div class="form-group mb-4">
<label class="control-label col-sm-2" for="name">Name:</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="name" placeholder="Enter Name" name="name" value="<?= old('name') ?>">
</div>
<!-- Error -->
<?php if( $validation->getError('name') ) {?>
<div class='text-danger mt-2'>
* <?= $validation->getError('name'); ?>
</div>
<?php }?>
</div>
<div class="form-group mb-4">
<label class="control-label col-sm-2" for="email">Email:</label>
<div class="col-sm-10">
<input type="email" class="form-control" id="email" placeholder="Enter Email" name="email" value="<?= old('email') ?>">
</div>
<!-- Error -->
<?php if( $validation->getError('email') ) {?>
<div class='text-danger mt-2'>
* <?= $validation->getError('email'); ?>
</div>
<?php }?>
</div>
<div class="form-group mb-4">
<label class="control-label col-sm-2" for="subject">Subject:</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="subject" placeholder="Enter Subject" name="subject" value="<?= old('subject') ?>" >
</div>
<!-- Error -->
<?php if( $validation->getError('subject') ) {?>
<div class='text-danger mt-2'>
* <?= $validation->getError('subject'); ?>
</div>
<?php }?>
</div>
<div class="form-group mb-4">
<label class="control-label col-sm-2" for="message">Message:</label>
<div class="col-sm-10">
<textarea class="form-control" id="message" name="message"><?= old('message') ?></textarea>
</div>
<!-- Error -->
<?php if( $validation->getError('message') ) {?>
<div class='text-danger mt-2'>
* <?= $validation->getError('message'); ?>
</div>
<?php }?>
</div>
<div class="form-group ">
<div class="col-sm-offset-2 col-sm-10">
<input type="hidden" id="recaptcha_response" name="recaptcha_response" value="">
<button type="submit" class="btn btn-info">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
8. Output
9. Conclusion
Using this you can protect your website without forcing the user to verify whether it is human or a bot.
You can also view this tutorial if you want to know Google reCAPTCHA v2 implementation in CodeIgniter 4.
If you found this tutorial helpful then don't forget to share.