Truform Integration Guide

Everything needed to add Truform to a website form, verify responses on the server, and choose the right display options.

Overview

Truform protects forms with an "I'm human" checkbox. When clicked, it opens an interactive puzzle. After a successful solve, Truform adds a hidden response field to the form.

Important: The browser integration proves that the visitor completed the widget. Your server must verify the returned response before accepting the form submission.

Keys

Each protected site uses two keys:

Key Where It Is Used Safe To Expose?
public site key Inside the HTML snippet. Yes.
private secret key Only on your server when verifying a response. No.

Never put the private secret key in HTML, JavaScript, client apps, or public repositories.

Basic Install

Add the Truform container inside your form and load the remote script.

<form method="post" action="/contact-submit.php">
  <label>
    Email
    <input type="email" name="email" required>
  </label>

  <div
    class="truform"
    data-sitekey="your_public_site_key"
  ></div>

  <button type="submit">Submit</button>
</form>

<script src="https://your-truform-domain.example/truform/api.js?v=2026-05-22" async defer></script>

The script automatically loads Truform's stylesheet, so the widget keeps the same design and dimensions on every site.

Server Verification

After the puzzle is solved, Truform adds a hidden field named truform-response to the form. Verify that value from your server.

PHP Example

<?php
$verify = curl_init('https://your-truform-domain.example/truform/api/siteverify.php');
curl_setopt_array($verify, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => [
        'secret' => 'your_private_secret_key',
        'response' => $_POST['truform-response'] ?? '',
    ],
]);

$result = json_decode((string) curl_exec($verify), true);
curl_close($verify);

if (empty($result['success'])) {
    http_response_code(400);
    exit('Truform verification failed.');
}

// Continue processing the trusted form submission.

Verification Response

{
  "success": true,
  "challenge_ts": "2026-05-18T20:30:00+00:00",
  "hostname": "example.com",
  "type": "slider"
}

Widget Options

Theme

data-theme="light", dark, or auto.

Size

data-size="normal" for 304x78, or compact for 164x44.

Puzzle Type

route, sequence, slider, icon-select, odd-icon, or random.

Callback

data-callback="onTruformSolved" runs a browser function after a successful solve.

Full Snippet

<div
  class="truform"
  data-sitekey="your_public_site_key"
  data-theme="auto"
  data-size="normal"
  data-puzzle-type="random"
  data-callback="onTruformSolved"
></div>

<script>
  function onTruformSolved(response) {
    console.log('Truform solved:', response);
  }
</script>

<script src="https://your-truform-domain.example/truform/api.js?v=2026-05-22" async defer></script>

Manual Rendering

Use manual rendering when your form is created dynamically or when you want to control exactly when Truform appears.

<div id="truform-box"></div>

<script src="https://your-truform-domain.example/truform/api.js?v=2026-05-22"></script>
<script>
  truform.ready(async () => {
    const widgetId = await truform.render('#truform-box', {
      sitekey: 'your_public_site_key',
      theme: 'dark',
      size: 'compact',
      puzzleType: 'sequence'
    });

    console.log('Widget id:', widgetId);
  });
</script>

Client API

Method Purpose
truform.ready(callback) Runs code after the Truform loader is ready.
truform.render(container, options) Creates a widget manually.
truform.getResponse(widgetId) Returns the current response token, if solved.
truform.reset(widgetId) Resets a widget back to the checkbox state.

Domain Rules

Truform keys are locked to the domains configured for that key. If the site is not allowed, the widget cannot load a challenge.

Configured Domain Allowed Not Allowed
example.com example.com, www.example.com app.example.com
*.example.com example.com, app.example.com, www.example.com Unrelated domains
* Any domain None

Examples

Contact Form

<form method="post" action="/send-message.php">
  <input name="name" placeholder="Name" required>
  <input type="email" name="email" placeholder="Email" required>
  <textarea name="message" placeholder="Message" required></textarea>

  <div class="truform" data-sitekey="your_public_site_key"></div>

  <button type="submit">Send</button>
</form>
<script src="https://your-truform-domain.example/truform/api.js?v=2026-05-22" async defer></script>

Dark Compact Signup

<div
  class="truform"
  data-sitekey="your_public_site_key"
  data-theme="dark"
  data-size="compact"
  data-puzzle-type="random"
></div>

Troubleshooting

Issue What To Check
Widget does not appear Confirm api.js is loading and the container has class="truform" and data-sitekey.
Challenge says it cannot load Confirm the public site key is active and the current domain is allowed.
Old widget behavior after an update Change the ?v= value on api.js. The loader passes that version to its CSS and widget script.
Too many requests Wait for the rate window to pass, or ask the Truform administrator to clear rate limits for testing.
Form submits without verification Make sure the server checks truform-response with siteverify.php.
Verification fails on server Confirm you are using the private secret key, not the public site key.
Compact widget is too small for the layout Use data-size="normal" for desktop forms and reserve compact for narrow mobile layouts.

Production Checklist

  1. Add the Truform HTML container to each protected form.
  2. Load api.js once on the page.
  3. Use the public site key in the browser snippet.
  4. Verify truform-response on the server with the private secret key.
  5. Reject the form submission if server verification fails.
  6. Keep normal server-side validation, rate limiting, and abuse monitoring in place.