Technical FAQs

Question

Can I host multiple PrizmDoc viewers on a single page?

Answer

It is possible to host multiple viewers on a single page. The following example leverages Bootstrap’s tab implementation:

<!DOCTYPE html>

<html lang="en">
<head>
    <!-- Metadata -->
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
    <meta name="description" content="" />

    <!-- Title -->
    <title>AccuSample</title>

    <!-- Libraries -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css">

    <!-- PrizmCSS -->
    <link rel="stylesheet" href="https://pcc-demos.accusoft.com/static/viewer-latest/css/viewercontrol.css">
    <link rel="stylesheet" href="https://pcc-demos.accusoft.com/static/viewer-latest/css/viewer.css">

    <!-- Inline Stylesheet -->
    <style>
        body {
            overflow-y: hidden;
        }
        #viewer1, #viewer2 {
            height: calc(100vh - 3em);
            width: 100%;
        }
    </style>

</head>
<body>
    <!-- #main -->
    <main class="container">
        <ul class="nav nav-tabs" role="tablist">
            <li class="nav-item">
                <a class="nav-link active" id="viewer1-tab" data-toggle="tab" href="#viewer1">Viewer 1</a>
            </li>
            <li class="nav-item">
                <a class="nav-link" id="viewer2-tab" data-toggle="tab" href="#viewer2">Viewer 2</a>
            </li>
        </ul>

        <div class="tab-content">
            <div class="tab-pane fade show active" id="viewer1" role="tabpanel">
                <div id="viewer1">
                </div>
            </div>
            <div class="tab-pane fade" id="viewer2" role="tabpanel">
                <div id="viewer2">
                </div>
            </div>
        </div>
    </main>

    <!-- Libraries -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.1/umd/popper.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/js/bootstrap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

    <!-- PrizmJS -->
    <script src="https://api.accusoft.com/v1/docstore/viewer/assets/classic/bundle.js"></script>
    <script src="https://pcc-demos.accusoft.com/static/viewer-latest/js/jquery.hotkeys.min.js"></script>
    <script src="https://pcc-demos.accusoft.com/static/viewer-latest/js/viewercontrol.js"></script>
    <script src="https://pcc-demos.accusoft.com/static/viewer-latest/js/viewer.js"></script>

    <!-- Inline Script -->
    <script>
        var viewingSessionId1;
        var viewerControl1;
        var viewingSessionId2;
        var viewerControl2;

        $(document).ready(function() {
            $.ajax({
                "type": "post",
                "url": "https://api.accusoft.com/PAS/V1/ViewingSession",
                "headers": {
                    "acs-api-key": ""
                },
                "data": JSON.stringify({
                    "source": {
                        "type": "url",
                        "url": ""
                    }
                })
            }).done(function(response) {
                viewingSessionId1 = response["viewingSessionId"];

                // Initialize viewer
                viewerControl1 = $("#viewer1").pccViewer({ 
                    documentID: viewingSessionId1,
                    imageHandlerUrl: "https://api.accusoft.com/v2/viewers/proxy",
                    language: languageItems,
                    template: htmlTemplates
                }).viewerControl;
            });

            $.ajax({
                "type": "post",
                "url": "https://api.accusoft.com/PAS/V1/ViewingSession",
                "headers": {
                    "acs-api-key": ""
                },
                "data": JSON.stringify({
                    "source": {
                        "type": "url",
                        "url": ""
                    }
                })
            }).done(function(response) {
                viewingSessionId2 = response["viewingSessionId"];

                // Initialize viewer
                viewerControl2 = $("#viewer2").pccViewer({ 
                    documentID: viewingSessionId2,
                    imageHandlerUrl: "https://api.accusoft.com/v2/viewers/proxy",
                    language: languageItems,
                    template: htmlTemplates
                }).viewerControl;
            });
        });
    </script>
</body>
</html>

developer sitting at computer

Offering product integrations can be one of the easiest ways to expand the feature set of a product without adding loads of time and cost on development resources. Docubee currently has external integrations with Salesforce, Sharepoint, and Brother scanners that we offer to our customers. Internally, we have an integration with Slack that allows our development team to be notified of different events that happen within Docubee. As a team of engineers, we are always looking for new ways that we could possibly use Docubee with other products, and luckily, we usually find some time to prototype out these integrations.

