iCaptcha3D Documentation
How To Add iCaptcha3D To Your Form

This article is for web developers. It explains how to add the iCaptcha3D widget to an HTML form on your website, as demonstrated on our Contact Us page, and make it work properly. Sample working code is provided for both PHP and Craft CMS so you don't need to do everything from scratch.

Client Side

STEP 1:

Insert either the minimal or full version of the iCaptcha3D Widget Script between the <form> and </form> elements on your HTML page. Ideally, this script should be inserted just above the "Submit" button, so the iCaptcha3D widget is positioned near the end of the form.

iCaptcha3D Widget Script – Minimal Version:

<script src="https://control.icaptcha3d.com/icaptcha3d_show.i?icaptcha3d_key=your_public_key"></script>

iCaptcha3D Widget Script – Full Version:

<script src="https://control.icaptcha3d.com/icaptcha3d_show.i?icaptcha3d_key=your_public_key&amp;icaptcha3d_auth=auth_string&amp;icaptcha3d_resp=resp_value&amp;icaptcha3d_xtra=extra_value"></script>

Here icaptcha3d_key is a unique public key that identifies your website and which you receive when you create a new website profile using the iCaptcha3D Management Portal. Thus, replace your_public_key with the actual value of your public key. For example: icaptcha3d_key=icaptcha3d_pk_live_123adn7jMH123UIePT.

The icaptcha3d_auth and icaptcha3d_resp parameters that appear in the full version of the iCaptcha3D Widget Script are optional. They are needed only if you wish to avoid showing a new iCaptcha3D widget every time your form is re-displayed as a result of your own server-side form validation logic rejecting the submitted data. Of course, in that case you need to replace auth_string and resp_value with the actual icaptcha3d_auth and icaptcha3d_resp parameter values submitted to your form. For example, icaptcha3d_auth=auth_0_3-19074-1058_dtc5e0ff925807103101 and icaptcha3d_resp=2215. If you do this, the user will only have to solve the iCaptcha3D challenge once (i.e. during the first display of the form), no matter how many times your server-side form validation logic subsequently rejects the form submission. In all those submissions, the iCaptcha3D widget will be suppressed, which improves user experience and reduces friction for real users of your form.

For example, if you are using PHP to output the form and your form submits the data using the POST method, you can insert this script in the following way:

<script src="https://control.icaptcha3d.com/icaptcha3d_show.i?icaptcha3d_key=icaptcha3d_pk_live_123adn7jMH123UIePT&amp;icaptcha3d_auth=<?php echo htmlspecialchars($_POST['icaptcha3d_auth']) ?>&amp;icaptcha3d_resp=<?php echo htmlspecialchars($_POST['icaptcha3d_resp']) ?>"></script>

Or, if you are using Craft CMS and twig to output the form, you can accomplish the same by inserting the script in the following way:

<script src="https://control.icaptcha3d.com/icaptcha3d_show.i?icaptcha3d_key=icaptcha3d_pk_live_123adn7jMH123UIePT&amp;icaptcha3d_auth={ {craft.app.request.getBodyParam('icaptcha3d_auth')} }&amp;icaptcha3d_resp={ {craft.app.request.getBodyParam('icaptcha3d_resp')} }"></script>

Finally, the icaptcha3d_xtra parameter shown above is truly optional. It's needed only if you want to customize the appearance of the iCaptcha3D widget or change the default language (English). In all other cases you can either omit it or set extra_value to 0. More information about this parameter will be available in the Advanced iCaptcha3D Customization section in the near future.

STEP 2 (OPTIONAL BUT RECOMMENDED):

Add the following onsubmit attribute to your <form> element:

onsubmit="return icaptcha3d_onsubmit(this);"

This is simply to display an alert if the user tries to submit the form without first solving the iCaptcha3D challenge by clicking the “I am human” checkbox inside the widget. 

Here are two examples showing what the full <form> element might look like when this step is completed:

Example 1:

<form onsubmit="return icaptcha3d_onsubmit(this);" action="submit.php" class="form" method="post" enctype="multipart/form-data">

Example 2:

<form onsubmit="return icaptcha3d_onsubmit(this);" action="" class="contact" method="post" accept-charset="UTF-8">

Adding the onsubmit attribute is useful and recommended since the alert makes it very clear to the user that iCaptcha3D must be solved, if they forget to do so, before the form is even submitted to the server. This saves time and improves user experience. However, if you don't want to display this alert and wish to rely exclusively on the server-side form validation, you can completely omit this step.

Server Side

Once your form is submitted, in addition to performing any form validation on the server required by your own business logic, you also need to send a secure POST request to the iCaptcha3D verification server to actually validate and expire the icaptcha3d_auth and icaptcha3d_resp values. Remember that bots can submit the form data without ever interacting with the iCaptcha3D widget or any other element of your form, so this step is required. Without this step your iCaptcha3D protection would be ineffective and incomplete. In other words, you cannot rely solely on the client-side iCaptcha3D verification.

The following shows the entire POST request you must send to the iCaptcha3D verification server:

