Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.spitshake.io/llms.txt

Use this file to discover all available pages before exploring further.

Template Builder Web Component

The <docuseal-builder> web component renders the full template editor inside your application. Users can upload documents, drag and drop fields, configure submitter roles, and save templates — all without leaving your page.

Quick start

Generate a JWT token server-side, then embed the builder:
<script src="https://your-app.com/js/docutrust-embed.js"></script>

<docuseal-builder
  data-token="eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxNSIsImlzcyI6ImRvY3V0cnVzdCIsImF1ZCI6ImJ1aWxkZXIiLCJhaWQiOiIxIiwiaWF0IjoxNzQ0MTk1OTIwLCJleHAiOjE3NDQyMTAzMjAsIm9wdHMiOnsiYXV0b3NhdmUiOnRydWUsInByZXZpZXciOnRydWUsImZpZWxkcyI6W119fQ.abc123"
></docuseal-builder>
The builder always requires authentication. Use a JWT token from POST /api/embed/token (recommended for embedded use) or pass data-template-id when the user is already authenticated via a session cookie.

Attributes

The <docuseal-builder> component accepts 33 data-* attributes to control behavior, authentication, and UI.
AttributeTypeDefaultDescription
data-tokenstringJWT token generated via POST /api/embed/token with audience: "builder". This is the recommended authentication method for embedded builders. The token encodes the template ID, account scope, and UI options.
data-hoststringcurrent originThe base URL of your DocuTrust instance. Only needed when the embed script is served from a different domain than the DocuTrust API. Example: "https://docs.your-app.com".
data-template-idstringTemplate ID to load in the builder. Only works when the user has an active session cookie (i.e., they are logged into DocuTrust in the same browser). For third-party embedding, use data-token instead.
data-languagestringUI language code. Supported values: "en", "es", "fr", "de", "pt", "it", "nl", "ja", "zh", "ko", "ar", "he".
data-autosave"false""true"Set to "false" to disable automatic saving. When disabled, the template is only saved when the user clicks Save or you call builder.save() programmatically.
data-preview"false""true"Set to "false" to hide the document preview panel on the right side of the builder.
data-with-title"false""true"Set to "false" to hide the editable template title field at the top of the builder.
data-with-send-button"false""true"Set to "false" to hide the “Send” button. Useful when you want to handle submission creation through your own UI or API calls.
data-with-recipients"false""true"Set to "false" to hide the recipients/submitter roles section. Useful when roles are pre-configured and should not be changed by the user.
data-only-defined-fields"true"When set, the field palette only shows the field types listed in data-fields. All other field types are hidden.
data-fieldsJSON stringPre-define the available fields as a JSON array. Each entry specifies a field name, type, and optional role assignment. See the Fields configuration section below.
data-rolesJSON stringPre-define submitter roles as a JSON array of role name strings. When provided, the user cannot add or remove roles. Example: '["Sender", "Recipient", "Witness"]'.
data-submittersJSON stringPre-define default submitters as a JSON array of objects with name and email properties. Example: '[{"name": "Recipient", "email": "jane@example.com"}]'.
data-required-fieldsJSON stringA JSON array of field names that must be placed on the document before saving. The builder shows a warning if any required field is missing. Example: '["Signature", "Date"]'.
data-field-typesstringComma-separated list of allowed field types in the field palette. Only the specified types are available for placement. Example: "text,signature,date,checkbox".
data-draw-field-typestringDefault field type when the user draws a new field on the document by clicking and dragging. Example: "text", "signature".
data-custom-button-titlestringCustom text for the primary action button in the builder toolbar. Replaces the default “Send” label. Example: "Publish Template".
data-custom-button-urlstringURL to navigate to when the custom button is clicked. When set, clicking the button navigates instead of triggering the send event.
data-with-upload-button"false""true"Set to "false" to hide the document upload button. Useful when documents are pre-loaded via the API.
data-with-add-page-button"true"Set to "true" to show an “Add blank page” button, allowing users to append empty pages to the document.
data-with-sign-yourself-button"false""true"Set to "false" to hide the “Sign yourself” button in the builder toolbar.
data-with-documents-list"false""true"Set to "false" to hide the documents sidebar listing all uploaded documents.
data-with-fields-list"false""true"Set to "false" to hide the fields sidebar listing all placed fields.
data-with-fields-detection"true"Set to "true" to show the AI-powered field detection button that automatically identifies and places fields on the document.
data-with-title-input"true"Set to "true" to show the editable template title input at the top of the builder. Equivalent to data-with-title.
data-with-send-myself-email"true"Set to "true" to show an option for the user to send themselves a copy of the template via email.
data-email-subjectstringCustom email subject line for emails sent from the builder. Supports template tokens like {{template.name}}.
data-email-bodystringCustom email body for emails sent from the builder. Supports template tokens like {{template.name}} and {{submitter.link}}.
data-background-colorstringBackground color for the builder as a HEX code (e.g., "#f9fafb"). Overrides the default background.
data-custom-cssstringCustom CSS rules injected into the builder iframe. Allows overriding default styles for advanced branding. Example: "body { font-family: 'Inter', sans-serif; }".
data-input-mode"true"When set to "true", enables data prefill mode. The builder shows a form for entering field values instead of the full drag-and-drop editor. Useful for creating pre-filled templates programmatically.
data-with-signature-id"true"When set to "true", displays a unique signature identifier alongside each signature field. Useful for audit and compliance tracking.
data-extract-fields"false""true"Set to "false" to disable automatic extraction of form fields from uploaded PDF documents. By default, DocuTrust auto-detects and places fields found in interactive PDF forms.

