Embed Signing Widget
Drop a signing experience into your app with a single JavaScript call. Works with any framework or plain HTML.
How It Works
Create envelope via API
Use POST /api/v1/envelopes to upload a PDF and add recipients.
Get embed URL
Call POST /api/v1/envelopes/{id}/embed-url to get a time-limited signing URL.
Open in your app
Use SignForge.open() to launch the signing UI as an inline iframe or modal overlay.
Get Embed URL
After creating an envelope and sending it, request an embed URL for a specific recipient:
curl -X POST https://signforge.io/api/v1/envelopes/{envelope_id}/embed-url \
-H "X-API-Key: sf_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"recipient_index": 0}'Response
{
"embed_url": "https://signforge.io/embed/sign/eyJhbGciOiJIUz...",
"token_expires_at": "2026-04-24T12:00:00Z"
}The embed URL contains a time-limited signing token. Generate a fresh URL each time a user needs to sign.
Install the JavaScript SDK
Add a single script tag to your page. No npm package or build step required.
<script src="https://signforge.io/signforge-embed.js"></script>The SDK exposes a global SignForge object.
Modal Mode (Default)
Opens a fullscreen overlay with the signing UI. Best for quick signing flows where you don't need the signer to stay on your page.
SignForge.open({
url: "https://signforge.io/embed/sign/{token}",
onReady: (data) => {
console.log("Signing UI loaded for:", data.envelope_id);
},
onSigned: (data) => {
console.log("Document signed at:", data.signed_at);
SignForge.close();
// Redirect or show success message
},
onError: (data) => {
console.error("Signing error:", data.message);
},
onExpired: () => {
alert("This signing link has expired.");
},
});Container Mode (Inline)
Embed the signing UI inline within a specific element. Great for multi-step wizards or custom layouts.
<div id="sign-here" style="width: 100%; height: 700px;"></div>
<script>
SignForge.open({
url: "https://signforge.io/embed/sign/{token}",
container: "#sign-here",
onSigned: (data) => {
document.getElementById("sign-here").innerHTML =
"<p>Signed successfully!</p>";
},
});
</script>The iframe will fill the container element. Set an explicit height for best results.
postMessage Events
The embed iframe communicates with the parent window via postMessage. If you prefer to listen directly instead of using the SDK:
| Event Type | Data | When |
|---|---|---|
| signforge:ready | { envelope_id } | Signing UI is loaded and interactive |
| signforge:signed | { envelope_id, signed_at } | Signer completed all fields and submitted |
| signforge:error | { message } | An error occurred (network, validation) |
| signforge:expired | {} | Signing token has expired |
Direct listener example
window.addEventListener("message", (event) => {
// Always verify origin
if (!event.origin.includes("signforge.io")) return;
const { type, ...data } = event.data;
switch (type) {
case "signforge:signed":
console.log("Signed!", data.envelope_id);
break;
case "signforge:error":
console.error("Error:", data.message);
break;
}
});SDK Reference
SignForge.open(options)
Opens the signing UI. Returns void.
| Option | Type | Description |
|---|---|---|
| url | string | Required. The embed URL from the API. |
| container | string | null | CSS selector for inline mode. Null or omit for modal. |
| onReady | function | Called when the signing UI is loaded. |
| onSigned | function | Called when signing is completed. |
| onError | function | Called on errors. |
| onExpired | function | Called when the signing link expires. |
SignForge.close()
Closes the signing UI (removes iframe and overlay). Safe to call at any time.
Framework Examples
React / Next.js
import { useEffect } from "react";
import Script from "next/script";
export default function SignPage({ embedUrl }: { embedUrl: string }) {
return (
<>
<Script
src="https://signforge.io/signforge-embed.js"
onLoad={() => {
(window as any).SignForge.open({
url: embedUrl,
container: "#sign-container",
onSigned: () => {
alert("Document signed!");
},
});
}}
/>
<div id="sign-container" style={{ height: 700 }} />
</>
);
}Plain HTML
<!DOCTYPE html>
<html>
<head>
<title>Sign Document</title>
<script src="https://signforge.io/signforge-embed.js"></script>
</head>
<body>
<h1>Please sign below</h1>
<div id="sign-here" style="width:100%;height:700px;border:1px solid #ccc;border-radius:8px;"></div>
<script>
SignForge.open({
url: "EMBED_URL_FROM_API",
container: "#sign-here",
onSigned: function(data) {
document.getElementById("sign-here").innerHTML =
"<h2>Thank you!</h2><p>Document signed successfully.</p>";
}
});
</script>
</body>
</html>Content Security Policy
If your site uses a Content Security Policy, add SignForge to your allowed sources:
frame-src https://signforge.io https://staging.signforge.io;
script-src https://signforge.io;The embed iframe loads from /embed/sign/* paths. No cookies or third-party scripts are loaded inside the iframe.
Branding
Shows “Powered by SignForge” text at the bottom of the embed.
Branding removed. Clean white-label signing experience.
API Reference
Full REST API documentation with endpoint reference.
MCP Server
Use SignForge from Claude Desktop and AI agents.
Code Examples
Integration samples for n8n, Retool, cURL, and more.