Being an Apple enthusiast myself, one of the first things I wanted to try to integrate Docubee with was Apple HomeKit so I could use Siri to launch workflows. I configured my Apple TV to work with the Home app and was all ready to go. Unfortunately, I quickly found out that HomeKit does not natively support customizations like this. Lucky for me, someone had already come up with a solution to this problem using Homebridge and a node module called homebridge-cmdswitch2.

According to their Github, Homebridge is “a lightweight NodeJS server you can run on your home network that emulates the iOS HomeKit API” and homebridge-cmdswitch2 “allows you to run Command Line Interface (CLI) commands via HomeKit”. After that, the setup was pretty simple to get everything working. I had to create a workflow in Docubee that I wanted to start, configure my Home app to work with Homebridge, and write this config file below. Before I knew it, Siri was launching workflows for me.

{
  "bridge": {
      "name": "Homebridge",
      "username": "CC:22:3D:E3:CE:30",
      "pin": "031-45-154"
  },
  
  "description": "Homebridge Docubee Config",

  "accessories": [],

  "platforms": [{
    "platform": "cmdSwitch2",
    "name": "CMD Switch",
    "switches": [{
      "name" : "Docubee Workflow",
      "on_cmd": "curl -d '{\"wfModelId\":\"ec6e7fc4-1c38-4ebf-8a32-a02ba6721ffe\", \"wfData\": {}}' -H \"Content-Type: application/json\" -X POST {LAUNCH_WORKFLOW_ENDPOINT}",
      "state_cmd": "exit 1",
      "off_cmd": "echo off"
    }]
 }]
}

One of the next integrations I wanted to try to play with was Slack. I mentioned that we already use it internally, but I wanted to see if there was a way that we could make a Slack integration that was useful for an end-user. After creating my own Slack app to play with, I wanted to be able to launch a workflow from Slack as well as send a message back to Slack notifying me that a workflow was launched. To do both of these things, I had to create a handler somewhere to take the callback IDs that Slack would send to our API and do something with them. The finished handler looked like this:

'use strict';
const qs = require('qs');
const request = require('request')

function handleInteractiveMessage(req, res) {
  const task = req.task;
  res.status(200);
  res.end();
  task.log.info({ source: 'slack-connector.handInteractiveMessage' }, qs.parse(req.body));
  const payload = JSON.parse(qs.parse(req.body).payload);
  const responseUrl = payload.response_url;
  const callbackId = payload.callback_id;
  task.log.info({ source: 'slack-connector.handleInteractiveMessage', responseUrl }, 'response url');
  task.log.info({ source: 'slack-connector.handleInteractiveMessage', callbackId }, 'callback id');
  if (payload.callback_id === 'docubee_workflow_start') {
    kickOffWorkflow(task);
  } else if (payload.callback_id === 'handle_workflow_actions' && payload.actions[0].value !== 'redirect') {
    confirmCancelWorkflow(task, responseUrl, payload.actions[0].value);
  } else if (payload.callback_id === 'confirm_cancel_workflow' && payload.actions[0].value !== 'No') {
    cancelWorkflow(task, payload.actions[0].value, responseUrl)
  }
}

function confirmCancelWorkflow(task, responseUrl, wfInstanceId) {
  return new Promise((resolve, reject) => {
    task.log.info({ source: 'slack-connector.confirmCancelWorkflow', wfInstanceId }, 'wf instance id');
    request({
      url: responseUrl,
      method: 'POST',
      json: true,
      body: {
        text: 'Are you sure you want to cancel this workflow?',
        attachments: [
          {
            fallback: 'See what\'s going on!',
            author_name: 'Owner: ntorretti',
            title: 'Confirm Cancel',
            text: 'Please confirm you want to cancel this workflow',
            callback_id: 'confirm_cancel_workflow',
            actions: [
              {
                name: 'action',
                type: 'button',
                text: 'Yes',
                style: '',
                value: wfInstanceId
              },
              {
                name: 'action',
                type: 'button',
                style: '',
                text: 'No',
                value: 'No'
              }
            ]
          }
        ]
      }
    }, (err, response) => {
      if (err) {
        task.log.error({ source: 'slack-connector.confirmCancelWorkflow', err }, 'whoops');
        reject(err);
      } else {
        task.log.info({ source: 'slack-connector.confirmCancelWorkflow', response }, 'response');
        resolve({ status: 'Request successfully sent to callback API endpoint.' });
      }
    });
  });
}