Full HTML example

<script src="https://your-app.com/js/docutrust-embed.js"></script>

<docuseal-builder
  id="template-builder"
  data-token="eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxNSIsImlzcyI6ImRvY3V0cnVzdCIsImF1ZCI6ImJ1aWxkZXIiLCJhaWQiOiIxIiwiaWF0IjoxNzQ0MTk1OTIwLCJleHAiOjE3NDQyMTAzMjAsIm9wdHMiOnsiYXV0b3NhdmUiOnRydWUsInByZXZpZXciOnRydWUsImZpZWxkcyI6W119fQ.abc123"
  data-host="https://your-app.com"
  data-language="en"
  data-autosave="true"
  data-preview="true"
  data-with-title="true"
  data-with-title-input="true"
  data-with-send-button="true"
  data-with-recipients="true"
  data-with-upload-button="true"
  data-with-add-page-button="false"
  data-with-sign-yourself-button="true"
  data-with-documents-list="true"
  data-with-fields-list="true"
  data-with-fields-detection="true"
  data-with-send-myself-email="false"
  data-only-defined-fields="true"
  data-draw-field-type="text"
  data-field-types="text,signature,initials,date,checkbox,select"
  data-custom-button-title="Publish Template"
  data-custom-button-url="https://your-app.com/templates/15/published"
  data-email-subject="Please sign: {{template.name}}"
  data-email-body="Hi, please review and sign the document: {{submitter.link}}"
  data-background-color="#f9fafb"
  data-custom-css="body { font-family: 'Inter', sans-serif; }"
  data-input-mode="false"
  data-with-signature-id="false"
  data-extract-fields="true"
  data-roles='["Sender", "Recipient", "Witness"]'
  data-submitters='[
    {"name": "Recipient", "email": "jane@example.com"},
    {"name": "Witness", "email": "witness@example.com"}
  ]'
  data-required-fields='["Recipient Signature", "Sender Signature", "Witness Signature"]'
  data-fields='[
    {"name": "Full Name", "type": "text", "role": "Recipient", "required": true},
    {"name": "Email", "type": "text", "role": "Recipient", "required": true},
    {"name": "Company", "type": "text", "role": "Recipient", "required": false},
    {"name": "Start Date", "type": "date", "role": "Recipient", "required": true},
    {"name": "Recipient Signature", "type": "signature", "role": "Recipient", "required": true},
    {"name": "Recipient Initials", "type": "initials", "role": "Recipient", "required": true},
    {"name": "Sender Signature", "type": "signature", "role": "Sender", "required": true},
    {"name": "Witness Signature", "type": "signature", "role": "Witness", "required": true},
    {"name": "Agreed to Terms", "type": "checkbox", "role": "Recipient", "required": true},
    {"name": "Department", "type": "select", "role": "Recipient", "required": false, "options": ["Engineering", "Sales", "Marketing", "Operations"]}
  ]'
></docuseal-builder>

Events

The <docuseal-builder> component emits DOM custom events. Listen with addEventListener on the element.

init

Fired when the web component is initialized and the iframe begins loading.
document.getElementById('template-builder').addEventListener('init', function (event) {
  console.log('Builder iframe is loading');
});
Event detail: null

load

