Skip to main content
Prerequisites: SDK v2.2.0+ installed, a published template with an effective version, and your App ID.
Use ClicktermDom.renderInline() to embed a clickwrap agreement as a checkbox directly in your page. Unlike dialog mode (which shows a modal overlay), inline mode gives you full control over where the checkbox appears and when the agreement is submitted.

Integration flow

Sequence diagram showing the inline clickwrap integration flow between End-User, Your Website, ClickTerm SDK, Your Backend, and ClickTerm API

When to use inline mode

InlineDialog
UICheckbox embedded in your pageFull-screen modal overlay
SubmissionYou call finalize() when ready (e.g., on form submit)User clicks Accept/Decline in the modal
Multiple on one pageYesOne modal at a time
Best forRegistration forms, checkouts, multi-consent flowsStandalone consent screens, blocking prompts

Basic usage

<div id="my-consent"></div>
const { ClicktermClient, ClicktermDom } = window.Clickterm;
ClicktermClient.initialize('YOUR_CLICKTERM_APP_ID');

const handle = await ClicktermDom.renderInline(
  'my-consent',
  {
    endUserId: 'user-123',
    clickwrapTemplateId: 'YOUR_TEMPLATE_ID',
  }
);

// Finalize when the user submits your form
document.getElementById('my-form').addEventListener('submit', async (e) => {
  e.preventDefault();
  const result = await handle.finalize();
  console.log('Status:', result.status);
  console.log('Signature:', result.clicktermSignature);
  // Send result.clicktermSignature to your backend for verification
});

Step-by-step

1

Prepare a container

Add an empty element with a unique id where the checkbox should appear:
<div id="consent-checkbox"></div>
The container must exist in the DOM when renderInline() is called and must not already have another inline clickwrap rendered in it.
2

Render the inline clickwrap

Call ClicktermDom.renderInline() with the container ID, request parameters, and optional callbacks:
const handle = await ClicktermDom.renderInline(
  'consent-checkbox',
  {
    endUserId: 'user-123',
    clickwrapTemplateId: 'YOUR_TEMPLATE_ID',
    language: 'en',
    templatePlaceholders: { fullName: 'Alice Johnson' },
  },
  {
    onChange: (checked) => {
      document.getElementById('submit-btn').disabled = !checked;
    },
  }
);
The SDK fetches the agreement content, renders a checkbox + text inside a Shadow DOM in your container, and returns a handle.
3

Use the onChange callback

The onChange callback fires every time the checkbox state changes. Use it to enable or disable your submit button:
onChange: (checked) => {
  submitButton.disabled = !checked;
}
4

Finalize on form submit

When the user submits your form, call finalize() on the handle. This locks the checkbox, reads its state, and sends the confirmation to ClickTerm:
const result = await handle.finalize();
if (result.status === 'ERROR') {
  console.error('Failed:', result.error?.message);
  // Checkbox is automatically unlocked for retry
} else {
  // Send result.clicktermSignature to your backend
}
5

Verify on your backend

Send the Signature to your server and call the ClickTerm verification endpoint. This step is the same as dialog mode — see Verifying a Signature for full details.

Parameters

ParameterTypeRequiredDescription
containerIdstringYesThe id of the HTML element to render into
endUserIdstringYesYour identifier for the end user (max 256 chars)
clickwrapTemplateIdstringYesTemplate ID from the ClickTerm dashboard
languagestringNoLanguage code (e.g., "en", "de"). See supported languages
templatePlaceholdersobjectNoKey-value pairs for placeholder substitution

Options

FieldTypeDescription
onChange(checked: boolean) => voidCalled every time the checkbox state changes
styleobjectVisual customization — see ClicktermDom styling reference

Result format

The finalize() method returns a ClicktermInlineFinalizeResult:
FieldTypeDescription
statusstringUNVERIFIED — verify the Signature server-side. ALREADY_ACCEPTED — user already accepted. ERROR — submission failed
clicktermSignaturestring | nullThe Signature to send to your backend for verification. null if not available
submittedStatusstringWhat was sent: ACCEPTED (checked) or DECLINED (unchecked)
errorErrorPresent only when status is ERROR
{
  "status": "UNVERIFIED",
  "clicktermSignature": "eyJhbGciOiJSUzI1NiJ9...",
  "submittedStatus": "ACCEPTED"
}
Requests to render an inline clickwrap are not counted toward billing. Only the verification step (POST /clickwrap/verify) is billed.

Handle types

Depending on the backend response, renderInline() may return different handle types:

Normal case

The user has not accepted yet. A checkbox and agreement text are rendered in the container.
const handle = await ClicktermDom.renderInline('container', request);
handle.isChecked();        // false (initially unchecked)
handle.getCurrentResult(); // null (not yet finalized)

Already accepted

The user already accepted this template in a previous session. No UI is rendered in the container.
const handle = await ClicktermDom.renderInline('container', request);
handle.isChecked();        // true (always)
handle.getCurrentResult(); // { status: 'ALREADY_ACCEPTED', clicktermSignature: null }

Existing signature

The backend has a signature from a different flow. No UI is rendered in the container.
const handle = await ClicktermDom.renderInline('container', request);
handle.isChecked();        // false
handle.getCurrentResult(); // { status: 'UNVERIFIED', clicktermSignature: '...' }

Handling all cases

