Skip to main content
RapidDev - Software Development Agency
bubble-integrationsBubble API Connector

Google Docs

Connect Bubble to Google Docs using two separate API Connector groups — one for the Google Docs API and one for the Google Drive API. The primary use case is document generation: a Bubble form triggers a Backend Workflow that duplicates a template Doc via Drive, then fills placeholders using the Docs batchUpdate endpoint. Both API groups use a service account Bearer token marked Private.

What you'll learn

  • How to set up a Google Cloud service account and enable the Docs and Drive APIs
  • How to configure two separate API Connector groups with different base URLs
  • How to duplicate a Google Doc template via the Drive API copy endpoint
  • How to fill placeholder text in a Doc using the Docs batchUpdate with replaceAllText
  • How to wire a Bubble Backend Workflow to chain the copy and fill steps in sequence
  • Common mistakes that cause silent 200 OK responses that skip placeholder replacements
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Advanced14 min read90–120 minutesProductivityLast updated July 2026RapidDev Engineering Team
TL;DR

Connect Bubble to Google Docs using two separate API Connector groups — one for the Google Docs API and one for the Google Drive API. The primary use case is document generation: a Bubble form triggers a Backend Workflow that duplicates a template Doc via Drive, then fills placeholders using the Docs batchUpdate endpoint. Both API groups use a service account Bearer token marked Private.

Quick facts about this guide
FactValue
ToolGoogle Docs
CategoryProductivity
MethodBubble API Connector
DifficultyAdvanced
Time required90–120 minutes
Last updatedJuly 2026

Automated document generation: the most valuable Bubble + Google Docs pattern

Virtually every Bubble + Google Docs integration follows the same template-replacement pattern: create a well-formatted Google Doc with placeholder text like {{client_name}}, {{project_title}}, {{date}}, then from Bubble, (1) duplicate the template via the Drive API to create a fresh document, (2) call the Docs batchUpdate endpoint with replaceAllText operations to swap every placeholder with real data. The result is a fully formatted document with a shareable Google Drive URL that Bubble can display or email to the user. Two key technical requirements make this pattern Bubble-specific: the Drive and Docs APIs have different base URLs and must be separate API Connector groups, and the sequential two-call pattern (copy then fill) requires a Bubble Backend Workflow for reliable execution — available on paid Bubble plans only.

Integration method

Bubble API Connector

Two separate Bubble API Connector groups: one for the Google Docs REST API v1 and one for the Google Drive REST API v3, both authenticated via a service account Bearer token marked Private.

Prerequisites

  • A Google account and access to Google Cloud Console (console.cloud.google.com) to create a project and service account
  • A template Google Doc with placeholder text in the format {{placeholder_name}} — avoid special characters or smart quotes in placeholders
  • A paid Bubble plan (Starter or above) — the two-call sequential pattern requires Backend Workflows, which are not available on the Free plan
  • The API Connector plugin installed in your Bubble app (Plugins tab → Add plugins → search 'API Connector' by Bubble)

Step-by-step guide

1

Enable the Google Docs and Drive APIs and create a service account

Open Google Cloud Console at console.cloud.google.com. Create a new project (or use an existing one). In the left menu, go to 'APIs & Services' → 'Library'. Search for 'Google Docs API' and click Enable. Then search for 'Google Drive API' and click Enable — you need both. Next, go to 'APIs & Services' → 'Credentials'. Click 'Create Credentials' → 'Service Account'. Give it a name like 'Bubble Docs Integration'. Click Create and Continue. For the role, select 'Editor' at the project level, or leave the role blank if you plan to share files individually (recommended for tighter security). Click Done. Find the service account in the list, click on it, go to the Keys tab, click 'Add Key' → 'Create new key' → select JSON → Create. A JSON file downloads to your computer — save it securely. The service account has an email address that looks like something@yourproject.iam.gserviceaccount.com — copy this email, you will need it in the next step.

Pro tip: The downloaded JSON key file contains the service account credentials. Store it securely and never commit it to version control. You will extract the private key and client_email fields from this file.