Fired when the iframe has loaded and the builder is ready to render.
document.getElementById('template-builder').addEventListener('load', function (event) {
  console.log('Builder iframe loaded');
});
Event detail: null

loaded

Fired when the builder UI has fully rendered and is interactive.
document.getElementById('template-builder').addEventListener('loaded', function (event) {
  console.log('Builder ready:', event.detail);
});
Event detail:
{
  "template_id": 15,
  "template_name": "Employment Agreement",
  "account_id": 1,
  "submitters": [
    {
      "name": "Sender",
      "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
    },
    {
      "name": "Recipient",
      "uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
    },
    {
      "name": "Witness",
      "uuid": "c3d4e5f6-a7b8-9012-cdef-123456789012"
    }
  ],
  "documents": [
    {
      "id": 42,
      "filename": "employment_agreement.pdf",
      "content_type": "application/pdf",
      "page_count": 4
    }
  ],
  "fields": [
    {
      "name": "Full Name",
      "type": "text",
      "required": true,
      "submitter_uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "page": 1
    },
    {
      "name": "Recipient Signature",
      "type": "signature",
      "required": true,
      "submitter_uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "page": 4
    }
  ]
}

template-saved

Fired when the template is saved (either by auto-save or the user clicking Save).
document.getElementById('template-builder').addEventListener('template-saved', function (event) {
  var data = event.detail;
  console.log('Template saved:', data.template_id);
  console.log('Fields:', data.fields.length);
});
Event detail:
{
  "template_id": 15,
  "template_name": "Employment Agreement",
  "updated_at": "2026-04-08T14:22:45.000Z",
  "submitters": [
    {
      "name": "Sender",
      "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
    },
    {
      "name": "Recipient",
      "uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
    },
    {
      "name": "Witness",
      "uuid": "c3d4e5f6-a7b8-9012-cdef-123456789012"
    }
  ],
  "documents": [
    {
      "id": 42,
      "filename": "employment_agreement.pdf",
      "content_type": "application/pdf",
      "page_count": 4
    }
  ],
  "fields": [
    {
      "name": "Full Name",
      "type": "text",
      "required": true,
      "submitter_uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "page": 1,
      "areas": [{"x": 0.15, "y": 0.32, "w": 0.35, "h": 0.03, "page": 1}]
    },
    {
      "name": "Email",
      "type": "text",
      "required": true,
      "submitter_uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "page": 1,
      "areas": [{"x": 0.15, "y": 0.38, "w": 0.35, "h": 0.03, "page": 1}]
    },
    {
      "name": "Start Date",
      "type": "date",
      "required": true,
      "submitter_uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "page": 2,
      "areas": [{"x": 0.55, "y": 0.12, "w": 0.20, "h": 0.03, "page": 2}]
    },
    {
      "name": "Recipient Signature",
      "type": "signature",
      "required": true,
      "submitter_uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "page": 4,
      "areas": [{"x": 0.10, "y": 0.72, "w": 0.30, "h": 0.08, "page": 4}]
    },
    {
      "name": "Sender Signature",
      "type": "signature",
      "required": true,
      "submitter_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "page": 4,
      "areas": [{"x": 0.55, "y": 0.72, "w": 0.30, "h": 0.08, "page": 4}]
    }
  ]
}

template-data

Fired when the builder emits template data in response to a getTemplate() call or internal state change.
document.getElementById('template-builder').addEventListener('template-data', function (event) {
  console.log('Template data:', event.detail);
});
Event detail: Same structure as template-saved.

send

Fired when the user clicks the “Send” button inside the builder.
document.getElementById('template-builder').addEventListener('send', function (event) {
  var data = event.detail;
  console.log('User clicked Send for template:', data.template_id);
  // Open your own send dialog or create a submission via the API
});
Event detail:
{
  "template_id": 15,
  "template_name": "Employment Agreement",
  "submitters": [
    {
      "name": "Sender",
      "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
    },
    {
      "name": "Recipient",
      "uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
    },
    {
      "name": "Witness",
      "uuid": "c3d4e5f6-a7b8-9012-cdef-123456789012"
    }
  ]
}

upload

Fired when a document is uploaded to the builder.
document.getElementById('template-builder').addEventListener('upload', function (event) {
  var data = event.detail;
  console.log('Document uploaded:', data.filename);
});
Event detail:
{
  "template_id": 15,
  "document_id": 42,
  "filename": "employment_agreement.pdf",
  "content_type": "application/pdf",
  "size": 184320,
  "page_count": 4
}

