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:

  1. Test the completion flow: Complete a test document and verify your custom actions execute
  2. Check console logs: Monitor browser console for event data and any errors
  3. Verify backend calls: Confirm that any API calls to your backend are successful
  4. 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