function sendCancelConfirmation(task, responseUrl) {
  return new Promise((resolve, reject) => {
    request({
      url: responseUrl,
      method: 'POST',
      json: true,
      body: {
        text: 'We have successfully cancelled your workflow.',
      }
    }, (err, response) => {
      if (err) {
        task.log.error({ source: 'slack-connector.sendCancelConfirmation', err }, 'whoops');
        reject(err);
      } else {
        task.log.info({ source: 'slack-connector.sendCancelConfirmation', response }, 'response');
        resolve({ status: 'Request successfully sent to callback API endpoint.' });
      }
    });
  });
}

function cancelWorkflow(task, wfInstanceId, responseUrl) {
  return new Promise((resolve, reject) => {
    request({
      headers: { 'content-type': 'application/json' },
      url: {CANCEL_WORKFLOW_ENDPOINT},
      method: 'POST'
    }, (err, response) => {
      if (err) {
        task.log.error({ source: 'slack-connector.cancelWorkflow', err }, 'whoops');
        reject(err);
      } else {
        task.log.info({ source: 'slack-connector.cancelWorkflow', response }, 'yay');
        sendCancelConfirmation(task, responseUrl);
        resolve(response);
      }
    });
  });
}

function kickOffWorkflow(task) {
  return new Promise((resolve, reject) => {
    request({
      headers: { 'content-type': 'application/json' },
      url: {LAUNCH_WORKFLOW_ENDPOINT},
      method: 'POST',
      body: JSON.stringify({
        wfModelId: 'd32aa8ba-f153-46b5-8c62-81d14327c924',
        wfInstanceName: 'Untitled',
        wfData: {
          Originator: 'Natalie Torretti',
          Originator_Email: 'ntorretti@accusoft.com',
          email: 'ntorretti@accusoft.com'
        }
      }),
    }, (err, response) => {
      if (err) {
        task.log.error({ source: 'slack-connector.handleInteractiveMessage', err }, 'whoops');
        reject(err);
      } else {
        task.log.info({ source: 'slack-connector.handleInteractiveMessage', response }, 'yay');
        resolve(response);
      }
    });
  });
}

module.exports.initialize = (params, imports, ready) => {
  const framework = imports['prv-common-service-base'];
  const task = framework.taskLogging.createTask();
  const server = imports.server;

  task.begin('Initializing Slack connector component');

  server.post('/interactiveMessage', handleInteractiveMessage);

  task.log.info({ source: 'slack-connector.initialize' }, 'Slack connector component initialized');
  task.end();
  ready();
};

Slack has some great documentation and really is built to handle these kind of integrations. It was not that much work to get everything configured after I had the connector in place. I still needed one more piece of code on the Docubee end to be able to actually send the message to Slack. That send message function ended up looking like this:

const sendSlackMessage = imports => (task, redirectUrl, workflowInstanceId, message) => {
  return new Promise((resolve, reject) => {
    task.log.info({ source: 'utils.sendSlackMessage' }, 'sending slack message');
    request({
      url: 'https://hooks.slack.com/services/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',
      method: 'POST',
      json: true,
      body: {
        text: JSON.stringify(message),
        attachments: [
          {
            fallback: 'See what\'s going on!',
            author_name: 'Owner: ntorretti',
            title: 'Workflow Actions',
            text: 'Here are some actions you can take!',
            callback_id: 'handle_workflow_actions',
            actions: [
              {
                name: 'action',
                type: 'button',
                text: 'View dashboard',
                style: '',
                value: 'redirect',
                url: {LINK_URL}
              },
              {
                name: 'action',
                type: 'button',
                text: 'Go to workflow',
                style: '',
                value: 'redirect',
                url: redirectUrl
              },
              {
                name: 'action',
                type: 'button',
                style: '',
                text: 'Cancel Workflow',
                value: workflowInstanceId
              }
            ]
          }
        ]
      }
    }, (err, response) => {
      if (err) {
        task.log.error({ source: 'utils.sendSlackMessage', err }, 'whoops');
        reject(err);
      } else {
        task.log.info({ source: 'utils.sendSlackMessage', response }, 'response');
        resolve({ status: 'Request successfully sent to callback API endpoint.' });
      }
    });
  });
}