change

Fired when any change occurs in the builder — field added, moved, resized, deleted, or properties updated. Useful for tracking unsaved changes or implementing custom auto-save logic.
document.getElementById('template-builder').addEventListener('change', function (event) {
  var data = event.detail;
  console.log('Builder changed:', data.change_type);
  console.log('Template ID:', data.template_id);
  console.log('Fields count:', data.fields.length);
});
Event detail:
{
  "template_id": 15,
  "template_name": "Employment Agreement",
  "change_type": "field_added",
  "submitters": [
    {
      "name": "Sender",
      "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
    },
    {
      "name": "Recipient",
      "uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
    },
    {
      "name": "Witness",
      "uuid": "c3d4e5f6-a7b8-9012-cdef-123456789012"
    }
  ],
  "documents": [
    {
      "id": 42,
      "filename": "employment_agreement.pdf",
      "content_type": "application/pdf",
      "page_count": 4
    }
  ],
  "fields": [
    {
      "name": "Full Name",
      "type": "text",
      "required": true,
      "submitter_uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "page": 1,
      "areas": [{"x": 0.15, "y": 0.32, "w": 0.35, "h": 0.03, "page": 1}]
    },
    {
      "name": "Recipient Signature",
      "type": "signature",
      "required": true,
      "submitter_uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "page": 4,
      "areas": [{"x": 0.10, "y": 0.72, "w": 0.30, "h": 0.08, "page": 4}]
    }
  ]
}

Public methods

The <docuseal-builder> element exposes two public methods for programmatic interaction.

getTemplate()

Returns a Promise that resolves with the current template state. The method communicates with the builder iframe via postMessage and has a 5-second timeout.
var builder = document.getElementById('template-builder');

async function saveAndLog() {
  try {
    var template = await builder.getTemplate();
    console.log('Template ID:', template.template_id);
    console.log('Template name:', template.template_name);
    console.log('Fields:', template.fields.length);
    console.log('Submitters:', template.submitters.map(function (s) { return s.name; }));
  } catch (error) {
    console.error('Failed to get template (timeout or error):', error.message);
  }
}

saveAndLog();
Return value:
{
  "template_id": 15,
  "template_name": "Employment Agreement",
  "updated_at": "2026-04-08T14:22:45.000Z",
  "submitters": [
    {
      "name": "Sender",
      "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
    },
    {
      "name": "Recipient",
      "uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
    },
    {
      "name": "Witness",
      "uuid": "c3d4e5f6-a7b8-9012-cdef-123456789012"
    }
  ],
  "documents": [
    {
      "id": 42,
      "filename": "employment_agreement.pdf",
      "content_type": "application/pdf",
      "page_count": 4
    }
  ],
  "fields": [
    {
      "name": "Full Name",
      "type": "text",
      "required": true,
      "submitter_uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "page": 1,
      "areas": [{"x": 0.15, "y": 0.32, "w": 0.35, "h": 0.03, "page": 1}]
    },
    {
      "name": "Recipient Signature",
      "type": "signature",
      "required": true,
      "submitter_uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "page": 4,
      "areas": [{"x": 0.10, "y": 0.72, "w": 0.30, "h": 0.08, "page": 4}]
    }
  ]
}

save()

Triggers a save operation via postMessage to the builder iframe. This is equivalent to the user clicking the Save button. The save is asynchronous — listen for the template-saved event to confirm completion.
var builder = document.getElementById('template-builder');

// Trigger a save
builder.save();

// Listen for confirmation
builder.addEventListener('template-saved', function (event) {
  console.log('Template saved at:', event.detail.updated_at);
});

Fields configuration

The data-fields attribute accepts a JSON array of field definitions. Each field object supports the following properties:
PropertyTypeRequiredDescription
namestringYesDisplay name of the field
typestringYesField type (see table below)
rolestringNoSubmitter role this field is assigned to
requiredbooleanNoWhether the field must be filled before submission
optionsstring[]NoAvailable options for select and radio field types
Supported field types:
TypeDescription
textSingle-line text input
signatureSignature pad (draw, type, or upload)
initialsInitials pad
dateDate picker
checkboxCheckbox toggle
selectDropdown select
radioRadio button group
numberNumeric input
fileFile upload
imageImage upload
stampStamp/seal placement
cellsCharacter-per-cell input (for codes, SSNs, etc.)
phonePhone number input
paymentPayment collection field
phone_verificationPhone + SMS OTP verification
Example with data-only-defined-fields: When you set data-only-defined-fields="true", only the field types specified in data-fields appear in the field palette. This is useful when you want to restrict what fields a user can place on the document.
<docuseal-builder
  data-token="YOUR_JWT_TOKEN"
  data-only-defined-fields="true"
  data-fields='[
    {"name": "Full Name", "type": "text", "role": "Recipient", "required": true},
    {"name": "Signature", "type": "signature", "role": "Recipient", "required": true},
    {"name": "Date Signed", "type": "date", "role": "Recipient", "required": true},
    {"name": "Agreed", "type": "checkbox", "role": "Recipient", "required": true}
  ]'
