🚀 Executive Summary

TL;DR: Manually generating NDAs from Typeform submissions is a repetitive, error-prone task consuming significant time. This process can be automated using a Python script that fetches Typeform data, populates a Google Doc template via the Google Docs API, and saves the final NDA to Google Drive.

🎯 Key Takeaways

  • The automation pipeline integrates Typeform, Google Docs, and Google Drive APIs using Python libraries like `requests` and `google-api-python-client`.
  • Google Service Accounts are essential for secure, server-side authentication with Google APIs, requiring explicit sharing of template documents and destination folders with the service account’s email.
  • Dynamic content population in Google Docs is achieved by using `batchUpdate` requests with `replaceAllText` operations to replace specific placeholders (e.g., `{{FULL_NAME}}`) with Typeform submission data.

Automate NDA Generation from Typeform inputs

Automate NDA Generation from Typeform inputs

Alright, let’s talk about a real time-sink: manual document generation. For the longest time, whenever a new contractor or partner came on board, I’d get a notification, manually copy their details from a Typeform submission, paste them into our NDA template, save it as a PDF, and then file it away in the right folder. It’s maybe 5-10 minutes per document, but that’s death by a thousand cuts. I calculated I was losing a couple of hours a month to this mindless task. This workflow is how I reclaimed that time, and hopefully, it’ll do the same for you.

We’re going to build a Python script that automatically pulls new submissions from a Typeform, uses that data to populate a Google Doc template, and saves the final NDA as a new document.

Prerequisites

Before we dive in, make sure you have the following ready to go. Getting these sorted out first will make the rest of the process much smoother.

  • A Typeform account with a form ready for collecting information.
  • A Google Workspace account (a standard Gmail account works too, but Workspace is better for this).
  • Python 3 installed on your machine or server.
  • Familiarity with enabling APIs in the Google Cloud Console. You’ll need the Google Drive API and Google Docs API enabled.
  • API credentials for Typeform and Google Cloud (we’ll cover how to get these).

The Guide: Step-by-Step

Step 1: Configure Your Typeform

First, create a form in Typeform to collect the necessary details. For an NDA, this is usually simple:

  • Full Name (Short Text)
  • Company Name (Short Text)
  • Date (Date field)

Once your form is published, you’ll need its unique Form ID. You can find this in the URL when you’re editing it. The URL will look something like `https://admin.typeform.com/form/aBcDeF12/create`. That last part is your ID.

You’ll also need a Personal Access Token from Typeform. Go to your account settings, find the “Personal access tokens” section, and generate a new token with `forms:read` and `responses:read` scopes. Store this securely.

Step 2: Create the Google Doc Template

Next, create a new Google Doc that will serve as your NDA template. Write out the legal text and use placeholders for the dynamic content. The key is to use a unique, consistent format for your placeholders. I like using double curly braces.

For example:

This Non-Disclosure Agreement is entered into by and between TechResolve Inc. and {{COMPANY_NAME}} (“Recipient”), represented by {{FULL_NAME}}, effective as of {{SIGN_DATE}}.

Once the template is ready, grab its Document ID from the URL. It’s the long string of characters in the middle: `https://docs.google.com/document/d/1a2b3c4d_5e6f7g8h9i0j/edit`. Also, create a folder in Google Drive where you want the generated NDAs to be saved and grab its Folder ID from its URL.

Step 3: Setting Up the Python Environment

I’ll skip the standard virtualenv setup since you likely have your own workflow for that. Let’s jump straight to the dependencies. You’ll need a few Python libraries to interact with the APIs. You can install them using pip: `requests` for the Typeform API, and Google’s client libraries: `google-api-python-client`, `google-auth-httplib2`, and `google-auth-oauthlib`.

For credentials, I recommend creating a simple `config.env` file in your project directory to store your secrets. Never hardcode them in your script. Your file should look like this:


TYPEFORM_API_KEY=your_typeform_personal_access_token
TYPEFORM_FORM_ID=your_form_id
GOOGLE_DOC_TEMPLATE_ID=your_template_doc_id
GOOGLE_DRIVE_FOLDER_ID=your_destination_folder_id

