How to Handle Post-Completion Actions in Embedded Signing
Implement custom post-completion workflows using JavaScript events when redirect URLs don't work
How to Handle Post-Completion Actions in Embedded Signing
Problem
You need to perform custom actions after a user completes signing a document in an embedded session. Unlike shared links, embedded signing sessions don't support automatic redirects via the redirect
parameter. Instead, you must handle post-completion actions using JavaScript events.
Prerequisites
- Existing embedded signing implementation with iframe
- Basic JavaScript knowledge
- Understanding of PandaDoc embedded signing events
Solution
Step 1: Set Up Event Listener
Add a JavaScript event listener to capture signing completion events from the embedded iframe:
window.addEventListener("message", (event) => {
// Verify the event comes from PandaDoc
if (event.origin !== "https://app.pandadoc.com") {
return;
}
const type = event.data && event.data.type;
const payload = event.data && event.data.payload;
switch (type) {
case "session_view.document.loaded":
handleDocumentLoaded(payload);
break;
case "session_view.document.completed":
handleDocumentCompleted(payload);
break;
case "session_view.document.exception":
handleDocumentException(payload);
break;
}
});
Step 2: Implement Completion Handler
Create a function to handle the document completion event and perform your custom actions:
- Example: Close the iframe and show success message
- Example: Redirect to a custom page
- Example: Update your application's state
- Example: Send completion data to your backend
Step 3: Handle Other Events
Implement handlers for loading and error events:
- Example: Hide loading spinner
- Example: Show signing instructions
- Example: Make iframe visible
- Example: Show error message
- Example: Log error for debugging
Step 4: Complete HTML Implementation
Here's a complete example integrating the iframe with event handling:
<!DOCTYPE html>
<html>
<head>
<title>Document Signing</title>
<style>
#pandadoc-iframe {
width: 100%;
height: 600px;
border: none;
}
#loading-spinner,
#success-message,
#error-message {
display: none;
padding: 20px;
text-align: center;
}
#success-message {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
#error-message {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
</style>
</head>
<body>
<div id="loading-spinner">
<p>Loading document...</p>
</div>
<div id="signing-instructions" style="display: none">
<p>Please review and sign the document below:</p>
</div>
<iframe
id="pandadoc-iframe"
src="https://app.pandadoc.com/s/qU89rB4r33FdM5NQTcAWKj/"
></iframe>
<div id="success-message">
<h3>Document Signed Successfully!</h3>
<p>
Thank you for completing the document. You will be redirected shortly.
</p>
</div>
<div id="error-message"></div>
<script>
showLoadingSpinner();
// Event listener implementation from steps above
window.addEventListener("message", (event) => {
if (event.origin !== "https://app.pandadoc.com") {
return;
}
const type = event.data && event.data.type;
const payload = event.data && event.data.payload;
switch (type) {
case "session_view.document.loaded":
handleDocumentLoaded(payload);
break;
case "session_view.document.completed":
handleDocumentCompleted(payload);
break;
case "session_view.document.exception":
handleDocumentException(payload);
break;
}
});
function handleDocumentLoaded(payload) {
console.log("Document loaded successfully");
// Example: Hide loading spinner
document.getElementById("loading-spinner").style.display = "none";
// Example: Show signing instructions
document.getElementById("signing-instructions").style.display = "block";
}
function handleDocumentException(payload) {
console.error("Document exception:", payload);
// Example: Show error message
showErrorMessage("An error occurred during signing. Please try again.");
// Example: Log error for debugging
logError("Embedded signing error", payload);
}
function showErrorMessage(message) {
const errorDiv = document.getElementById("error-message");
errorDiv.textContent = message;
errorDiv.style.display = "block";
}
function logError(message, payload) {
// Send error information to your logging system
console.error(message, payload);
}
function showLoadingSpinner() {
document.getElementById("loading-spinner").style.display = "block";
}
function handleDocumentCompleted(payload) {
console.log("Document completed:", payload);
// Example: Close the iframe and show success message
closeSigningIframe();
showSuccessMessage();
// Example: Redirect to a custom page
redirectToThankYouPage();
// Example: Update your application's state
updateDocumentStatus("completed");
// Example: Send completion data to your backend
notifyBackend(payload);
}
function closeSigningIframe() {
const iframe = document.getElementById("pandadoc-iframe");
if (iframe) {
iframe.remove();
}
}
function redirectToThankYouPage() {
// Custom redirect logic
// window.location.href = "/thank-you?document=completed";
}
function showSuccessMessage() {
// Show custom success UI
document.getElementById("success-message").style.display = "block";
}
function updateDocumentStatus(status) {
// Update your application's document tracking
// This could involve API calls to your backend
}
function notifyBackend(payload) {
// Send completion event to your backend for processing
}
</script>
</body>
</html>
Verification
To confirm your event handling is working correctly:
- Test the completion flow: Complete a test document and verify your custom actions execute
- Check console logs: Monitor browser console for event data and any errors
- Verify backend calls: Confirm that any API calls to your backend are successful
- Test error scenarios: Simulate errors to ensure error handling works properly
Troubleshooting
Issue: Events not firing
- Verify the iframe src URL is correct and accessible
- Check that event listener is set up before the iframe loads
- Ensure you're listening for the correct event origin (
https://app.pandadoc.com
)
Issue: Custom actions not executing
- Check browser console for JavaScript errors
- Verify event handler functions are defined
- Ensure payload data structure matches your expectations
Related
- Understanding Shared Links vs Embedded Signing Sessions - Conceptual differences
- Embedded Signing Documentation - Full implementation details
- How to Set Up Post-Completion Redirect URLs - For shared link redirects
Updated 2 days ago