We called this the send SlackMessage function after the “Start Demo Workflow” was started. This sends a message back to Slack that gives the user a couple different actions that they could take on that message. If a user clicked one of the buttons in the message, a request with a specific callback ID was sent to the slack handler and the appropriate action was taken. The first image below shows how I integrated starting a workflow in Slack and the second image shows the message we sent back to Slack after a workflow was started giving the user different actions they can take.

These are just a few ways that Accusoft’s Docubee can be integrated into your daily routines. Whether it’s starting a workflow with Siri or enabling automated Slack processes, Docubee is built to help you and your organization to find the best way to automate processes.

Natalie Torretti

Natalie Torretti, Software Engineer III

Natalie joined Accusoft as a software engineer in 2016. She started on the eDocr team but has spent the last two and a half years on Docubee development team. Natalie has been a large contributor to the React front-end UI of Docubee and made several enhancements to the back-end microservices as well. She obtained her B.S. in Biobehavioral Health with a Psychology minor from Penn State as well as her A.S.T. in Information Technology from South Hills School of Business and Technology. When Natalie is not writing code she enjoys working out, spending time at the pool, and playing with her dogs.

FinTech covid stimulus

When President Joe Biden signed the $1.9 trillion American Rescue Plan Act relief package into law on March 11, 2021, millions of Americans looked forward to receiving a much-needed $1400 stimulus check from the government. Although many people would receive paper checks directly from the Internal Revenue Service (IRS), anyone who had previously filed their taxes electronically and had returns delivered to their bank accounts were eligible to receive their stimulus relief via direct deposit. The IRS set the date of March 17 for the delivery of stimulus funds, which would give sufficient time for payments to make their way through the complex Automated Clearing House (ACH) system used to transfer payments electronically.

FinTech Lenders to the Rescue

But on March 12, just one day after the landmark bill was signed into law, many FinTech banking customers received notifications that funds had already been delivered to their accounts. The digital banking startup Current bragged on Twitter that afternoon that it had already distributed $600 million to 250,000 customers. On March 15, the FinTech lender Chime announced that it had paid about $3.5 billion to more than one million customers over the weekend. Chime had previously made headlines the previous spring when it advanced stimulus funds from the CARES Act to customers before the government actually made the money available.

Unsurprisingly, the announcements caused quite an uproar from customers at traditional banks that did not start releasing funds until the previously announced March 17 date. Despite many of the accusations leveled at these lenders, however, the discrepancy had nothing to do with banks deliberately withholding funds and everything to do with the unique business model of leading FinTech lenders.

In the case of Chime, for instance, the company frequently makes payment funds available to customers as soon as the transfer is initiated, rather than waiting for it to clear through the ACH. “I guess you could argue we’re taking a risk,” said Chime co-founder and CEO Chris Britt. “But we’ve been told by the Federal Reserve that the money is coming so we don’t think it’s that much of a risk.” 

Traditional banks were quick to respond by saying that they could not make funds available before March 17 because that was the date set by the government for the money to actually be transferred. For FinTech companies with higher risk tolerance, the delay provided a unique opportunity to demonstrate the benefits of digital lending applications. During the first wave of stimulus checks in April of 2020, mobile banking app registrations increased by 200% over the previous month as Americans rushed to embrace various forms of digital banking.

The Flexible Features of FinTech Applications

Part of the reason why FinTech lenders are willing to offer more generous services to customers is that they often assess risk differently than traditional banks. Armed with sophisticated algorithms and data capture tools, FinTech applications are able to gather more information about customers and lending sources to create a more accurate risk profile.