POST https://control.icaptcha3d.com/icaptcha3d_verify.i HTTP/1.1
Content Type: application/x-www-form-urlencoded

icaptcha3d_key=your_public_key&icaptcha3d_sec=your_secret_key&icaptcha3d_auth=auth_string&icaptcha3d_resp=resp_value&icaptcha3d_xtra=extra_value

The icaptcha3d_key, icaptcha3d_auth, icaptcha3d_resp and icaptcha3d_xtra parameters have already been described above, so we will not repeat that here. The icaptcha3d_sec parameter is your unique secret key that identifies your website and which you receive when you create a new website profile using your iCaptcha3D Management Portal, in addition to your public key. For example: icaptcha3d_sec=icaptcha3d_sk_live_MR3eErYajII. This secret key needs to be included only in this POST request to the iCaptcha3D verification server and nowhere else. It's your own secret and should not be revealed to third parties.

If you are using PHP and your form uses the POST method to submit the data, you can send this secure POST request by calling the iCaptcha3D_Verify function provided in the following fully functional code snippet:

function JsonToArray($data) { return json_decode($data, true); }
function ArrayValGet($arr, $key, $empty_val = '') { return (isset($arr[$key]) ? $arr[$key] : $empty_val); }

function POSTRequest($uri, $options_arr = NULL)
{
   if ($options_arr)
   {
      $context = stream_context_create($options_arr);
      $data = file_get_contents($uri, false, $context);
   }
   else
   {
      $data = file_get_contents($uri);
   }

   return $data;
}

function iCaptcha3D_POSTRequest($icaptcha3d_url, $icaptcha3d_key, $icaptcha3d_sec, $icaptcha3d_auth, $icaptcha3d_resp, $icaptcha3d_xtra = 0)
{
   $l = strlen($icaptcha3d_auth); if ($l < 1 || $l > 128) return false;
   $l = strlen($icaptcha3d_resp); if ($l < 1 || $l > 128) return false;

   $post_header = 'Content-Type: application/x-www-form-urlencoded';
   $post_content = 'icaptcha3d_key=' . $icaptcha3d_key . '&icaptcha3d_sec=' . $icaptcha3d_sec . '&icaptcha3d_auth=' . $icaptcha3d_auth . '&icaptcha3d_resp=' . $icaptcha3d_resp . '&icaptcha3d_xtra=' . $icaptcha3d_xtra;

   $options_arr = array
   (
      'ssl'=>array
      (
         'verify_peer' => false,
         'verify_peer_name' => false
      ),
      'http' => array
      (
         'method' => 'POST',
         'header' => $post_header,
         'content' => $post_content
      )
   );

   $icaptcha3d_data_json = POSTRequest($icaptcha3d_url, $options_arr);

   $icaptcha3d_data_array = JsonToArray($icaptcha3d_data_json);
   $icaptcha3d_status = ArrayValGet($icaptcha3d_data_array, 'status');

   if ($icaptcha3d_status == 'solved') return true;
   return false;
}

function iCaptcha3D_Verify()
{
   $icaptcha3d_url = 'https://control.icaptcha3d.com/icaptcha3d_verify.i';
   $icaptcha3d_key = 'icaptcha3d_pk_live_123adn7jMH123UIePT';
   $icaptcha3d_sec = 'icaptcha3d_sk_live_MeR5e312UueErYajII';
   $icaptcha3d_auth = $_POST['icaptcha3d_auth']; //e.g. auth_0_3-19074-1058_dtc5e0ff925807103101
   $icaptcha3d_resp = $_POST['icaptcha3d_resp']; //e.g. 2215

   $icaptcha3d_solved = iCaptcha3D_POSTRequest($icaptcha3d_url, $icaptcha3d_key, $icaptcha3d_sec, $icaptcha3d_auth, $icaptcha3d_resp);

   if ($icaptcha3d_solved)
   {
      echo 'iCaptcha3D Challenge Solved!';
      return true;
   }

   echo 'iCaptcha3D Challenge Failed!';
   return false;
}

If you are using curl, you can do the same like this:

curl -s https://control.icaptcha3d.com/icaptcha3d_verify.i -d icaptcha3d_key=your_public_key -d icaptcha3d_sec=your_secret_key -d icaptcha3d_auth=auth_string -d icaptcha3d_resp=resp_value -d icaptcha3d_xtra=extra_value

Or, if you are using the Contact Form plugin for Craft CMS, you can simply replace the default modules/Module.php file with the one provided below. This will add the iCaptcha3D protection capability to all your forms submitted using the Contact Form plugin. As a result, any form submissions that fail the iCaptcha3D challenge will be marked as Spam and will not be sent to the destination email address.

modules/Module.php:

<?php
namespace modules;

use Craft;

use craft\contactform\events\SendEvent;
use craft\contactform\Mailer;
use yii\base\Event;