Expected result: Both Google Docs API and Google Drive API show as Enabled in your Cloud Console. You have a service account JSON key file and the service account email address.

2

Share the template Doc with the service account and get the template ID

Open the Google Doc template you want to use in your browser. Click 'Share' in the top right corner. In the sharing dialog, paste the service account email address (something@yourproject.iam.gserviceaccount.com) into the 'Add people and groups' field. Set the permission level to 'Editor' — Viewer is not sufficient because the service account needs to copy the file. Click 'Send' or 'Share'. Now look at the URL in your browser while viewing the template — it looks like: https://docs.google.com/document/d/DOCUMENT_ID/edit. Copy the DOCUMENT_ID (the long string between /d/ and /edit). This is your template document ID that you will use in the Drive API copy call. Also note the Google Drive folder where you want generated documents to be saved — share that folder with the service account email as well (Editor permission) if you want organized file management.

Pro tip: A common issue: if you forget to share the template with the service account, the Drive API copy call returns 404 'File not found' — even though you can see the file when logged in as yourself.

Expected result: The template Google Doc is shared with the service account email. You have the template document ID copied. When the service account copies the file, it will have Editor access to the original.

3

Configure two separate API Connector groups for Drive and Docs

In Bubble, open Plugins → API Connector. You need two separate API groups because the Google Drive and Google Docs APIs have different base URLs — if you mix them under one base URL, all calls fail. Click 'Add another API'. Name the first group 'Google Drive API'. Add one shared header: key = Authorization, value = Bearer YOUR_ACCESS_TOKEN — mark it Private. Note: obtaining the access_token from a service account normally requires exchanging the JSON key for a short-lived token via Google's OAuth2 token endpoint. For simplicity in Bubble, the most practical approach is to use a service account with domain-wide delegation OR to generate a long-lived access token using a script or service like Token Service, then store it in Bubble as an App Data value and reference it in the header. See the troubleshooting section for the service account token flow. Click 'Add another API' again. Name the second group 'Google Docs API'. Add the same Authorization header (Bearer token, Private). Leave the base URL at the group level empty for both — you will enter full URLs in each call.

api-connector-groups-config.json
1Google Drive API group:
2 Shared header: Authorization: Bearer <your_access_token> [Private]
3 Base URL: (leave empty)
4
5Google Docs API group:
6 Shared header: Authorization: Bearer <your_access_token> [Private]
7 Base URL: (leave empty)
8
9Note: Both groups use the same token but different API endpoint base URLs in each call.

Pro tip: Service account access tokens expire after 1 hour. For a production Bubble app, implement a Backend Workflow that refreshes the token using the JWT grant flow and stores the new token in Bubble's App Data — then reference App Data's token in the shared header value.

Expected result: Two separate API Connector groups exist in your Bubble app: 'Google Drive API' and 'Google Docs API', each with an Authorization header marked Private.

4

Add the Drive copy call to duplicate the template

In the 'Google Drive API' group, click 'Add another call'. Name it 'Copy Template'. Set Method to POST. Set the URL to: https://www.googleapis.com/drive/v3/files/YOUR_TEMPLATE_ID/copy — replace YOUR_TEMPLATE_ID with the document ID you copied in Step 2. Set 'Use as' to 'Action' since this call is triggered from a workflow. In the Body section, check 'Send arbitrary data' and provide the JSON body shown below — this sets the name of the newly created document. To make the document name dynamic (e.g., include the client's name), define a parameter in the body with a placeholder like <new_doc_name> that Bubble will prompt you to fill when using this call in a workflow. Click 'Initialize call'. Bubble will make the actual API call and return the new file's metadata including its id — this id is what you will pass to the Docs batchUpdate call in the next step. After initialization, confirm that the 'id' field appears in Bubble's detected response fields.

drive-copy-template.json
1POST https://www.googleapis.com/drive/v3/files/YOUR_TEMPLATE_ID/copy
2
3Headers (shared):
4 Authorization: Bearer <token> [Private]
5
6Body:
7{
8 "name": "<dynamic: new_doc_name>"
9}

