Last week, my colleague Hector Zelaya authored a post called, Live eSign Saves a Trip to the Bank. He spoke about how the power trio of secure WebRTC video conferencing, co-browsing, and PDF editing could make visiting a financial institution or similar office to sign documents or provide visual proof of identity in front of an attorney, bank officer, lawyer, or notary a thing of the past.
Today, I’ll provide the technical details on exactly how to enable Live eSign in your WebRTC application.
It is assumed that you already have a secure video conferencing application. (Need to build one? We can help!)
The code examples here are written in TypeScript and run on NodeJS and Next.js. If your video conferencing application uses a different stack, you can still apply the concepts but you will need to adapt the code.
You will need a Docker and Docker Compose for running the co-browsing service locally.
A PubNub account is used to handle the events related with editing and sharing the PDF file.
The first step is to let the employee from the institution (we call them the “power user”) add a PDF document to the application. To do so, let’s create a new React component to include in the video call page of your application.
In this new component we will perform three tasks:
Let’s start by adding the new ESignContainer
component in your video call component, along with a useState hook for storing the URL of the PDF file. Such an URL is passed as a prop to the new component. Depending on the logic of your application you might need to pass additional props to it.
Now we need a way to let all participants know when there is a file available. For this, we will subscribe the participants to a PubNub channel. We need to set a unique name for the channel, perhaps the identifier of the video call session or room name. Make sure to adapt this to your application.
We then use the useEffect
hook to initialize the PubNub client and start listening for new messages. For now, we just want to set the file URL in the state. In this post, we use the pubnub-react library to initialize the client through a convenient hook.
Now, let’s create this ESignContainer
component. Here we want to manage the files that are shared and the state of such shares. This includes React’s useState
hooks for such files and a set of multiple flags that indicates their state.
It also includes handler functions for when power users drag and drop files or when they click the “Add” button. In addition, we use PubNub’s sendFile
feature to set up temporary storage for the PDF file and also to share its URL.
We also create a new component, ESignView
, which allows power users to add the PDF file and render it when it’s available. We will see this component in depth later.
Now let’s take a look at the ESignView
component. Here we want to show a form where the power user can add a PDF file. After that, we want to enable the power user to prepare the file before sharing it with the client.
To do so, we render a simple upload form with support for dragging and dropping files. This is done by setting the handleDrop
function we defined before in its onDrop
attribute. The form includes a button that initiates the upload through the, previously defined, handleUpload
function that is passed to its onClick
attribute.
The PDF editing capabilities will come from the PSPDFKit library, which we’ll explore in the next section. For now, we simply add an HTML div tag where the PDF editor will live.
Once the file is available in PubNub, we download and render it so the power user can edit it before sharing it with the client. We will use the PSPDFKit library. As per the library documentation, let’s start by installing the library and copying the web assets to public
folder of the project, as follows:
Next, we need to actually render a file. The code that we wrote so far allows a power user to upload the file to PubNub. When this happens, PubNub will let all participants know that there is a file available, they, in turn, store its URL in the fileUrl
variable from the ESignContainer
component. Let’s use that fileUrl
variable to know when the file is ready to edit and actually render it using PSPDFKit.
First, let’s use a useState
hook to store an instance of the PDF editor. We will use this instance to export the final PDF file. We also need to initialize the PSPDFKit client and also use the useRef hook to get the reference of the HTML div tag where the editor renders.
The PDF magic happens inside a useEffect
hook that reacts to fileUrl
value changes. The first thing we do here is download the file, using the axios library, and add it to the editor. For this, we add a custom convertPdfToBase64
function that takes the fileUrl
and converts it into something usable by the editor.
Your application should now have the ability to upload a PDF file, store it in PubNub, and allow the power user to edit it. Now, let’s add a way to share the file with the rest of the participants.
For this, we include a new flag in the ESignContainer: shareAndStart
. This flag indicates that the file is ready and the participants can start with eSigning. We also have a new useState
hook, finalPDFBuffer
, that stores the final PDF before it’s added to PubNub.
The new flag is enabled by clicking a new “Share Document and Start eSign” button that is available while editing the file and after clicking the upload button. The value of such flag is passed to the ESignView
component, we will look at this later.
We also listen for finalPDFBuffer
value changes, and when the file is ready we upload it to PubNub, again using sendFile
feature. After that, we’re ready for co-browsing. More on that in the next section.
Besides the new flag and hook, we also want to send a message to the PubNub channel that notifies all participants that they can join the co-browsing session once it’s ready. For now, we will define a sendShareAndStart
function that will get called when clicking the button mentioned above.
Now, let’s take a look at the ESignView
component. Here, we listen for changes in the shareAndStart
variable that we receive as prop, and when an instance of the PDF file is ready, we assign it to the finalPDFBuffer
state we just created. This logic lives in a separate function and we use the useCallback
hook to make it optimal across component renders. Another thing we do is render the PDF file only if the shareAndStart
flag is false
, which is the case for when editing the file.
Now we’re ready for co-browsing! But before that, let’s create a component for the page we will co-browse to. We will call this component ESignPageContainer.
In this new component, we use PSPDFKit to render the more recent PDF file that has been uploaded to the PubNub channel.
We also need the unique identifier for the channel, which we will call esignId
. In our example we have set this to the room name, make sure you adapt this to the logic of your application.
Co-browsing is enabled using n.eko. n.eko defines itself as, “a self hosted virtual browser that runs in Docker.” This tool allows you to run a virtual browser in a remote server that you control via WebRTC. It’s an ideal solution for developers to test web applications, privacy-conscious users that seek for a secure browsing experience, or anything that can take advantage of a virtual server running in an isolated environment.
For our particular use case, the most interesting feature is that n.eko allows multiple users to access the browser simultaneously. Hence, it provides that “shared” context where Live eSign takes place.
The first step is to have n.eko running. This can be done easily using Docker and Docker Compose. The official documentation provides an example of a docker-compose.yml file that uses Google Chrome. Add this file to your project.
Then you can run n.eko using the command docker-compose up. As a result you will have a web client available at http://localhost:8080 that you can use to interact with the remote browser via WebRTC.
The easiest way to add this functionality to your video conferencing application is via an HTML iframe tag that shows n.eko’s web client. You can even build your own client so it behaves the way you want and add additional features, such as a more advanced authentication mechanism or supporting extra parameters. For this post we will use the one that comes by default.
Before looking into this, let’s take it from where we left it in the previous section. As you may recall, after the power user clicks the “Share Document and Start eSign” button, the application notifies clients that it’s ready to start eSign, and also updates the shareAndStart
flag, which in turn triggers a function that sets the finalPDFBuffer
. Once the finalPDFBuffer
is ready, it’s uploaded to PubNub using sendFile.
As a result, there are two messages that we need to listen for: one is the StartEsign
message that lets clients know that eSign has started, and also the FinalFile
message that is sent when uploading the edited file to PubNub. We use these to allow clients and power users to set up the iframe.
Let’s start by adding the URL of the n.eko web client, http://localhost:8080, in our video container and send it to the ESignContainer
component as a prop. Next, we need to get back to the PubNub listeners to make sure that we initialize the iframe when we receive the notifications.
As mentioned before, the clients need to listen for the StartEsign
message, while power users need to listen for FinalFile
, so let’s add the code for setting up the iframe there.
To set up the iframe, we need the URL of the n.eko web client and also pass some query parameters that allow users to go straight to browsing. These parameters are a display name and a password.
Display user name can be whatever you want, it’s used to identify users within the co-browsing session. You can use the name your application gives to your users. Passwords, on the other hand, are defined at n.eko level. By default, admin
is the password that grants elevated privileges to users and neko is for regular ones.
Now, in ESignContainer
, we just need to add the HTML iframe element when setAndShareStart
value is true
and set its src
attribute to the prop we just created.
After that it’s just a matter of manually navigating to the ESignPageContainer page we created before. You can also build a custom web client for n.eko that supports specifying a target page as query params. If you’re interested in the latter you can check out the code of a neko-client that you can work upon.
With co-browsing and PDF editing enabled in a WebRTC application, all parties can remotely sign a legal document, close a loan, perform an eMortgage, and other activities that normally require in-person witnessing, notary, or visual proof of identity.
If you’re interested in adding co-browsing and PDF editing capabilities to your WebRTC application, our team has plenty of experience! Contact us to learn how our services can adapt to your business needs. Let’s make it live!
Related post: Live eSign Saves a Trip to the Bank