You’ll also need to set up Google API credentials. For a script like this that runs on a server, a Service Account is the best approach. Go to the Google Cloud Console, create a service account, grant it Editor permissions, and download the JSON key file. Rename it to `credentials.json` and place it in your project directory.

Pro Tip: When setting up your Google Service Account, make sure you share both the template Google Doc and the destination Google Drive folder with the service account’s email address (it looks like `my-service-account@your-project.iam.gserviceaccount.com`). If you don’t, you’ll get permission denied errors. This is a classic “gotcha”.

Step 4: The Python Script

Now for the fun part. Let’s write the script that ties everything together. We’ll structure it with a few functions: one to get Typeform data, one to create the Google Doc, and a main function to orchestrate the process.

Here’s the complete script. I’ve added comments to explain the logic behind each part.


import os
import requests
from datetime import datetime
from google.oauth2 import service_account
from googleapiclient.discovery import build

# --- CONFIGURATION ---
# In a real setup, I'd use a library like python-dotenv to load this
# For simplicity, we'll pretend these are loaded from a config.env file.
TYPEFORM_API_KEY = "your_typeform_personal_access_token"
TYPEFORM_FORM_ID = "your_form_id"
TEMPLATE_ID = "your_template_doc_id"
FOLDER_ID = "your_destination_folder_id"

# Path to your service account key file
SERVICE_ACCOUNT_FILE = 'credentials.json'

# --- GOOGLE API SETUP ---
SCOPES = ['https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/documents']
creds = service_account.Credentials.from_service_account_file(
        SERVICE_ACCOUNT_FILE, scopes=SCOPES)
drive_service = build('drive', 'v3', credentials=creds)
docs_service = build('docs', 'v1', credentials=creds)


def get_latest_typeform_submission(api_key, form_id):
    """Fetches the most recent submission from a Typeform."""
    print("Fetching latest Typeform submission...")
    headers = {
        'Authorization': f'Bearer {api_key}',
    }
    # Get the most recent, completed submission
    url = f"https://api.typeform.com/forms/{form_id}/responses?page_size=1&completed=true"
    
    try:
        response = requests.get(url, headers=headers)
        response.raise_for_status() # Raises an HTTPError for bad responses
        data = response.json()

        if not data['items']:
            print("No submissions found.")
            return None

        # The structure of the response can be complex. You need to map field IDs to answers.
        # It's best to inspect your form's response JSON to get the correct field IDs.
        answers = data['items'][0]['answers']
        
        # Example: Let's assume you know the field IDs from the form API
        # Replace 'field_id_name', 'field_id_company', 'field_id_date' with your actual IDs.
        submission_data = {
            "fullName": next((a['text'] for a in answers if a['field']['id'] == 'field_id_name'), 'N/A'),
            "companyName": next((a['text'] for a in answers if a['field']['id'] == 'field_id_company'), 'N/A'),
            "signDate": next((a['date'] for a in answers if a['field']['id'] == 'field_id_date'), datetime.now().strftime('%Y-%m-%d')),
        }
        
        print(f"Found submission for: {submission_data['fullName']}")
        return submission_data

    except requests.exceptions.RequestException as e:
        print(f"Error fetching from Typeform API: {e}")
        return None

def generate_nda_from_template(data):
    """Copies the template and fills it with submission data."""
    if not data:
        print("No data provided to generate document.")
        return

    full_name = data['fullName']
    company_name = data['companyName']
    sign_date = data['signDate']
    
    # Create a filename for the new document
    new_doc_title = f"NDA - {company_name} - {full_name}"

    print(f"Generating document: {new_doc_title}")

    # --- 1. Copy the Template Document ---
    copy_body = {
        'name': new_doc_title,
        'parents': [FOLDER_ID]
    }
    
    try:
        new_doc = drive_service.files().copy(
            fileId=TEMPLATE_ID,
            body=copy_body
        ).execute()
        new_doc_id = new_doc['id']
        print(f"Successfully copied template. New Doc ID: {new_doc_id}")

        # --- 2. Replace Placeholders in the New Document ---
        requests = [
            {
                'replaceAllText': {
                    'containsText': {
                        'text': '{{FULL_NAME}}',
                        'matchCase': True
                    },
                    'replaceText': full_name
                }
            },
            {
                'replaceAllText': {
                    'containsText': {
                        'text': '{{COMPANY_NAME}}',
                        'matchCase': True
                    },
                    'replaceText': company_name
                }
            },
            {
                'replaceAllText': {
                    'containsText': {
                        'text': '{{SIGN_DATE}}',
                        'matchCase': True
                    },
                    'replaceText': sign_date
                }
            }
        ]
        
        docs_service.documents().batchUpdate(
            documentId=new_doc_id,
            body={'requests': requests}
        ).execute()

        print("Document generation complete.")
        # You could add logic here to export to PDF or email the document

    except Exception as e:
        print(f"An error occurred during document generation: {e}")