Pro tip: After the copy call initializes, verify that Bubble detected 'id' in the response. This is the new document's ID that you will pipe into the Docs batchUpdate call. Without this field being detected, you cannot chain the calls.

Expected result: The Initialize call succeeds and Bubble detects an 'id' field in the response (the new document's Google Drive file ID). A duplicate of the template appears in your Google Drive.

5

Add the Docs batchUpdate call for placeholder replacement

In the 'Google Docs API' group, click 'Add another call'. Name it 'Fill Placeholders'. Set Method to POST. Set the URL to: https://docs.googleapis.com/v1/documents/DOCUMENT_ID:batchUpdate — where DOCUMENT_ID will be a dynamic parameter filled from the previous step's result. In the API Connector, configure DOCUMENT_ID as a parameter by writing it as <new_doc_id> in the URL path so Bubble prompts you to fill it in the workflow. Set 'Use as' to 'Action'. In the Body, check 'Send arbitrary data' and provide the replaceAllText request array. Each placeholder replacement is one object in the requests array. Add dynamic parameters for each value you want to fill in (e.g., <client_name>, <project_title>). Initialize the call with real example values to confirm it works before wiring into the workflow. Note: replaceAllText is case-sensitive and requires the placeholder text to match exactly — including the double curly braces if you used them in the template.

docs-batch-update.json
1POST https://docs.googleapis.com/v1/documents/<new_doc_id>:batchUpdate
2
3Headers (shared):
4 Authorization: Bearer <token> [Private]
5
6Body:
7{
8 "requests": [
9 {
10 "replaceAllText": {
11 "containsText": {
12 "text": "{{client_name}}",
13 "matchCase": true
14 },
15 "replaceText": "<dynamic: client_name>"
16 }
17 },
18 {
19 "replaceAllText": {
20 "containsText": {
21 "text": "{{project_title}}",
22 "matchCase": true
23 },
24 "replaceText": "<dynamic: project_title>"
25 }
26 },
27 {
28 "replaceAllText": {
29 "containsText": {
30 "text": "{{date}}",
31 "matchCase": true
32 },
33 "replaceText": "<dynamic: document_date>"
34 }
35 }
36 ]
37}

Pro tip: The batchUpdate returns 200 OK even if no replacements were made — it does not tell you how many replacements occurred. If you open the generated document and see unfilled placeholders, check the tip in Troubleshooting about smart quotes and split textRun elements.

Expected result: The Initialize call succeeds and returns 200. When you open the test document in Google Drive, you see the placeholder values replaced with the example data you provided during initialization.

6

Wire a Backend Workflow to chain copy and fill in sequence

In Bubble, go to the Backend Workflows section (Settings → API → enable 'This app exposes a Workflow API', then open the Backend Workflows tab). Create a new API Workflow named something like 'Generate Document'. Add the parameters you need: client_name (text), project_title (text), date (date), and any other fields your template uses. In the workflow steps: Step 1 — Plugins → Google Drive API → Copy Template, set the new_doc_name parameter to a dynamic value combining your inputs (e.g., 'Proposal - ' + client_name). Step 2 — Plugins → Google Docs API → Fill Placeholders, set new_doc_id = Result of Step 1's id, and map client_name, project_title, and date from the workflow parameters. Step 3 — Make changes to a Thing: create or update a Bubble data type record to store the new document URL (construct it as 'https://docs.google.com/document/d/' + Step 1's id). To trigger this Backend Workflow from a regular page workflow, add a 'Schedule API Workflow' step in your form submit button's workflow and pass the form field values as the parameters. Backend Workflows on paid Bubble plans run reliably in sequence, ensuring the copy completes before the fill starts. RapidDev's team has built document generation flows like this across dozens of Bubble apps — book a free scoping call at rapidevelopers.com/contact if you get stuck.

backend-workflow-chain.txt
1Backend Workflow: Generate Document
2Parameters: client_name (text), project_title (text), document_date (date)
3
4Step 1: [API] Copy Template
5 new_doc_name: "Proposal - " + client_name
6 returns: id (new document ID)
7
8Step 2: [API] Fill Placeholders
9 new_doc_id: Result of Step 1's id
10 client_name: This workflow's client_name
11 project_title: This workflow's project_title
12 document_date: This workflow's document_date :formatted as MM/DD/YYYY
13
14Step 3: Make changes to Thing (Order)
15 document_url: "https://docs.google.com/document/d/" + Step 1's id

Pro tip: Backend Workflows require a paid Bubble plan. If you try to build this as a standard page workflow with two chained API calls, the second call may fire before the first completes — resulting in a 'File not found' error because the copied document doesn't exist yet.

Expected result: Clicking the form submit button triggers the Backend Workflow, which creates a new Google Doc with all placeholders filled and stores the document URL in Bubble's database. The whole process completes within a few seconds.

Common use cases

Proposal and contract generation

A Bubble form collects project details, pricing, and client information. On submit, a Backend Workflow duplicates the proposal template, fills in the client's data via replaceAllText, and stores the new Google Doc URL in Bubble's database. The client receives an email with the shareable link.

Bubble Prompt

When the 'Generate Proposal' button is clicked, duplicate the proposal template Doc, replace {{client_name}}, {{project_budget}}, and {{delivery_date}} with the form values, then display the new Google Doc link in a popup.

Copy this prompt to try it in Bubble

Invoice and receipt creation

After a Stripe payment is processed, a Bubble Backend Workflow creates a Google Doc invoice populated with the customer name, line items, and payment amount. The invoice URL is saved to the customer's record and sent via email.

Bubble Prompt

After a successful payment, generate a PDF-ready Google Doc invoice with the customer's billing details and payment amount, and store the document URL in the user's order record.

Copy this prompt to try it in Bubble

Personalized onboarding documents

New users fill out an onboarding form in Bubble. The workflow generates a personalized welcome packet, project brief, or terms document from a template, filling in the user's name, company, and selected service options.

Bubble Prompt

When a new client completes onboarding, create a personalized project brief Google Doc with their company name, selected services, and assigned team member, then share it with their email address.

Copy this prompt to try it in Bubble

Troubleshooting

Drive API copy call returns 404 'File not found'

Cause: The service account email has not been granted access to the template document. Google Drive requires explicit sharing — the service account cannot see files you own unless you share them.

Solution: Open the template Google Doc, click Share, add the service account email (format: name@project.iam.gserviceaccount.com), set permission to Editor, and click Share. Then retry the copy call.

batchUpdate returns 200 OK but placeholders in the document remain unfilled

Cause: The most common cause is that the placeholder text in the template was auto-corrected to smart quotes (curly quotes like {{client_name}} instead of {{client_name}}), or that Google Docs internally split the placeholder across multiple textRun elements during editing. The API's replaceAllText performs exact string matching and cannot find placeholders that are typographically different from what it was given.

Solution: Open the template Google Doc, select the placeholder text, delete it, and retype it manually without using autocorrect. Alternatively, turn off smart quotes in Tools → Preferences → uncheck 'Use smart quotes'. Then check the template by pasting it into a plain text editor to confirm the characters are standard ASCII. If the placeholder was split across runs (happens when you edit part of it), delete and retype the entire placeholder in one action.

'There was an issue setting up your call' when initializing the Drive or Docs API call

Cause: The access token is expired or invalid. Service account tokens are short-lived (1 hour) and must be refreshed via Google's OAuth2 token endpoint using a JWT assertion.

Solution: For testing, generate a fresh access token using the Google OAuth Playground (oauth2.googleapis.com/tokeninfo) or a curl command with your service account JSON. For production, implement a Bubble Backend Workflow that periodically calls Google's token endpoint and updates the token stored in Bubble's App Data. Reference the App Data value in the API Connector shared header.

The Docs API call fails with 'Request had insufficient authentication scopes'

Cause: The service account access token was generated with insufficient OAuth2 scopes. The Docs API requires the scope https://www.googleapis.com/auth/documents, and the Drive API requires https://www.googleapis.com/auth/drive.

Solution: When generating the access token, include both scopes in the JWT claim: 'scope': 'https://www.googleapis.com/auth/documents https://www.googleapis.com/auth/drive'. Regenerate the token and update it in your Bubble API Connector headers.

The second API call in the workflow fires before the first completes

Cause: Standard Bubble page workflows do not wait for API calls to finish before moving to the next step. Chaining a Drive copy call and a Docs batchUpdate call in a standard workflow creates a race condition.

Solution: Move the two-call sequence into a Bubble Backend Workflow (requires paid plan). Backend Workflows execute steps sequentially and guarantee that Step 1 completes (and its result is available) before Step 2 begins.

Best practices

  • Mark the Authorization header as Private in both API Connector groups — this keeps the service account token completely server-side and never exposes it in the browser's network requests.
  • Add Privacy rules in Bubble's Data tab for any Things that store generated document URLs — without Privacy rules, any logged-in Bubble user can query all document records via Bubble's API.
  • Type placeholder text manually in your Google Docs template and disable smart quotes (Tools → Preferences) to prevent the auto-correction that silently breaks replaceAllText matches.
  • Use a Backend Workflow for the two-call copy + fill sequence — it guarantees sequential execution and provides reliable error handling via Bubble's Logs tab.
  • Store the generated Google Doc URL in a Bubble data type record immediately after creation. This gives you a link to share or display, and a record to reference if you need to update the document later.
  • Implement periodic token refresh for production apps: Google service account access tokens expire after 1 hour. A Bubble Backend Workflow scheduled every 50 minutes can call Google's token endpoint and update the token in App Data.
  • Test your template with all placeholder types (text, dates, numbers) before wiring it into Bubble — the batchUpdate succeeds silently even if no replacements match, making it hard to detect configuration errors without visual inspection.

Alternatives

Frequently asked questions

Can I use a regular Google account instead of a service account?

Technically yes, using OAuth 2.0 user authorization, but it is significantly more complex in Bubble. OAuth requires a redirect flow to obtain a refresh token, and Bubble does not have a native OAuth callback handler. A service account with direct API access is much simpler to set up and maintain in Bubble — it is the recommended approach for Bubble apps that generate documents on behalf of the app owner rather than on behalf of individual users.

Why do I need two separate API Connector groups?

Because the Google Drive API and Google Docs API have different base URLs — Drive uses googleapis.com/drive/v3 and Docs uses docs.googleapis.com/v1. Bubble's API Connector applies the base URL to all calls in a group, so mixing them under one base URL causes all calls to go to the wrong endpoint. Separating them into two groups ensures each call reaches the correct API.

How do I get the final document URL to display or share with the user?

After the Backend Workflow's copy step completes, the Drive API returns the new file's id. Construct the Google Docs URL as: https://docs.google.com/document/d/ + the id value. You can store this in a Bubble data field and display it as a link, or use a 'Send email' step to email the link to the user. The document inherits the sharing settings of the destination Drive folder — if the folder is private, the generated document is private and requires sign-in to view.

Can I generate a PDF instead of a Google Doc?

Yes. After generating the Doc with filled placeholders, add a third call to the Drive API: GET https://www.googleapis.com/drive/v3/files/DOCUMENT_ID/export?mimeType=application/pdf. This returns the PDF binary. However, handling binary data in Bubble is complex — you would need to store the export URL and let users click it directly, which prompts a browser download, rather than processing the PDF within Bubble.

What happens if a placeholder in my template doesn't get replaced?

The batchUpdate endpoint returns HTTP 200 OK regardless of whether replacements were made — it does not report zero-match replacements as errors. If you see unfilled placeholders in the generated document, check: (1) the placeholder text in the template uses standard ASCII quotes (not smart/curly quotes), (2) the placeholder was not accidentally split across multiple text runs in Google Docs internal formatting, (3) the matchCase setting in replaceAllText matches the actual capitalization of your placeholder.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire Bubble integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.