/**
* Custom module class.
*
* This class will be available throughout the system via: `Craft::$app->getModule('my-module')`.
*
* You can change its module ID ("my-module") to something else from config/app.php.
*
* If you want the module to get loaded on every request, uncomment this line in config/app.php:
*
*    'bootstrap' => ['my-module']
*
* Learn more about Yii module development in Yii's documentation:
* http://www.yiiframework.com/doc-2.0/guide-structure-modules.html
*/

class Module extends \yii\base\Module
{
  private function JsonToArray($data) { return json_decode($data, true); }
  private function ArrayValGet($arr, $key, $empty_val = '') { return (isset($arr[$key]) ? $arr[$key] : $empty_val); }

  private function POSTRequest($uri, $options_arr = NULL)
  {
     if ($options_arr)
     {
        $context = stream_context_create($options_arr);
        $data = file_get_contents($uri, false, $context);
     }
     else
     {
        $data = file_get_contents($uri);
     }

     return $data;
  }

  protected function iCaptcha3D_POSTRequest($icaptcha3d_url, $icaptcha3d_key, $icaptcha3d_sec, $icaptcha3d_auth, $icaptcha3d_resp, $icaptcha3d_xtra = 0)
  {
     $l = strlen($icaptcha3d_auth); if ($l < 1 || $l > 128) return false;
     $l = strlen($icaptcha3d_resp); if ($l < 1 || $l > 128) return false;

     $post_header = 'Content-Type: application/x-www-form-urlencoded';
     $post_content = 'icaptcha3d_key=' . $icaptcha3d_key . '&icaptcha3d_sec=' . $icaptcha3d_sec . '&icaptcha3d_auth=' . $icaptcha3d_auth . '&icaptcha3d_resp=' . $icaptcha3d_resp . '&icaptcha3d_xtra=' . $icaptcha3d_xtra;

     $options_arr = array
     (
        'ssl'=>array
        (
           'verify_peer' => false,
           'verify_peer_name' => false
        ),
        'http' => array
        (
           'method' => 'POST',
           'header' => $post_header,
           'content' => $post_content
        )
     );

     $icaptcha3d_data_json = $this->POSTRequest($icaptcha3d_url, $options_arr);

     $icaptcha3d_data_array = $this->JsonToArray($icaptcha3d_data_json);
     $icaptcha3d_status = $this->ArrayValGet($icaptcha3d_data_array, 'status');

     if ($icaptcha3d_status == 'solved') return true;
     return false;
  }

  protected function iCaptcha3D_Init()
  {
     Event::on(Mailer::class, Mailer::EVENT_BEFORE_SEND, function(SendEvent $e)
     {
        $request = Craft::$app->request;

        $icaptcha3d_url = 'https://control.icaptcha3d.com/icaptcha3d_verify.i';
        $icaptcha3d_key = 'icaptcha3d_pk_live_123adn7jMH123UIePT';
        $icaptcha3d_sec = 'icaptcha3d_sk_live_MeR5e312UueErYajII';
        $icaptcha3d_auth = $request->getBodyParam('icaptcha3d_auth'); //e.g. auth_0_3-19074-1058_dtc5e0ff925807103101
        $icaptcha3d_resp = $request->getBodyParam('icaptcha3d_resp'); //e.g. 2215

        $icaptcha3d_solved = $this->iCaptcha3D_POSTRequest($icaptcha3d_url, $icaptcha3d_key, $icaptcha3d_sec, $icaptcha3d_auth, $icaptcha3d_resp);

        if (!$icaptcha3d_solved) $e->isSpam = true;
     });
  }

  /**
   * Initializes the module.
   */

  public function init()
  {
     // Set a @modules alias pointed to the modules/ directory
     Craft::setAlias('@modules', __DIR__);

     // Set the controllerNamespace based on whether this is a console or web request
     if (Craft::$app->getRequest()->getIsConsoleRequest())
     {
        $this->controllerNamespace = 'modules\\console\\controllers';
     }
     else
     {
        $this->controllerNamespace = 'modules\\controllers';
     }

     parent::init();

     // Custom initialization code goes here...
     $this->iCaptcha3D_Init();
  }
}
?>

Regardless of what method you use to send the POST request, the answer you receive from the iCaptcha3D verification server will always be returned in JSON format as one of the following three possible response types:

Type 1 – Error (e.g. POST request is malformed):

{
   "status": "error",
   "description": "Invalid parameter"
}

Type 2 - iCaptcha3D Challenge Failed

{
   "status": "failed",
   "description": "User failed challenge."
}

Type 3 – iCaptcha3D Challenge Solved

{
   "status": "solved",
   "description": "User solved challenge."
}

You can assume the user has successfully solved the iCaptcha3D challenge only if you receive Type 3 response in which the value of the "status" member is "solved". In all other cases, you should assume that the user/bot failed the iCaptcha3D challenge and, therefore, either reject or discard the form submission.

Note that in the future additional members might be added to the above JSON responses, e.g. for diagnostic purposes or to provide additional information to the caller. The presence of those additional members should not cause your code to fail and/or properly parse out the status value.

GET HELP

No Answer?

If we don't have an answer for you here, send us an email with your questions and we'll be glad to help you!

Contact Support