JavaScript SDK
The SpitShake JavaScript SDK provides a globalwindow.SpitShake API for programmatic control over embedded signing forms and template builders. Use the SDK when you need imperative mounting, dynamic configuration, or event-driven integration that goes beyond static HTML attributes.
Loading the SDK
Include the embed script in your HTML. The script registerswindow.SpitShake and defines the <docuseal-form> and <docuseal-builder> web components.
<script src="https://your-app.com/js/spitshake-embed.js"></script>
function loadSpitShakeSDK(host) {
return new Promise(function (resolve, reject) {
if (window.SpitShake) {
resolve(window.SpitShake);
return;
}
var script = document.createElement('script');
script.src = host + '/js/spitshake-embed.js';
script.onload = function () { resolve(window.SpitShake); };
script.onerror = function () { reject(new Error('Failed to load SpitShake SDK')); };
document.head.appendChild(script);
});
}
// Usage
loadSpitShakeSDK('https://your-app.com').then(function (SpitShake) {
SpitShake.configure({ host: 'https://your-app.com' });
console.log('SpitShake SDK loaded');
});
Methods
SpitShake.configure(options)
Set the SpitShake instance URL. Call this once before mounting any forms or builders. Parameters:| Property | Type | Required | Description |
|---|---|---|---|
host | string | Yes | Base URL of your SpitShake instance, e.g., "https://your-app.com" |
SpitShake.configure({
host: 'https://your-app.com'
});
SpitShake.mount(options)
Mount a signing form into a container element. Returns the created DOM element. Parameters:| Property | Type | Required | Default | Description |
|---|---|---|---|---|
element | string or HTMLElement | Yes | — | CSS selector or DOM element to mount into |
submitterSlug | string | Yes | — | Submitter signing slug (the SLUG from /s/SLUG) |
withTitle | boolean | No | true | Show the template title |
withDownloadButton | boolean | No | true | Show the download button after completion |
withSendCopyButton | boolean | No | true | Show the “Send a copy” button |
allowToResubmit | boolean | No | false | Allow the signer to resubmit |
language | string | No | — | UI language code (e.g., "en", "es", "fr") |
email | string | No | — | Pre-fill signer email |
name | string | No | — | Pre-fill signer name |
role | string | No | — | Target a specific submitter role |
preview | boolean | No | false | Enable read-only preview mode |
goToLast | boolean | No | false | Jump to last incomplete field |
expand | boolean | No | false | Expand form to full content height |
autoscroll | boolean | No | true | Auto-scroll to next field |
skipFields | string | No | — | Comma-separated field names to skip |
readonlyFields | string | No | — | Comma-separated read-only field names |
values | object | No | — | Pre-fill field values as key-value pairs |
metadata | object | No | — | Custom metadata object |
completedRedirectUrl | string | No | — | Has no effect (it sets data-completed-redirect-url, which the signing page ignores). Set completed_redirect_url when you create the submission; see Redirect after completion. |
externalId | string | No | — | Link signer to your system ID |
token | string | No | — | JWT token for authentication |
logo | string | No | — | Custom logo URL |
i18n | object | No | — | Custom i18n key overrides |
withDecline | boolean | No | false | Show decline button |
withFieldNames | boolean | No | true | Show field labels |
withFieldPlaceholder | string | No | — | Placeholder text for fields |
withCompleteButton | boolean | No | true | Show complete button |
onlyRequiredFields | boolean | No | false | Show only required fields |
allowTypedSignature | boolean | No | true | Allow typed signatures |
signature | string | No | — | Pre-fill signature (base64/URL/text) |
sendCopyEmail | boolean | No | true | Allow send-copy email |
orderAsOnPage | boolean | No | false | Order fields by page position |
backgroundColor | string | No | — | Background color (HEX code) |
minimizeFirstStep | boolean | No | false | Collapse first step into compact bar |
customCss | string | No | — | Custom CSS rules injected into the form iframe |
completedMessageTitle | string | No | — | Custom completion screen title |
completedMessageBody | string | No | — | Custom completion screen body text |
completedButtonTitle | string | No | — | Custom completion button text |
completedButtonUrl | string | No | — | Custom completion button URL |
minimize | boolean | No | false | Always minimize (collapse) field panels |
<docuseal-form> DOM element.
var formElement = SpitShake.mount({
element: '#signing-container',
submitterSlug: 'aB3kL9mNpQ',
email: 'jane.doe@example.com',
name: 'Jane Doe',
role: 'Recipient',
externalId: 'usr_9f84b2a1',
logo: 'https://your-app.com/assets/logo.png',
language: 'en',
withTitle: true,
withDownloadButton: true,
withSendCopyButton: true,
withDecline: true,
withFieldNames: true,
withFieldPlaceholder: 'Enter value here',
withCompleteButton: true,
onlyRequiredFields: false,
allowToResubmit: false,
allowTypedSignature: true,
goToLast: true,
expand: true,
autoscroll: true,
preview: false,
minimizeFirstStep: true,
orderAsOnPage: false,
sendCopyEmail: true,
backgroundColor: '#ffffff',
customCss: 'body { font-family: "Inter", sans-serif; } .field-label { color: #1e3a5f; }',
completedMessageTitle: 'Thank you for signing!',
completedMessageBody: 'Your signed document will be emailed to you shortly.',
completedButtonTitle: 'Return to Dashboard',
completedButtonUrl: 'https://your-app.com/dashboard',
minimize: false,
skipFields: 'Internal Notes',
readonlyFields: 'Contract Amount,Start Date',
signature: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...',
values: {
'Full Name': 'Jane Doe',
'Email': 'jane.doe@example.com',
'Company': 'Acme Inc',
'Title': 'VP of Operations',
'Date': '2026-04-08'
},
metadata: {
customer_id: 'cust_8472',
deal_id: 'deal_291',
plan: 'enterprise',
source: 'sdk_integration'
},
i18n: {
submit: 'Confirm & Sign',
next: 'Continue',
decline: 'Decline to Sign'
}
});
console.log('Form mounted:', formElement);
SpitShake.mountBuilder(options)
Mount the template builder into a container element. Returns the created DOM element. Parameters:| Property | Type | Required | Default | Description |
|---|---|---|---|---|
element | string or HTMLElement | Yes | — | CSS selector or DOM element to mount into |
templateId | number or string | No | — | Template ID (session auth only) |
token | string | No | — | JWT token from POST /api/embed/token |
language | string | No | — | UI language code |
autosave | boolean | No | true | Enable auto-save |
preview | boolean | No | true | Show document preview panel |
withTitle | boolean | No | true | Show editable template title |
withSendButton | boolean | No | true | Show the “Send” button |
withRecipients | boolean | No | true | Show recipients section |
onlyDefinedFields | boolean | No | false | Only show pre-defined field types |
fields | array | No | — | Pre-defined field definitions |
roles | array | No | — | Pre-defined submitter role names |
host | string | No | — | Override the configured host URL |
submitters | array | No | — | Default submitters with name and email |
requiredFields | array | No | — | Field names required before saving |
fieldTypes | string | No | — | Comma-separated allowed field types |
drawFieldType | string | No | — | Default field type when drawing |
customButtonTitle | string | No | — | Custom primary button text |
customButtonUrl | string | No | — | URL for custom button navigation |
withUploadButton | boolean | No | true | Show upload button |
withAddPageButton | boolean | No | false | Show add blank page button |
withSignYourselfButton | boolean | No | true | Show sign yourself button |
withDocumentsList | boolean | No | true | Show documents sidebar |
withFieldsList | boolean | No | true | Show fields sidebar |
withFieldsDetection | boolean | No | false | Show AI field detection button |
withTitleInput | boolean | No | true | Show title input |
withSendMyselfEmail | boolean | No | false | Show email-to-self option |
emailSubject | string | No | — | Custom email subject |
emailBody | string | No | — | Custom email body |
backgroundColor | string | No | — | Background color (HEX code) |
customCss | string | No | — | Custom CSS rules injected into the builder iframe |
inputMode | boolean | No | false | Enable data prefill mode instead of full editor |
withSignatureId | boolean | No | false | Show signature ID alongside signature fields |
extractFields | boolean | No | true | Auto-extract fields from uploaded PDF forms |
<docuseal-builder> DOM element.
var builderElement = SpitShake.mountBuilder({
element: '#builder-container',
token: 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxNSIsImlzcyI6ImRvY3V0cnVzdCIsImF1ZCI6ImJ1aWxkZXIiLCJhaWQiOiIxIiwiaWF0IjoxNzQ0MTk1OTIwLCJleHAiOjE3NDQyMTAzMjAsIm9wdHMiOnsiYXV0b3NhdmUiOnRydWUsInByZXZpZXciOnRydWUsImZpZWxkcyI6W119fQ.abc123',
language: 'en',
autosave: true,
preview: true,
withTitle: true,
withTitleInput: true,
withSendButton: true,
withRecipients: true,
withUploadButton: true,
withAddPageButton: false,
withSignYourselfButton: true,
withDocumentsList: true,
withFieldsList: true,
withFieldsDetection: true,
withSendMyselfEmail: false,
onlyDefinedFields: false,
drawFieldType: 'text',
fieldTypes: 'text,signature,initials,date,checkbox,select',
customButtonTitle: 'Publish Template',
customButtonUrl: 'https://your-app.com/templates/15/published',
emailSubject: 'Please sign: {{template.name}}',
emailBody: 'Hi, please review and sign the document: {{submitter.link}}',
backgroundColor: '#f9fafb',
customCss: 'body { font-family: "Inter", sans-serif; }',
inputMode: false,
withSignatureId: false,
extractFields: true,
roles: ['Sender', 'Recipient', 'Witness'],
submitters: [
{ name: 'Recipient', email: 'jane@example.com' },
{ name: 'Witness', email: 'witness@example.com' }
],
requiredFields: ['Signature', 'Sender Signature', 'Witness Signature'],
fields: [
{ name: 'Full Name', type: 'text', role: 'Recipient', required: true },
{ name: 'Email', 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 },
{ name: 'Witness Signature', type: 'signature', role: 'Witness', required: true }
]
});
console.log('Builder mounted:', builderElement);
SpitShake.form(options)
Alias forSpitShake.mount(). Accepts the same parameters and returns the same result.
var formElement = SpitShake.form({
element: '#signing-container',
submitterSlug: 'aB3kL9mNpQ',
email: 'jane.doe@example.com',
name: 'Jane Doe',
role: 'Recipient',
externalId: 'usr_9f84b2a1',
logo: 'https://your-app.com/assets/logo.png',
language: 'en',
withTitle: true,
withDownloadButton: true,
withSendCopyButton: true,
withDecline: true,
withFieldNames: true,
withFieldPlaceholder: 'Enter value here',
withCompleteButton: true,
onlyRequiredFields: false,
allowToResubmit: false,
allowTypedSignature: true,
goToLast: true,
expand: true,
autoscroll: true,
minimizeFirstStep: false,
orderAsOnPage: false,
sendCopyEmail: true,
backgroundColor: '#ffffff',
customCss: 'body { font-family: "Inter", sans-serif; }',
completedMessageTitle: 'Thank you for signing!',
completedMessageBody: 'Your signed document will be emailed to you shortly.',
completedButtonTitle: 'Return to Dashboard',
completedButtonUrl: 'https://your-app.com/dashboard',
minimize: false,
signature: 'Jane Doe',
values: {
'Full Name': 'Jane Doe',
'Email': 'jane.doe@example.com',
'Company': 'Acme Inc',
'Title': 'VP of Operations',
'Date': '2026-04-08'
},
metadata: {
customer_id: 'cust_8472',
deal_id: 'deal_291',
source: 'sdk_integration'
},
i18n: {
submit: 'Confirm & Sign',
next: 'Continue'
}
});
SpitShake.builder(options)
Alias forSpitShake.mountBuilder(). Accepts the same parameters and returns the same result.
var builderElement = SpitShake.builder({
element: '#builder-container',
token: 'YOUR_JWT_TOKEN',
language: 'en',
autosave: true,
preview: true,
withTitle: true,
withTitleInput: true,
withSendButton: true,
withRecipients: true,
withUploadButton: true,
withAddPageButton: false,
withSignYourselfButton: true,
withDocumentsList: true,
withFieldsList: true,
withFieldsDetection: false,
withSendMyselfEmail: false,
onlyDefinedFields: false,
drawFieldType: 'text',
fieldTypes: 'text,signature,date',
customButtonTitle: 'Publish',
customButtonUrl: 'https://your-app.com/templates/published',
emailSubject: 'Please sign: {{template.name}}',
emailBody: 'Please review and sign: {{submitter.link}}',
backgroundColor: '#f9fafb',
customCss: 'body { font-family: "Inter", sans-serif; }',
inputMode: false,
withSignatureId: false,
extractFields: true,
roles: ['Sender', 'Recipient'],
submitters: [
{ name: 'Recipient', email: 'jane@example.com' }
],
requiredFields: ['Signature'],
fields: [
{ 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 }
]
});
SpitShake.on(event, callback)
Subscribe to an event. Returns theSpitShake SDK instance for method chaining.
Parameters:
| Property | Type | Required | Description |
|---|---|---|---|
event | string | Yes | Event name (see Events section) |
callback | function | Yes | Callback function receiving the event detail |
SpitShake (for chaining)
SpitShake
.on('loaded', function (detail) {
console.log('Form loaded for submitter:', detail.submitter);
})
.on('completed', function (detail) {
console.log('Signer finished:', detail.submitter);
})
.on('declined', function (detail) {
console.log('Signer declined:', detail.reason);
});
SpitShake.off(event, callback)
Unsubscribe from an event. Returns theSpitShake SDK instance for method chaining.
Parameters:
| Property | Type | Required | Description |
|---|---|---|---|
event | string | Yes | Event name |
callback | function | Yes | The same function reference passed to on() |
SpitShake (for chaining)
function onCompleted(detail) {
console.log('Signer finished:', detail.submitter);
}
// Subscribe
SpitShake.on('completed', onCompleted);
// Later, unsubscribe
SpitShake.off('completed', onCompleted);
Events
Form events
These events fire when a signing form is mounted viaSpitShake.mount() or SpitShake.form().
loaded
Fired when the form content has fully rendered and is interactive.SpitShake.on('loaded', function (detail) {
console.log('Signer:', detail.submitter);
});
{
"submitter": "aB3kL9mNpQ"
}
submitter is the signer’s slug.
completed
Fired when the signer successfully submits the form.SpitShake.on('completed', function (detail) {
console.log('Signer:', detail.submitter);
console.log('Redirect URL:', detail.redirect_url);
});
{
"submitter": "aB3kL9mNpQ",
"redirect_url": "https://your-app.com/signing-complete"
}
redirect_url is the completed_redirect_url resolved for this signer, or null. The
event carries no document, field or submission data; use the API or webhooks for those.
When redirect_url is an http(s) URL, the form element redirects your page to it after
the event. SpitShake.on('completed') cannot stop that. To handle the redirect yourself,
listen on the element that mount() returns and call preventDefault():
const form = SpitShake.mount({ element: '#signing-container', submitterSlug: 'aB3kL9mNpQ' });
form.addEventListener('completed', function (event) {
event.preventDefault();
showThankYou(event.detail.submitter);
});
declined
Fired when the signer declines to sign the document.SpitShake.on('declined', function (detail) {
console.log('Declined by:', detail.submitter);
console.log('Reason:', detail.reason);
});
{
"submitter": "aB3kL9mNpQ",
"reason": "Terms not acceptable"
}
field-value
Fired each time the signer fills in or changes a field value.SpitShake.on('field-value', function (detail) {
console.log('Field changed:', detail.field_uuid, '=', detail.value);
});
{
"field_uuid": "3f0c9b1e-8a2d-4c55-9e1a-2b7d6c4f8a10",
"value": "Jane Doe"
}
Builder events
These events fire when a template builder is mounted viaSpitShake.mountBuilder() or SpitShake.builder().
loaded
Fired when the builder UI has fully rendered.SpitShake.on('loaded', function (detail) {
console.log('Builder loaded for template:', detail.template_id);
console.log('Documents:', detail.documents.length);
console.log('Fields:', detail.fields.length);
});
{
"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"
}
],
"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": "Signature",
"type": "signature",
"required": true,
"submitter_uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"page": 4
}
]
}
template-saved
Fired when the template is saved.SpitShake.on('template-saved', function (detail) {
console.log('Template saved:', detail.template_id);
console.log('Updated at:', detail.updated_at);
console.log('Fields:', detail.fields.length);
});
{
"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"
}
],
"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": "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}]
}
]
}
template-data
Fired in response to agetTemplate() call or internal state changes.
SpitShake.on('template-data', function (detail) {
console.log('Template data received:', detail.template_id);
});
template-saved.
send
Fired when the user clicks the “Send” button inside the builder.SpitShake.on('send', function (detail) {
console.log('Send requested for template:', detail.template_id);
console.log('Submitter roles:', detail.submitters.map(function (s) { return s.name; }));
// Open your own send dialog
});
{
"template_id": 15,
"template_name": "Employment Agreement",
"submitters": [
{
"name": "Sender",
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
},
{
"name": "Recipient",
"uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
}
]
}
change
Fired when any change occurs in the builder — field added, moved, resized, deleted, or properties updated.SpitShake.on('change', function (detail) {
console.log('Builder changed:', detail.change_type);
console.log('Template:', detail.template_id);
console.log('Fields:', detail.fields.length);
});
{
"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"
}
],
"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": "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}]
}
]
}
Complete integration example
This example shows a full SPA integration that loads the SDK dynamically, mounts a signing form, handles all events, and provides a fallback builder flow.<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SpitShake Integration</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; padding: 24px; }
.embed-container { max-width: 960px; margin: 0 auto; min-height: 600px; border: 1px solid #e5e7eb; border-radius: 8px; }
#status { padding: 12px; margin-bottom: 16px; border-radius: 6px; font-size: 14px; }
.status-loading { background: #fef3c7; color: #92400e; }
.status-ready { background: #d1fae5; color: #065f46; }
.status-completed { background: #dbeafe; color: #1e40af; }
.status-declined { background: #fee2e2; color: #991b1b; }
.controls { margin-bottom: 16px; }
.controls button { padding: 8px 16px; margin-right: 8px; border: 1px solid #d1d5db; border-radius: 6px; background: white; cursor: pointer; }
.controls button:hover { background: #f9fafb; }
</style>
</head>
<body>
<div id="status" class="status-loading">Loading SpitShake SDK...</div>
<div class="controls">
<button id="btn-mount-form">Mount Signing Form</button>
<button id="btn-mount-builder">Mount Builder</button>
</div>
<div id="signing-container" class="embed-container"></div>
<div id="builder-container" class="embed-container" style="display: none;"></div>
<script>
var SPITSHAKE_HOST = 'https://your-app.com';
var SUBMITTER_SLUG = 'aB3kL9mNpQ';
var BUILDER_TOKEN = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxNSJ9.abc123';
function updateStatus(message, className) {
var el = document.getElementById('status');
el.textContent = message;
el.className = className;
}
// Load SDK dynamically
var script = document.createElement('script');
script.src = SPITSHAKE_HOST + '/js/spitshake-embed.js';
script.onload = function () {
SpitShake.configure({ host: SPITSHAKE_HOST });
updateStatus('SDK loaded. Click a button to mount.', 'status-ready');
// Register global event handlers with chaining
SpitShake
.on('loaded', function (detail) {
updateStatus('Form loaded for submitter ' + detail.submitter, 'status-ready');
})
.on('completed', function (detail) {
updateStatus('Signer ' + detail.submitter + ' completed', 'status-completed');
console.log('Redirect URL:', detail.redirect_url);
})
.on('declined', function (detail) {
updateStatus('Signer declined: ' + detail.reason, 'status-declined');
console.log('Declined:', detail);
})
.on('field-value', function (detail) {
console.log(
'Field "' + detail.field_name + '" (' + detail.field_type + ') = ' + detail.value +
' [' + detail.completed_fields + '/' + detail.total_fields + ']'
);
})
.on('template-saved', function (detail) {
updateStatus('Template ' + detail.template_id + ' saved at ' + detail.updated_at, 'status-ready');
console.log('Saved template:', detail);
})
.on('send', function (detail) {
console.log('Send clicked for template:', detail.template_id);
console.log('Roles:', detail.submitters.map(function (s) { return s.name; }));
});
};
document.head.appendChild(script);
// Mount signing form on button click
document.getElementById('btn-mount-form').addEventListener('click', function () {
// Clear previous content safely
var signingContainer = document.getElementById('signing-container');
while (signingContainer.firstChild) {
signingContainer.removeChild(signingContainer.firstChild);
}
signingContainer.style.display = 'block';
document.getElementById('builder-container').style.display = 'none';
SpitShake.mount({
element: '#signing-container',
submitterSlug: SUBMITTER_SLUG,
email: 'jane.doe@example.com',
name: 'Jane Doe',
role: 'Recipient',
externalId: 'usr_9f84b2a1',
logo: 'https://your-app.com/assets/logo.png',
language: 'en',
withTitle: true,
withDownloadButton: true,
withSendCopyButton: true,
withDecline: true,
withFieldNames: true,
withFieldPlaceholder: 'Enter value here',
withCompleteButton: true,
onlyRequiredFields: false,
allowToResubmit: false,
allowTypedSignature: true,
goToLast: true,
expand: true,
autoscroll: true,
minimizeFirstStep: true,
orderAsOnPage: false,
sendCopyEmail: true,
backgroundColor: '#ffffff',
values: {
'Full Name': 'Jane Doe',
'Email': 'jane.doe@example.com',
'Company': 'Acme Inc',
'Title': 'VP of Operations',
'Date': '2026-04-08'
},
metadata: {
customer_id: 'cust_8472',
deal_id: 'deal_291',
plan: 'enterprise',
source: 'sdk_integration'
},
i18n: {
submit: 'Confirm & Sign',
next: 'Continue'
}
});
updateStatus('Mounting signing form...', 'status-loading');
});
// Mount builder on button click
document.getElementById('btn-mount-builder').addEventListener('click', function () {
// Clear previous content safely
var builderContainer = document.getElementById('builder-container');
while (builderContainer.firstChild) {
builderContainer.removeChild(builderContainer.firstChild);
}
builderContainer.style.display = 'block';
document.getElementById('signing-container').style.display = 'none';
SpitShake.mountBuilder({
element: '#builder-container',
token: BUILDER_TOKEN,
language: 'en',
autosave: true,
preview: true,
withTitle: true,
withTitleInput: true,
withSendButton: true,
withRecipients: true,
withUploadButton: true,
withAddPageButton: false,
withSignYourselfButton: true,
withDocumentsList: true,
withFieldsList: true,
withFieldsDetection: true,
withSendMyselfEmail: false,
drawFieldType: 'text',
fieldTypes: 'text,signature,date,checkbox',
customButtonTitle: 'Publish Template',
emailSubject: 'Please sign: {{template.name}}',
emailBody: 'Hi, please review and sign: {{submitter.link}}',
backgroundColor: '#f9fafb',
roles: ['Sender', 'Recipient'],
submitters: [
{ name: 'Recipient', email: 'jane@example.com' }
],
requiredFields: ['Signature', 'Sender Signature'],
fields: [
{ name: 'Full Name', type: 'text', role: 'Recipient', required: true },
{ name: 'Email', 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 }
]
});
updateStatus('Mounting template builder...', 'status-loading');
});
</script>
</body>
</html>
Chaining pattern
Theon() and off() methods return the SDK instance, enabling a fluent chaining pattern:
SpitShake
.configure({ host: 'https://your-app.com' })
SpitShake
.on('loaded', function (detail) {
console.log('Ready:', detail.submitter);
})
.on('completed', function (detail) {
fetch('/api/internal/signing-complete', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ submitter_slug: detail.submitter })
});
})
.on('declined', function (detail) {
fetch('/api/internal/signing-declined', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ submitter_slug: detail.submitter, reason: detail.reason })
});
})
.on('field-value', function (detail) {
console.log(detail.field_uuid, '=', detail.value);
})
.on('change', function (detail) {
console.log('Builder changed:', detail.change_type, detail.template_id);
});
When using both form and builder events with
SpitShake.on(), the loaded event fires for both. Differentiate by checking for detail.submitter (form only).
