Browser-Based Document Signing on Website

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1215
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1043
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    815

Browser-Based Document Signing Implementation

Browser-based document signing is a process where user views document, confirms their agreement, and signs without installing additional software. Covers wide spectrum: from simple electronic signature (click "Agree"), drawn signature to simple QES via SMS.

Levels of Electronic Signature

Simple ES — identity confirmation via login/password or SMS code. Legally weak, suitable for internal documents and agreements.

Enhanced non-qualified ES — created using keys but without certified CA certificate. Used in b2b with mutual EDI agreement.

Enhanced qualified ES (QES) — full legal effect. Requires certified SKZI.

Most "browser signing" scenarios are simple or enhanced non-qualified ES.

Signing Workflow

User opens document
  ↓
View PDF/HTML document
  ↓
Enter signature (draw, text, or SMS)
  ↓
Document hash + metadata → server
  ↓
Server creates signed version
  ↓
Notification + storage

PDF Viewing in Browser

Before signing, user must read document. Embed PDF viewer:

import { Viewer, Worker } from '@react-pdf-viewer/core';
import { defaultLayoutPlugin } from '@react-pdf-viewer/default-layout';
import '@react-pdf-viewer/core/lib/styles/index.css';

function DocumentViewer({ pdfUrl, onDocumentRead }) {
  const [pagesRead, setPagesRead] = useState(new Set<number>());
  const totalPagesRef = useRef(0);

  const handlePageChange = ({ currentPage }: { currentPage: number }) => {
    setPagesRead(prev => {
      const updated = new Set(prev).add(currentPage);
      if (updated.size >= totalPagesRef.current) {
        onDocumentRead(); // Unlock sign button
      }
      return updated;
    });
  };

  return (
    <Worker workerUrl="/pdf.worker.min.js">
      <Viewer
        fileUrl={pdfUrl}
        plugins={[defaultLayoutPlugin()]}
        onPageChange={handlePageChange}
        onDocumentLoad={({ doc }) => { totalPagesRef.current = doc.numPages; }}
      />
    </Worker>
  );
}

Applying Signature to PDF

After receiving user signature, embed it in PDF and create signed version:

// Backend: process signed document
async function processDocumentSignature(documentId, userId, signatureDataUrl, metadata) {
  const document = await db.documents.findByPk(documentId);

  // 1. Load original PDF
  const originalPdf = await s3.getObject({ Bucket: BUCKET, Key: document.s3Key }).promise();

  // 2. Compute hash for audit log
  const originalHash = crypto.createHash('sha256').update(originalPdf.Body).digest('hex');

  // 3. Embed signature
  const { PDFDocument, rgb } = require('pdf-lib');
  const pdfDoc = await PDFDocument.load(originalPdf.Body);
  const lastPage = pdfDoc.getPages().at(-1);

  // Add signature image
  const signatureImage = await pdfDoc.embedPng(
    Buffer.from(signatureDataUrl.replace(/^data:image\/png;base64,/, ''), 'base64')
  );
  lastPage.drawImage(signatureImage, { x: 60, y: 50, width: 150, height: 50 });

  // Add text stamp
  const font = await pdfDoc.embedFont('Helvetica');
  lastPage.drawText(
    `Signed: ${metadata.signerName}\n${metadata.signedAt.toISOString()}\nIP: ${metadata.ip}`,
    { x: 60, y: 30, size: 8, font, color: rgb(0.4, 0.4, 0.4) }
  );

  const signedPdfBytes = await pdfDoc.save();

  // 4. Save signed version
  const signedKey = `signed/${documentId}/${userId}.pdf`;
  await s3.putObject({ Bucket: BUCKET, Key: signedKey, Body: signedPdfBytes }).promise();

  // 5. Record in database
  await db.documentSignatures.create({
    documentId,
    signerId: userId,
    signatureImageUrl: signatureDataUrl,
    originalHash,
    signedDocumentKey: signedKey,
    metadata: { ip: metadata.ip, userAgent: metadata.userAgent, signedAt: new Date() },
  });

  return signedKey;
}

SMS Confirmation as Simple ES

For legally significant agreements — phone number confirmation:

// Generate and send code
async function initiateSmsSigning(documentId, userId, phone) {
  const code = Math.random().toString(36).substring(2, 8).toUpperCase();
  const codeHash = bcrypt.hashSync(code, 10);

  await redis.setex(
    `sms_sign:${documentId}:${userId}`,
    300, // 5 minutes
    JSON.stringify({ codeHash, phone, attempts: 0 })
  );

  await smsService.send(phone, `Document signing code: ${code}. Valid for 5 minutes.`);
}

// Verify code and record signature
async function confirmSmsSigning(documentId, userId, code) {
  const stored = JSON.parse(await redis.get(`sms_sign:${documentId}:${userId}`));
  if (!stored || !bcrypt.compareSync(code, stored.codeHash)) {
    throw new Error('Invalid code');
  }

  await redis.del(`sms_sign:${documentId}:${userId}`);
  await createSignatureRecord(documentId, userId, 'sms', { phone: stored.phone });
}

Multi-Signing

Documents often require signatures from multiple parties (contract between client and provider). Workflow:

  1. Party A signs → document gets partially_signed status
  2. Notification to Party B + signing link
  3. Party B signs → status fully_signed
  4. Both parties get final document via email

Timeframe

PDF viewing + drawn signature + PDF embedding + audit log — 4–5 days. SMS confirmation — 1–2 days. Multi-signing with workflow — 3–4 days.