@aoexl/sign
v1.2.23
Published
Embeddable PDF eSignature SDK by Aoexl
Maintainers
Readme
@aoexl/sign
Embed Aoexl's PDF signing experience directly inside your product.
Install
npm install @aoexl/signProduction model
Use pk_test_demo for local evaluation and move to your own pk_live_* key for
production. Production embeds are expected to use the managed Aoexl engine after
license validation.
Recommended production auth order:
- easiest:
licenseEndpoint="/api/aoexl-token"so the browser talks only to your backend - advanced SPA:
getEngineToken={async () => ...}for custom fetch logic - SSR / one-off page:
engineToken="..."for a pre-minted short-lived token - legacy compatibility:
licenseKey="pk_live_..."directly in the browser
base and engineUrl can be used for localhost development or for same-origin
app-hosted engine assets in production. Arbitrary cross-origin engine URLs stay
blocked by the SDK.
React
import { AoexlViewer } from "@aoexl/sign";
export default function EmbeddedSigner() {
return (
<AoexlViewer
licenseEndpoint="/api/aoexl-token"
pdfUrl="/Merchant.pdf"
mode="embedded-signing"
signerInfo={{ name: "Taylor Merchant", email: "[email protected]" }}
completionRedirectUrl="/done?session={{sessionId}}&completedAt={{completedAt}}"
onComplete={(result) => console.log(result)}
onError={(error) => console.error(error)}
/>
);
}Vanilla JS
import AoexlSign from "@aoexl/sign";
const viewer = await AoexlSign.init({
licenseEndpoint: "/api/aoexl-token",
container: "#signer",
pdfUrl: "/Merchant.pdf",
mode: "embedded-signing",
});
// later
viewer.destroy();Props
All configuration for AoexlSign.init() or <AoexlViewer /> is passed via the config object:
| Prop | Type | Description |
| :--- | :--- | :--- |
| licenseKey | string | Legacy browser-validation path (pk_test_* or pk_live_*). |
| engineToken | string | Pre-minted short-lived engine token from your backend. |
| getEngineToken | Function | Async function that returns a short-lived engine token. |
| licenseEndpoint | string | Easiest production path. SDK POSTs { domain, timestamp } to your backend route and expects { engineToken, refreshAfterSeconds? }. |
| pdfUrl | string | URL of the PDF to load. |
| pdfData | Uint8Array \| Blob \| string | Raw bytes or data-URL (alternative to pdfUrl). |
| mode | AoexlMode | 'prepare', 'sign', or 'view'. |
| theme | Theme | Customise colors (primaryColor) and container layout. |
| signers | Signer[] | Define signer roles and identities. |
| fields | Field[] | Restore a previously saved field layout. |
| completionRedirectUrl | string | Optional redirect after completion. Supports {{sessionId}}, {{fileName}}, {{completedAt}}, {{signerName}}, {{signerEmail}}. |
| base | string | Asset base for localhost development or same-origin app-hosted engine assets. |
| ui | UIConfig | Hide specific buttons or sidebars using hide: []. |
| config | Config | Behavior flags such as first-load zoom, field order, auto-flattening, and flattened banner customization. |
| onComplete | Function | Fired when signing is finished and document is ready. |
At least one auth prop is required: licenseKey, engineToken, getEngineToken, or licenseEndpoint.
For the full prop contract, responsive behavior notes, and embed recipes, see PROPS.md.
First-load zoom and flattened banner
Use config.initialViewMode when an embedded PDF should open responsively instead of at a fixed zoom percentage.
<AoexlViewer
licenseEndpoint="/api/aoexl-token"
pdfUrl="/Merchant.pdf"
mode="sign"
initialScale={1}
config={{
initialViewMode: "fit-width",
flattenedBanner: {
text: "This document is locked for review.",
backgroundColor: "#0f172a",
textColor: "#ffffff",
actionLabel: "Edit again",
showUnlock: true
}
}}
/>initialViewMode supports 'scale', 'fit-width', and 'fit-page'. Set flattenedBanner: false to hide the flattened-document banner entirely.
Responsive signing behavior
The SDK supports two common embedded experiences:
mode="view"for read-only disclosures or consent PDFsmode="sign"/mode="signing"for signer-facing flows
For signing embeds, prefer:
<AoexlViewer
mode="sign"
ui={{ hide: ["toolbar"] }}
config={{
initialViewMode: "fit-width",
enableSignatureIndicator: true,
}}
/>That combination is the supported way to:
- hide the header row
- show the signing progress widget instead of the centered header tabs
- keep the bottom signing-progress footer on widths below
960px
For read-only embeds, keep mode="view" and use config.initialViewMode: "fit-width" so the PDF fills the container on first load.
Backend token route example
The secure-but-easy production model is:
- frontend uses
licenseEndpoint="/api/aoexl-token" - your backend stores the long-lived
pk_live_*key - your backend calls Aoexl server-to-server
- your backend returns only the short-lived engine token
Example backend route:
app.post('/api/aoexl-token', async (req, res) => {
const upstream = await fetch('https://aoexl.com/api/v1/license_verification', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
licenseKey: process.env.AOEXL_LICENSE_KEY,
domain: req.body.domain,
timestamp: req.body.timestamp,
}),
})
const data = await upstream.json()
if (!upstream.ok || !data?.engineToken) {
return res.status(400).json({ error: data?.error || 'Failed to mint engine token' })
}
res.json({
engineToken: data.engineToken,
refreshAfterSeconds: data.refreshAfterSeconds,
})
})Loading and rendering guarantees
The SDK validates the license first and only then fetches the managed Aoexl engine for production use.
To avoid scroll stutter in short onboarding packets and consent forms, PDFs with 5 pages or fewer render every page up front at high canvas quality. Larger PDFs render on demand while showing an in-view preparing state instead of leaving a blank page.
When a user uploads or opens a different PDF inside the viewer, previously supplied fields are cleared for that new document. If you want fields on the replacement PDF, pass the saved field layout for that PDF when you initialize or reinitialize the viewer.
API
The init() method returns a viewer instance with the following methods:
destroy(): Unmount and cleanup.savePdf(options): Triggers a download/save of the current PDF state.getPdfBytes(options): Returns the signed PDF as aUint8Array.flattenPdf(): Merges all annotations and signatures into the base PDF.setScale(value): Sets the zoom level (e.g.1.5for 150%).fitWidth()/fitPage(): Auto-scale to fill the viewport.
How It Works
- The npm package is the public shell package (~400KB).
- The heavier managed engine (~4MB) is fetched dynamically after license validation.
- Live keys are enforced server-side and authorized origins are validated.
