← Back to list

Criando um Sistema de Assinatura Digital no Google Docs com Apps Script.

🚀 Automatize a inserção de assinaturas nos seus documentos de forma simples!

Emerson Maia · 2025-02-18 12:57 · 0 claps · 3.8 min read
#apps-script #google-docs #bulma #sweetalert #google-sheets
Open on Medium ↗

Criando um Sistema de Assinatura Digital no Google Docs com Apps Script.

🚀 Automatize a inserção de assinaturas nos seus documentos de forma simples!

Telas da aplicação

Telas da aplicação

Pasta para salvar a assinaturas

Pasta para salvar a assinaturas

Se você já precisou adicionar assinaturas digitais em documentos do Google Docs manualmente, sabe como pode ser cansativo. Neste tutorial, vamos criar um sistema automático de assinatura digital que permite desenhar a assinatura e inseri-la diretamente no documento.

Tecnologias usadas:

✔ Google Apps Script — Para automatizar e manipular o Google Docs e Drive. ✔ HTML, CSS e JavaScript — Para criar a interface do usuário. ✔ Google Drive API — Para armazenar as assinaturas como imagens.

No final, teremos um menu no Google Docs que abrirá uma interface onde o usuário poderá desenhar sua assinatura e adicioná-la automaticamente ao documento.

Bibliotecas que Vamos Usar

Bulma (CSS Framework) Bulma é um framework CSS leve que ajuda a estilizar a interface sem precisar escrever muito CSS. Usamos ele para criar botões, caixas e organizar os elementos na tela.

SweetAlert2 (Pop-ups Personalizados) O SweetAlert2 permite criar alertas mais bonitos e interativos do que os alertas padrão do JavaScript. Usamos ele para exibir mensagens de sucesso e erro para o usuário.

Signature Pad (Desenho da Assinatura) Essa biblioteca permite desenhar assinaturas diretamente no navegador usando um <canvas>. Com ela, conseguimos capturar a assinatura como uma imagem e salvá-la no Google Drive.

Código Back-End (Apps script)

let folderId = PropertiesService.getScriptProperties().getProperty('folderId');

function onOpen() {
  DocumentApp.getUi()
    .createMenu('Assinatura Digital')
    .addItem('Assinar Documento', 'showModal')
    .addToUi();
}

function showModal() {
  const html = HtmlService.createHtmlOutputFromFile('sidebar')
    .setTitle('Assinatura Digital')
    .setWidth(400)
    .setHeight(500);

  DocumentApp.getUi()
    .showModalDialog(html, 'Assinatura Digital');
}

function saveSignature(dataURL) {
  const fileName = 'assinatura_' + DocumentApp.getActiveDocument().getName() + '.png';
  const folder = DriveApp.getFolderById(folderId);

  if (folder) {
    const blob = Utilities.newBlob(Utilities.base64Decode(dataURL.split(',')[1]), 'image/png', fileName);
    folder.createFile(blob);
  } else {
    console.log('Pasta não encontrada!');
    throw new Error('Pasta não encontrada!'); // Lança um erro para ser tratado no HTML
  }
}

function signDocument(dataURL) {
  try {
    const fileName = 'assinatura_' + DocumentApp.getActiveDocument().getName() + '.png';
    const folder = DriveApp.getFolderById(folderId);

    if (!folder) {
      throw new Error('Pasta não encontrada!');
    }

    const files = folder.getFilesByName(fileName);
    if (files.hasNext()) {
      throw new Error('Este documento já foi assinado. Não é possível assiná-lo novamente.');
    } else {
      saveSignature(dataURL); // Salva a assinatura
      insertSignature();       // Insere a assinatura
    }

  } catch (error) {
    console.error(error); // Log do erro no Apps Script
    throw error;         // Re-lança o erro para ser tratado no HTML
  }
}

function insertSignature() {
  const fileName = 'assinatura_' + DocumentApp.getActiveDocument().getName() + '.png';
  const folder = DriveApp.getFolderById(folderId);

  if (!folder) {
      console.log('Pasta não encontrada: ' + folderId);
      return; // Sai da função se a pasta não for encontrada
  }

  const files = folder.getFilesByName(fileName);

  if (files.hasNext()) {
    const file = files.next();
    const blob = file.getBlob();

    const document = DocumentApp.getActiveDocument();
    const body = document.getBody();

    const elements = body.getParagraphs();
    for (let i = 0; i < elements.length; i++) {
      const element = elements[i];
      if (element.getText().includes('[ASSINATURA]')) {
        element.replaceText('[ASSINATURA]', '');
        body.appendImage(blob);
        return; // Sai da função após inserir a assinatura
      }
    }
    console.log('Marcador [ASSINATURA] não encontrado no documento.'); // Mensagem se o marcador não for encontrado

  } else {
    console.log('Arquivo não encontrado: ' + fileName);
  }
}