Over the last two decades, FinTech developers have worked hard to build the digital platforms that innovative firms are using to offer these services. These software solutions need to be flexible enough to process information quickly and provide essential functionality that helps both FinTech firms and their customers to view and share information quickly and easily.

Forms Processing

Structured forms are an essential tool of the financial services industry, whether it’s a loan application or an IRS tax form. The faster those forms can be processed, the more quickly firms can deliver money into the hands of their customers. That’s why FinTech developers need to make sure they’re incorporating the forms processing tools that make it easy to automate data capture. Given that the latest round of COVID stimulus funds are based upon tax return information, many customers will be scrambling to update their records as quickly as possible. By integrating the tools to process that data with haste, FinTech developers can help firms keep pace with the needs of their clients.

Easy Viewing

While FinTech developers are primarily building applications for lenders, they should always keep in mind that a solution that doesn’t provide a positive customer experience will have trouble catching on in a crowded marketplace. Today’s banking customers expect transparent and intuitive applications that allow them to quickly view their financial records and check the status of applications or loans. By building HTML5 viewing capabilities into their FinTech solutions, developers can help customers track the status and history of their finances, which is certainly a major concern as they monitor the status of their stimulus payments.

Interactive Tools

With all of the nuances surrounding COVID stimulus payments in the latest round of legislation, many customers will be turning to their FinTech lender to understand how much money they can expect to receive based on their eligibility. A well-designed spreadsheet may be able to provide this or similar information much more quickly than building a dedicated tool within an application, but downloading XLSX files can be a hassle for many people, especially for customers who primarily interact with their FinTech bank using a mobile device. By giving firms the ability to securely embed spreadsheets into their applications, developers can help them to quickly share tools and resources with customers, regardless of what kind of device they’re using.

Empowering the FinTech Future with Accusoft

Accusoft’s collection of SDK and API integrations allow FinTech developers to build a broad range of features into their applications to streamline processing and accelerate vital financial services. 

Our FormSuite forms SDK collection can automate form identification and OCR data capture to help FinTech applications maintain their speed advantage when it comes to processing applications and loans. For financial platforms that need comprehensive viewing functionality, PrizmDoc Viewer’s HTML5 viewing, annotation, and redaction capabilities can turn any platform into a powerful document viewer that helps users handle most of their financial business purely through their FinTech application. 

And when it comes to embedding interactive spreadsheets to provide quick reference and calculations for various services, PrizmDoc Cells allows developers to bypass the difficult work of building that functionality from the ground up. To learn more about how Accusoft integrations are powering the next generation of FinTech applications, visit our financial services page and download our FinTech integrations fact sheet.

top coding trends

The software development industry is changing more rapidly than ever before. With new technology hitting the market on a regular basis, software vendors need to become flexible enough to adapt to the top coding trends if they want to remain competitive.

After a tumultuous 2020, the industry has seen a number of key trends emerge in the first half of 2021. Here are some of the top coding trends worth watching in the second half of the year.

Top 5 Coding Trends of 2021 (So Far)

1. Open-Source Evolution

Developers have been turning to open-source solutions for some time now as a quick way to integrate new features into their applications. While there are a lot of great benefits to using open-source code, it’s not always the simple solution that it appears to be. Substantial work may need to be done to implement the specific features an application requires. More importantly, open-source solutions rarely offer much in the way of support or security updates, and there can also be complicated intellectual property issues to consider when incorporating open source code into a proprietary application.

That’s why many innovative developers are using stable open-source solutions as a foundation for creating more feature-rich software SDKs. For teams building new applications, it’s often much easier to implement one of these integrations because it will require far less configurations and additional coding to get up and running. They can also get the benefits of dedicated support and not have to worry about whether their new integration will create any legal issues down the road.

2. UX Design

With the proliferation of Software as a Service (SaaS) platforms and the widespread use of open source development resources, it’s becoming easier for organizations to find the applications that suit their business needs. What they can’t always find, however, is a solution that’s easy for their employees and customers to use. That’s why the quality of an application’s user experience (UX) is quickly becoming a key differentiator in the software market.