></docuseal-builder>

React integration

import { useEffect, useRef, useCallback } from 'react';

function TemplateBuilder({ token, onSaved, onSend, onChange }) {
  const builderRef = useRef(null);

  const handleSaved = useCallback((event) => {
    const data = event.detail;
    console.log('Template saved:', data.template_id, data.template_name);
    console.log('Fields:', data.fields.length);
    if (onSaved) onSaved(data);
  }, [onSaved]);

  const handleSend = useCallback((event) => {
    const data = event.detail;
    console.log('Send clicked for template:', data.template_id);
    if (onSend) onSend(data);
  }, [onSend]);

  const handleUpload = useCallback((event) => {
    const data = event.detail;
    console.log('Document uploaded:', data.filename, `(${data.page_count} pages)`);
  }, []);

  const handleChange = useCallback((event) => {
    const data = event.detail;
    console.log('Builder changed:', data.change_type, 'Fields:', data.fields.length);
    if (onChange) onChange(data);
  }, [onChange]);

  useEffect(() => {
    const el = builderRef.current;
    if (!el) return;

    el.addEventListener('template-saved', handleSaved);
    el.addEventListener('send', handleSend);
    el.addEventListener('upload', handleUpload);
    el.addEventListener('change', handleChange);

    return () => {
      el.removeEventListener('template-saved', handleSaved);
      el.removeEventListener('send', handleSend);
      el.removeEventListener('upload', handleUpload);
      el.removeEventListener('change', handleChange);
    };
  }, [handleSaved, handleSend, handleUpload, handleChange]);

  async function handleGetTemplate() {
    const el = builderRef.current;
    if (!el) return;
    try {
      const template = await el.getTemplate();
      console.log('Current template state:', template);
    } catch (err) {
      console.error('Timeout getting template:', err.message);
    }
  }

  function handleManualSave() {
    const el = builderRef.current;
    if (el) el.save();
  }

  return (
    <div>
      <div style={{ marginBottom: '12px' }}>
        <button onClick={handleManualSave}>Save Template</button>
        <button onClick={handleGetTemplate}>Get Template State</button>
      </div>
      <docuseal-builder
        ref={builderRef}
        data-token={token}
        data-language="en"
        data-autosave="true"
        data-preview="true"
        data-with-title="true"
        data-with-title-input="true"
        data-with-send-button="true"
        data-with-recipients="true"
        data-with-upload-button="true"
        data-with-add-page-button="false"
        data-with-sign-yourself-button="true"
        data-with-documents-list="true"
        data-with-fields-list="true"
        data-with-fields-detection="true"
        data-with-send-myself-email="false"
        data-draw-field-type="text"
        data-field-types="text,signature,date,checkbox"
        data-custom-button-title="Publish Template"
        data-custom-button-url="https://your-app.com/templates/published"
        data-email-subject="Please sign: {{template.name}}"
        data-email-body="Hi, please review and sign: {{submitter.link}}"
        data-background-color="#f9fafb"
        data-custom-css="body { font-family: 'Inter', sans-serif; }"
        data-input-mode="false"
        data-with-signature-id="false"
        data-extract-fields="true"
        data-roles='["Sender", "Recipient"]'
        data-submitters={JSON.stringify([
          { name: 'Recipient', email: 'jane@example.com' }
        ])}
        data-required-fields={JSON.stringify(['Signature', 'Date'])}
        data-fields={JSON.stringify([
          { name: 'Full Name', type: 'text', role: 'Recipient', required: true },
          { name: 'Signature', type: 'signature', role: 'Recipient', required: true },
          { name: 'Date', type: 'date', role: 'Recipient', required: true },
          { name: 'Sender Signature', type: 'signature', role: 'Sender', required: true }
        ])}
      />
    </div>
  );
}

export default TemplateBuilder;