function closeModal() {
  return HtmlService.createHtmlOutput('').close();
}

Para o id da pasta onde salvamos as imagens geradas usei o PropertiesService, caso não conheça essa possibilidade, de uma olhada nesse tutorial de como usar.

[embed]

Você pode colocar o id da pasta direto no código.

Código Front-End (Lado client)

<!DOCTYPE html>
<html>
<head>
  <base target="_top">
  <title>Assinatura Digital</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
  <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
  <script src="https://cdn.jsdelivr.net/npm/signature_pad@4.1.5/dist/signature_pad.umd.min.js"></script>
</head>

<body class="has-background-grey-lighter p-4">
  <div class="box">
    <h2 class="title is-2">Assinatura Digital</h2>
    <canvas id="signature-pad" width="300" height="150" class="border"></canvas><br>
    <div class="mt-4">
      <button id="clear" class="button is-danger">Limpar</button>
      <button id="sign" class="button is-info">Assinar</button>
    </div>
  </div>

  <script>
    const canvas = document.getElementById('signature-pad');
    const clearButton = document.getElementById('clear');
    const signButton = document.getElementById('sign');

    const signaturePad = new SignaturePad(canvas, {
      minWidth: 5,
      maxWidth: 10,
      penColor: "#000",
      backgroundColor: "#fff"
    });

    clearButton.addEventListener('click', () => {
      signaturePad.clear();
    });

    signButton.addEventListener('click', () => {
      if (signaturePad.isEmpty()) {
        Swal.fire({
          icon: 'warning',
          title: 'Atenção!',
          text: 'Por favor, assine antes de assinar o documento.'
        });
        return;
      }

      const dataURL = signaturePad.toDataURL('image/png');

      // 🔹 Bloqueia os botões e ativa o spinner
      signButton.classList.add('is-loading');
      signButton.disabled = true;
      clearButton.disabled = true;

      google.script.run
        .withFailureHandler(error => {
          console.error("Erro ao salvar assinatura:", error);

          // 🔹 Remove o spinner e reativa os botões em caso de erro
          signButton.classList.remove('is-loading');
          signButton.disabled = false;
          clearButton.disabled = false;

          Swal.fire({
            title: 'Erro!',
            text: error.message,
            icon: 'error',
            confirmButtonText: 'Ok'
          });
        })
        .withSuccessHandler(() => {
          // 🔹 Agora insere a assinatura
          google.script.run
            .withFailureHandler(error => {
              console.error("Erro ao inserir assinatura:", error);

              // 🔹 Remove o spinner e reativa os botões em caso de erro
              signButton.classList.remove('is-loading');
              signButton.disabled = false;
              clearButton.disabled = false;

              Swal.fire({
                title: 'Erro!',
                text: error.message,
                icon: 'error',
                confirmButtonText: 'Ok'
              });
            })
            .withSuccessHandler(() => {
              // 🔹 Remove o spinner antes da mensagem aparecer
              signButton.classList.remove('is-loading');
              signButton.disabled = false;
              clearButton.disabled = false;

              // 🔹 Exibe a mensagem de sucesso
              Swal.fire({
                title: 'Sucesso!',
                text: 'Documento assinado e salvo.',
                icon: 'success',
                confirmButtonText: 'Ok'
              }).then(() => {
                google.script.run.closeModal();
                signaturePad.clear();
              });
            })
            .insertSignature();
        })
        .signDocument(dataURL);
    });
  </script>
</body>
</html>

appscript.json

{
  "timeZone": "America/Sao_Paulo",
  "dependencies": {
  },
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8"
}

Agora, ao abrir o Google Docs, você pode acessar “Assinatura Digital” → “Assinar Documento”, assinar e a assinatura será salva e inserida automaticamente no documento!

🚀 Assim você tem um sistema de assinatura digital funcional!

PROJETO NO GITHUB DOCS PARA CÓPIA

▶️ ***Canal Youtu*be 🚀 *Meu Git *📚 [*Documentação apps script](https://bit.ly/docappsscript)***


메타데이터
post_id
b3944e72d758
slug
criando-um-sistema-de-assinatura-digital-no-google-docs-com-apps-script-b3944e72d758
url
https://medium.com/@maiaemersondev/criando-um-sistema-de-assinatura-digital-no-google-docs-com-apps-script-b3944e72d758
canonical_url
https://medium.com/@maiaemersondev/criando-um-sistema-de-assinatura-digital-no-google-docs-com-apps-script-b3944e72d758
author_url
https://medium.com/@maiaemersondev
status
ok
fetched_at
2026-06-26 08:21:59