Rather than implementing UX features at a later stage of the coding process, developers need to consider how users will interact with their solution from the very beginning. Software needs to be intuitive and easy to implement out-of-the-box. This applies equally to end-user products and developer-focused SDK integrations. No one has time to struggle with software that’s difficult to use. If a solution proves too cumbersome and hard to implement, customers will likely turn to a competing product that offers a better user experience. The more time developers spend considering their software’s UX, the better they’ll be able to adapt it to customer needs in the future.

3. Responsive Mobile Support

For many years, there was a somewhat artificial distinction between mobile software development and desktop development. But in a world where half of all internet activity comes from mobile devices, no developer working on web-based applications can afford to consider their software “just” for desktops. Just as website designers have been building pages that respond dynamically to different screen sizes and control interfaces, developers must also account for the unique characteristics of mobile devices.

The unique characteristics of mobile screens present specific challenges regarding the application’s user interface (UI). Simply providing standard desktop controls is bound to result in a frustrating mobile experience. Mobile responsive applications can accommodate touch-specific controls (such as pinch-to-zoom) without compromising the desktop experience at the same time. Developers must think about what kinds of devices their software solutions will be used on if they’re to build features and tools that will truly benefit their customers.

4. API Integrations

Today’s developers no longer need to build every feature their application might require from scratch. Thanks to a new generation of web API technology, it’s easier than ever to find software integrations that can quickly and easily add vital features without having to dedicate weeks of development time to building them. Understanding which web application features can be incorporated via a REST API helps development teams to focus their limited resources and time on the truly unique features that will help set them apart from the competition.

Utilizing web API technologies can streamline sprints and shorten development time significantly. That’s because much of the “trial and error” work of building a new feature is eliminated. Rather than designing and testing new capabilities for months, developers can simply implement a tested and proven web API integration within a matter of days. That helps to keep budgets under control and development schedules on track to make targeted launch days.

5. Remote Work

When the COVID-19 pandemic struck the world in early 2020, many software developers transitioned to a remote workplace arrangement. As other industries begin to tentatively return to the office, tech workers seem to have become quite accustomed to working remotely. According to a late 2020 survey conducted by Indeed, nearly half of participants reported that they now have the option to work remotely on a permanent basis, with 95 percent of them planning to do so. Perhaps even more telling, however, was the finding that 60 percent of tech workers are willing to take a pay cut in order to keep working from home.

Software vendors will have to accommodate these expectations if they hope to remain competitive when it comes to finding and retaining talent. Project managers should not expect work patterns to go back to the way they were before the pandemic. They will be better served focusing on how to organize remote work efficiently and how to provide the resources developers need to be productive while working from home. Transitioning to a more remote workforce is also allowing organizations to tap into a much broader pool of talent, which will help to bring more diverse voices and experiences into the development process.

Keeping an Eye on Future Trends

The software development teams at Accusoft are always looking ahead to see where today’s coding trends are leading the industry. That’s why we’ve been building easy-to-implement, lightweight SDKs like the free-to-use Accusoft PDF Viewer alongside our stable of versatile API solutions like PrizmDoc Viewer. We also continue to make ongoing improvements to our products to provide a better user experience for customers.

Our collection of software integrations can help development teams keep up with today’s top coding trends. Whether you’re looking to quickly integrate new features into an existing application or are looking for the right tools to support your next project, we have the API and SDK resources to keep you on-budget and on-time. Check out the Accusoft Resource Center to learn more.

Why Your Application Needs a Built-in PDF Reader

Managing and viewing documents is critical to providing a quality user experience in today’s applications. Without some way of controlling the presentation of digital files like PDFs, organizations put themselves in a situation where they must rely on external solutions that may not be responsive to their needs. PDF integration into their applications helps developers to maintain control over their documents while providing a more consistent viewing experience for users.

What Are Your PDF Reader Options?

Sharing and viewing PDFs online has become much easier with the development of HTML5 viewing technology and PDF.js-based software. For many years, the only way to view a PDF was to download a file and open it using a dedicated PDF reader application. Although many of these readers could be added to a web browser using a plug-in, this wasn’t always a reliable solution and inconsistent support for these extensions often created security risks.

