Embed SDKs

Embed a signing session in your page

Mount a recipient signing URL with @zsign/embed@0.1.1 (vanilla JS) or @zsign/react@0.1.1 (React 18). The framed page is still zSign's signing UI. These packages mount the iframe and listen for origin-guarded postMessage events.

Install
npm install @zsign/embed@0.1.1
npm install @zsign/react@0.1.1

Requires Node.js 18 or newer. @zsign/react also requires React 18+. @zsign/embed is installed automatically with the React package.

Allow the parent origin first

Embedding is default-deny

An empty embed_origins list blocks all framing. Register the exact origin of the page that will host the iframe before you load a signing URL inside it. A disallowed parent sees the signing page's blocked-frame screen, not the document.

PUT /api/branding/embed-origins
curl -X PUT "$ZSIGN_BASE_URL/api/branding/embed-origins" \
-H "Authorization: Bearer $ZSIGN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"origins": ["https://app.yourcompany.com"]}'

Origin rules

  • Dashboard: Settings → Embedding.
  • ZSIGN_BASE_URL defaults to the public zSign API host.
  • Exact match only. https is required except http://localhost[:port].
  • No paths or wildcards. At most 10 origins. Hosts are stored lowercased.

See Set Embed Origins in the API reference.

Vanilla JS

createSigningEmbed

Pass a recipient signing URL from POST /api/v1/documents/send (signing_urls) or the dashboard. To keep zSign from emailing that link when you deliver it yourself, send with send_invite: false.

@zsign/embed@0.1.1
import { createSigningEmbed } from "@zsign/embed";
const handle = createSigningEmbed({
signingUrl,
container: document.getElementById("signing"),
height: "auto",
onReady: () => {},
onSigned: ({ session_id }) => {},
onError: ({ message }) => {},
});
handle.destroy();

React

ZSignEmbed

ZSignEmbed accepts every createSigningEmbed option except container (the component owns the mount node), plus className and style for that wrapper div. Changing signingUrl or layout tears down the previous iframe. Callback identity changes do not.

layout is "auto", "compact", or "full" and sets ?signing_layout= on the signing URL. Framed pages default to compact (denser toolbar, no page navigation on one-page PDFs); standalone tabs default to full. Layout is visual only and never bypasses the origin guard.

Since 0.1.1 the iframe is granted fullscreen, so the signing page's own fullscreen toggle works inside your layout. The toggle only renders when document.fullscreenEnabled is true — integrators on an older SDK and iPhone Safari simply don't see it. Framed pages also show an open in new tab control; once a signer leaves the embed, onSigned no longer reaches the parent, so rely on the webhook or a status check if your flow needs the completion signal.

@zsign/react@0.1.1
import { ZSignEmbed } from "@zsign/react";
<ZSignEmbed
signingUrl={signingUrl}
height="auto"
onReady={() => {}}
onSigned={({ session_id }) => {}}
onError={({ message }) => {}}
/>

Live protocol

Events the signing page posts

The signing page posts { v: 1, type: "zsign:<event>", payload } to the allowed parent. The SDK ignores messages from any other origin or window. Do not invent other event names. onDeclined is an SDK option only; the live signing page does not emit zsign:declined.

typeSDK callbackPayloadWhen
zsign:readyonReady—session loaded and this parent is allowed
zsign:signedonSigned{ session_id? }signer completed the document
zsign:erroronError{ message? }completion failed
zsign:resizeiframe height{ height }document body resized (height: "auto" or omitted)