def main():
    """Main function to run the workflow."""
    # In a real application, you'd fetch these from your config.env
    submission = get_latest_typeform_submission(TYPEFORM_API_KEY, TYPEFORM_FORM_ID)
    
    # Simple check to see if we got data.
    # A more robust solution would track processed submission IDs in a database or file.
    if submission:
        generate_nda_from_template(submission)

if __name__ == '__main__':
    main()

Pro Tip: The script as written fetches the single most recent submission. In a production environment, this is a bit naive. I’d recommend storing the `response_id` of each processed Typeform submission in a simple text file or a small database (like SQLite). Before processing, you’d check if the ID has already been seen. This prevents creating duplicate documents if you run the script multiple times.

Step 5: Scheduling the Script

To make this truly automated, you need to run it on a schedule. If you’re on a Linux server, a simple cron job is perfect for this. For example, to run the script every hour, you would set up a cron job like this:

`0 * * * * python3 generate_nda.py`

This way, you’re not constantly hitting the APIs, but you’re still processing new submissions in a timely manner.

Where I Usually Mess Up (Common Pitfalls)

1. **API Permissions:** I’ve lost count of how many times I’ve forgotten to enable the Google Drive and Google Docs APIs in the Cloud Console or failed to share the folder/doc with my service account. The script will fail with a `PermissionDenied` error, and it’s always the first thing I check now.
2. **Placeholder Mismatch:** Typos are the enemy. If your template says `{{FULL_NAME}}` but your script is looking for `{{FULLNAME}}`, it will fail silently—the placeholder just won’t be replaced. Double-check that they match exactly, including case.
3. **Incorrect Typeform Field IDs:** The trickiest part of the Typeform API is parsing the answers. Each field has a unique, random-looking ID. You need to make a sample call to the API (or look at the JSON payload in their webhooks section) to find the correct IDs for “Full Name,” “Company Name,” etc., and use those in the script.

Conclusion

And there you have it. With a bit of setup and a Python script, you’ve built a pipeline that eliminates a tedious, manual task. This not only saves you time but also reduces the chance of copy-paste errors and ensures every NDA is filed correctly. In my experience, automating small, repetitive tasks like this is one of the biggest wins in DevOps. It frees up your mental energy for the complex problems that actually require your expertise. Now, go find the next manual process to automate

Darian Vance - Lead Cloud Architect

Darian Vance

Lead Cloud Architect & DevOps Strategist

With over 12 years in system architecture and automation, Darian specializes in simplifying complex cloud infrastructures. An advocate for open-source solutions, he founded TechResolve to provide engineers with actionable, battle-tested troubleshooting guides and robust software alternatives.


🤖 Frequently Asked Questions

âť“ How can I automate NDA generation using Typeform and Google Docs?

Automate NDA generation by creating a Python script that fetches submission data from Typeform, uses a Google Doc as a template with placeholders, and then employs the Google Docs API to replace these placeholders with the Typeform data, saving the final document to Google Drive.

âť“ What are the alternatives to a custom Python script for this automation?

Alternatives include using no-code/low-code integration platforms like Zapier or Make (formerly Integromat) for simpler workflows, or specialized document generation services that might offer more advanced features but less customization than a Python script.

âť“ What are the most common errors encountered during this automation setup?

Common errors include `PermissionDenied` from Google APIs due to unenabled APIs or insufficient service account permissions, exact placeholder mismatches between the Google Doc template and the script, and incorrect Typeform field IDs when parsing submission data.

Leave a Reply

Discover more from TechResolve - SaaS Troubleshooting & Software Alternatives

Subscribe now to keep reading and get access to the full archive.

Continue reading