After Mozilla introduced the PDF.js open-source library in 2011, integrated PDF viewing quickly became an essential feature for web browsers. Most users now simply take PDF viewing for granted, trusting that their browser will be able to open and read any file. For some organizations, relying on a browser PDF reader is a perfectly reasonable solution, especially if they don’t have any concerns over controlling the document viewing experience.

But for many developers building web applications, these browsers and external PDF readers put them at the mercy of third-party providers. Changes or security problems with these solutions can leave development teams scrambling to implement workarounds that could have been avoided if they had their own dedicated viewing solution. That’s why applications increasingly feature a built-in PDF reader that allows them to better manage and present important digital documents.

Why Your Application Needs a Built-in PDF Reader

The core problem with relying on an external viewing solution comes down to control. In order to view a PDF in a dedicated reader, the file needs to be downloaded. Once that document is removed from a secure application, it could easily be distributed or altered without any authorization or oversight. This often results in serious version confusion that leaves everyone wondering which version of a PDF is the most up-to-date. By keeping documents within a controlled application, developers can ensure that the files viewed there are current.

Relying on external PDF viewers can also create an inconsistent user experience. Since not all viewers render documents, in the same way, it’s impossible to control what someone will see when they open a given PDF. In some cases, that could result in wrong fonts being displayed or some image layers failing to render properly. But it may also prevent someone from even viewing a file at all. For example, browser-based viewers that use the base PDF.js library without making any improvements to it often struggle to render lengthy or complex files. 

When applications incorporate a built-in PDF reader, developers can ensure that every document viewed within that solution will look the same on every device (and that it will open in the first place!). This level of control is incredibly important for organizations looking to build a frictionless and compelling user experience.

Integrating a PDF Reader

By incorporating a PDF reader into their web-based applications, developers are able to both retain full control over the viewing experience and keep files within a protected environment. When users are interacting with the application, all PDF viewing can be handled by the built-in viewer rather than handed off to external software. This makes it easier to manage access effectively and limits the number of downloads. 

Since every user will be viewing documents through the same built-in PDF reader, developers can also craft a consistent experience across multiple platforms. With more and more people accessing their applications with mobile devices, it’s important for development teams to offer responsive viewing solutions that can accommodate various screen sizes and interfaces.

In order to maintain complete control over files and deliver better performance, a built-in PDF reader should be able to operate as an entirely client-side solution. Whether it’s running within an on-premises technology stack or as part of an application’s cloud deployment, a PDF viewer without any complicated dependencies never has to worry about connecting to a third-party service to facilitate viewing. 

But why stop at PDF viewing?

PDF Editing

Often users need the ability to view as well as collaborate on their PDF documents, and providing the ability to edit those documents presents a challenge for developers. In a recent survey conducted amongst developers, there appears to be a disconnect between the PDF editing features that are available in most applications, to what developers actually need to fulfill and enhance their applications. So what’s the solution? 

Third-party Integrated PDF Viewing and Editing

A PDF solution provider has already worked out the challenges associated with viewing and editing PDF documents within an application. They’ve also devoted their resources to improving their document capabilities and expanding features to offer greater flexibility.

A good third-party provider also offers extensive support during and after the implementation process. If the developer needs to add a new PDF-related capability to their application or if they encounter a problem, they can quickly resolve the issue by working with their provider rather than wasting valuable resources trying to identify and fix the problem themselves. That combination of expertise and service means that developers can spend more time focusing on their application’s unique features rather than continuously wrestling with PDF-related challenges.

Enhance Your Application with PDF Integrations from Accusoft

With more than three decades of experience managing documents and images, Accusoft has been building innovative PDF solutions since the format was first introduced. Whether you need to add flexible front-end viewing and editing features to your application or are looking to add powerful programmatic PDF capabilities into the back end of your software, we provide a wide range of PDF solutions that address multiple development needs.

To learn more about how Accusoft can solve your PDF document management challenges, talk to one of our PDF specialists today and find the integration that works best for your software project.