const handle = await ClicktermDom.renderInline('container', request);
const initialResult = handle.getCurrentResult();

if (initialResult?.status === 'ALREADY_ACCEPTED') {
  // User already accepted — no checkbox shown, proceed with your flow
} else if (initialResult?.status === 'UNVERIFIED' && initialResult?.clicktermSignature) {
  // Existing signature — verify it server-side
} else {
  // Normal case — checkbox rendered, wait for user interaction
}

Multiple inline clickwraps

You can render multiple independent inline clickwraps on the same page. Each needs its own container and renderInline() call.
<div id="consent-tos"></div>
<div id="consent-privacy"></div>
const tosHandle = await ClicktermDom.renderInline('consent-tos', {
  endUserId: 'user-123',
  clickwrapTemplateId: 'TEMPLATE_TOS',
});

const privacyHandle = await ClicktermDom.renderInline('consent-privacy', {
  endUserId: 'user-123',
  clickwrapTemplateId: 'TEMPLATE_PRIVACY',
});

Finalizing all at once

Instead of calling finalize() on each handle, use finalizeAll():
const results = await ClicktermDom.finalizeAll();

// Or finalize specific ones
const results = await ClicktermDom.finalizeAll(['consent-tos', 'consent-privacy']);

// Check results
for (const [containerId, result] of Object.entries(results)) {
  if (result.status === 'ERROR') {
    console.error(`Failed for ${containerId}:`, result.error?.message);
  } else {
    console.log(`${containerId} signature:`, result.clicktermSignature);
  }
}

Error handling

Wrap renderInline() in try/catch. All errors are instances of ClickwrapError:
try {
  const handle = await ClicktermDom.renderInline('container', request, options);
} catch (error) {
  console.error('Failed to render:', error.message);
}
ErrorCauseFix
Container element not foundNo element with that ID in the DOMEnsure the element exists before calling renderInline()
Already rendered for containerrenderInline() called twice for the same containerCall handle.destroy() first, or use a different container
Missing inline contentBackend returned content without the inlineContent fieldCheck your template configuration — make sure inline content is set
Client not initializedClicktermClient.initialize() was not calledCall initialize() before any render calls
Finalize errors do not throw. They return a result with status: 'ERROR' and the checkbox is automatically unlocked for retry.

Full working example

A registration form with two inline clickwraps:
<form id="registration-form">
  <label>
    Email
    <input type="email" id="email" required />
  </label>

  <label>
    Password
    <input type="password" id="password" required />
  </label>

  <!-- Inline clickwrap containers -->
  <div id="consent-tos"></div>
  <div id="consent-privacy"></div>

  <button type="submit" id="submit-btn" disabled>Create Account</button>
</form>

<!-- Load the SDK — must come before the inline script -->
<script src="https://cdn.clickterm.com/sdk/clickterm-widget-2.2.1.min.js"></script>
<script>
  const { ClicktermClient, ClicktermDom } = window.Clickterm;
  ClicktermClient.initialize('YOUR_CLICKTERM_APP_ID');

  const submitBtn = document.getElementById('submit-btn');
  const checkboxStates = { tos: false, privacy: false };

  function updateSubmitButton() {
    submitBtn.disabled = !(checkboxStates.tos && checkboxStates.privacy);
  }

  async function init() {
    const tosHandle = await ClicktermDom.renderInline(
      'consent-tos',
      { endUserId: 'user-123', clickwrapTemplateId: 'TEMPLATE_TOS_ID' },
      {
        onChange: (checked) => { checkboxStates.tos = checked; updateSubmitButton(); },
        style: { checkbox: { color: '#2563EB', size: 18 } },
      }
    );

    const privacyHandle = await ClicktermDom.renderInline(
      'consent-privacy',
      { endUserId: 'user-123', clickwrapTemplateId: 'TEMPLATE_PRIVACY_ID' },
      {
        onChange: (checked) => { checkboxStates.privacy = checked; updateSubmitButton(); },
        style: { checkbox: { color: '#2563EB', size: 18 } },
      }
    );

    // Handle already-accepted cases
    if (tosHandle.getCurrentResult()?.status === 'ALREADY_ACCEPTED') {
      checkboxStates.tos = true;
    }
    if (privacyHandle.getCurrentResult()?.status === 'ALREADY_ACCEPTED') {
      checkboxStates.privacy = true;
    }
    updateSubmitButton();

    // Finalize on form submit
    document.getElementById('registration-form').addEventListener('submit', async (e) => {
      e.preventDefault();
      submitBtn.disabled = true;
      submitBtn.textContent = 'Creating account...';

      try {
        const results = await ClicktermDom.finalizeAll();
        const signatures = {};
        for (const [id, result] of Object.entries(results)) {
          if (result.status === 'ERROR') throw new Error(`Failed for ${id}`);
          signatures[id] = result.clicktermSignature;
        }
        // Send signatures + form data to your backend for verification
        console.log('Signatures:', signatures);
      } catch (error) {
        console.error('Registration failed:', error);
        submitBtn.disabled = false;
        submitBtn.textContent = 'Create Account';
      }
    });
  }

  init().catch(console.error);
</script>

Next steps

Verifying a Signature

Verify the user’s action on your backend.

ClicktermDom API

Full API reference, styling options, and type definitions.

Template placeholders

Pass dynamic data into the agreement text.

Dialog mode

Use the modal dialog approach instead.