Skip to main content
RapidDev - Software Development Agency
bolt-ai-integrationsBolt Chat + API Route

How to Integrate Bolt.new with Google Docs

Integrate Bolt.new with Google Docs by enabling the Google Docs API in Google Cloud Console, implementing OAuth 2.0 (requires deployment for the redirect URI), then using Next.js API routes to create documents, read document content, and insert text. For simpler read-only display without OAuth, embed documents via iframe. The OAuth callback cannot be tested in Bolt's WebContainer preview — deploy to Netlify or Bolt Cloud first.

What you'll learn

  • How to enable the Google Docs API and configure OAuth 2.0 credentials in Google Cloud Console
  • How to implement the Google OAuth authorization code flow in Next.js API routes
  • How Google Docs API represents document content as a structured tree of elements, not plain text
  • How to create documents, read content, and insert text using the Google Docs REST API
  • How to embed Google Docs via iframe for simple read-only display without OAuth
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate17 min read40 minutesOtherApril 2026RapidDev Engineering Team
TL;DR

Integrate Bolt.new with Google Docs by enabling the Google Docs API in Google Cloud Console, implementing OAuth 2.0 (requires deployment for the redirect URI), then using Next.js API routes to create documents, read document content, and insert text. For simpler read-only display without OAuth, embed documents via iframe. The OAuth callback cannot be tested in Bolt's WebContainer preview — deploy to Netlify or Bolt Cloud first.

Building Google Docs Features into Bolt.new Apps

The Google Docs API gives your Bolt application programmatic access to one of the world's most widely used document platforms. With the API, you can create new documents from templates, read structured document content, perform batch text edits, insert tables and images, and update named ranges — all without users having to download, upload, or copy-paste between systems. This is powerful for automating document generation: contract creation from form data, report generation from database records, proposal drafts populated from CRM data, or meeting notes templates auto-filled from calendar events.

What makes the Google Docs API distinctive is its document model. Unlike a traditional word processor that treats a document as a stream of characters, the Google Docs API represents every document as a structured tree of elements: body, paragraphs, runs, tables, table rows, table cells, images, and named ranges. Reading a document returns a deeply nested JSON object describing every structural element with precise position indices. Editing uses a batch of requests (insert, delete, format) that reference character offsets. This design is powerful but requires some adjustment for developers used to simpler APIs.

For simpler use cases where you only need read-only display of a Google Doc, iframe embedding is far faster to implement than the full API. Any Google Doc with link sharing enabled can be embedded as an iframe in your React components with no OAuth required. The tradeoff is that embedded docs display with Google's formatting — you cannot extract or style the text content. For use cases where you need the actual content (to search, display custom-styled, or process), the full OAuth + API route approach is the right path.

Integration method

Bolt Chat + API Route

Bolt generates the Google Docs integration code — OAuth 2.0 authorization routes, API route handlers for document operations, and React components for document display — through conversation with the AI. Google Docs requires OAuth 2.0, meaning users must authorize your app through Google's consent screen before your app can access their documents. The OAuth callback URL must be a publicly accessible HTTPS address, so the auth flow requires deployment. Document creation and content reads then work through server-side API routes that keep credentials out of the browser.

Prerequisites

  • A Google account with access to Google Cloud Console (console.cloud.google.com)
  • A Google Cloud project with the Google Docs API enabled
  • OAuth 2.0 credentials (Client ID and Client Secret) configured for a web application with your deployed callback URL
  • A deployed Bolt.new app on Netlify or Bolt Cloud (required for the OAuth redirect URI — the auth flow cannot run in the WebContainer preview)
  • A Next.js project in Bolt with the googleapis npm package (prompt: 'Install the googleapis npm package')

Step-by-step guide

1

Enable the Google Docs API and create OAuth 2.0 credentials

Start in the Google Cloud Console. If you do not have a project, create one at console.cloud.google.com by clicking 'New Project'. Give it a name and click Create. With your project selected, navigate to APIs & Services → Library. Search for 'Google Docs API' and click Enable. Also enable the Google Drive API — you will need it to list documents and set sharing permissions on newly created docs. Next, create OAuth 2.0 credentials. Go to APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID. If prompted, configure the OAuth consent screen first: choose 'External' for testing (allows any Google account), fill in the app name, support email, and developer email. On the Scopes page, add https://www.googleapis.com/auth/documents for Docs access and https://www.googleapis.com/auth/drive.file for creating and managing files your app creates. Back in Create Credentials, select 'Web application' as the application type. In Authorized redirect URIs, add your deployed app's callback URL (e.g., https://your-app.netlify.app/api/google/callback) and http://localhost:3000/api/google/callback for local testing. Click Create and copy the Client ID and Client Secret. Store these in your .env.local file. The Google OAuth client secret must only ever appear in server-side code — never in React components or any code that runs in the browser.

Bolt.new Prompt

Set up Google Docs OAuth 2.0 in my Next.js app. Create a lib/google-auth.ts file that exports a getOAuthClient function returning a configured OAuth2 client using GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, and GOOGLE_REDIRECT_URI from environment variables. Create an /api/google/authorize route that generates and redirects to the Google auth URL requesting the docs and drive.file scopes. Create an /api/google/callback route that exchanges the authorization code for tokens, stores them server-side, and redirects to /dashboard on success.

Paste this in Bolt.new chat

lib/google-auth.ts
1// .env.local
2GOOGLE_CLIENT_ID=your_client_id.apps.googleusercontent.com
3GOOGLE_CLIENT_SECRET=your_client_secret
4GOOGLE_REDIRECT_URI=https://your-app.netlify.app/api/google/callback
5
6// lib/google-auth.ts
7import { google } from 'googleapis';
8
9export function getOAuthClient() {
10 return new google.auth.OAuth2(
11 process.env.GOOGLE_CLIENT_ID,
12 process.env.GOOGLE_CLIENT_SECRET,
13 process.env.GOOGLE_REDIRECT_URI
14 );
15}
16
17export function getAuthUrl(): string {
18 const oauth2Client = getOAuthClient();
19 return oauth2Client.generateAuthUrl({
20 access_type: 'offline',
21 scope: [
22 'https://www.googleapis.com/auth/documents',
23 'https://www.googleapis.com/auth/drive.file',
24 ],
25 prompt: 'consent', // Force refresh token on each auth
26 });
27}

Pro tip: Set access_type: 'offline' and prompt: 'consent' when generating the auth URL. This ensures Google returns a refresh token on every authorization, not just the first. Without a refresh token, your app will lose access after the one-hour access token expires.

Expected result: Visiting /api/google/authorize redirects to Google's consent screen showing your app name and the requested Docs/Drive scopes. After authorizing, you are redirected back to your callback URL.

2

Implement the OAuth callback and token storage

After the user authorizes your app on Google's consent screen, Google redirects them to your callback URL with an authorization code as a query parameter. Your callback route must exchange this code for access and refresh tokens by calling Google's token endpoint, then store the tokens so your app can make authenticated Docs API calls. The googleapis library handles the token exchange and management. The OAuth2 client's getToken method exchanges the code for a credentials object containing access_token, refresh_token, expiry_date, and token_type. The refresh_token is particularly important — it allows your server to get new access tokens when the current one expires, without requiring the user to re-authorize. For token storage, the approach depends on your app's complexity. For a single-user tool or prototype, storing tokens in an encrypted HTTP-only cookie is simple and effective. For a multi-user app where different users connect their own Google accounts, store tokens in a database keyed by your user's ID. Never store refresh tokens in environment variables — they must be persisted across server restarts and may need to be updated when refreshed. An important constraint: the OAuth callback is an incoming redirect from Google to your server. Bolt's WebContainer cannot receive these incoming connections. Deploy your app first, register the deployed URL as the redirect URI in Google Cloud Console, and test the full auth flow on the deployed site. During development, you can temporarily use the localhost redirect URI to test the callback locally by running Next.js outside of Bolt.

Bolt.new Prompt

Create the Google OAuth callback handler at /api/google/callback. It receives the authorization code as a query parameter, exchanges it for tokens using the googleapis OAuth2 client, and stores the access_token, refresh_token, and expiry_date in an encrypted server-side cookie called google_tokens. If there's an error query parameter from Google, redirect to /error with a message. After successful token storage, redirect to /dashboard.

Paste this in Bolt.new chat

app/api/google/callback/route.ts
1// app/api/google/callback/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3import { getOAuthClient } from '@/lib/google-auth';
4
5export async function GET(request: NextRequest) {
6 const { searchParams } = new URL(request.url);
7 const code = searchParams.get('code');
8 const error = searchParams.get('error');
9
10 if (error) {
11 return NextResponse.redirect(new URL(`/error?message=${encodeURIComponent(error)}`, request.url));
12 }
13
14 if (!code) {
15 return NextResponse.json({ error: 'Missing authorization code' }, { status: 400 });
16 }
17
18 try {
19 const oauth2Client = getOAuthClient();
20 const { tokens } = await oauth2Client.getToken(code);
21
22 // Store tokens in an HTTP-only cookie
23 // In production, encrypt this or store in a database keyed by user ID
24 const tokenData = JSON.stringify({
25 access_token: tokens.access_token,
26 refresh_token: tokens.refresh_token,
27 expiry_date: tokens.expiry_date,
28 token_type: tokens.token_type,
29 });
30
31 const response = NextResponse.redirect(new URL('/dashboard', request.url));
32 response.cookies.set('google_tokens', tokenData, {
33 httpOnly: true,
34 secure: process.env.NODE_ENV === 'production',
35 sameSite: 'lax',
36 maxAge: 60 * 60 * 24 * 30, // 30 days
37 path: '/',
38 });
39
40 return response;
41 } catch (err) {
42 console.error('Token exchange error:', err);
43 return NextResponse.redirect(new URL('/error?message=auth_failed', request.url));
44 }
45}
46
47// lib/get-google-client.ts — helper to get authenticated client from cookie
48import { cookies } from 'next/headers';
49
50export async function getAuthenticatedClient() {
51 const cookieStore = cookies();
52 const tokenCookie = cookieStore.get('google_tokens');
53
54 if (!tokenCookie) throw new Error('Not authenticated with Google');
55
56 const tokens = JSON.parse(tokenCookie.value);
57 const oauth2Client = getOAuthClient();
58 oauth2Client.setCredentials(tokens);
59 return oauth2Client;
60}

Pro tip: The googleapis library automatically refreshes the access token using the refresh token when it is about to expire, as long as you call oauth2Client.setCredentials(tokens) before making API calls. Update the stored tokens after each API call if the credentials changed (check oauth2Client.credentials after the call).

Expected result: After completing the OAuth flow on the deployed app, the browser redirects to /dashboard and a google_tokens HTTP-only cookie is set. Subsequent API routes can retrieve this cookie to make authenticated Docs API calls.

3

Create and read Google Docs via API routes

With authentication working, you can now create documents and read their content. The Google Docs API is accessed through the googleapis library's google.docs() client. Every API call needs an authenticated OAuth2 client — use the getAuthenticatedClient helper from the previous step. Creating a document is a single API call to documents.create with a title. This creates an empty document and returns the document ID, which is the same string you see in the Google Docs URL (/document/d/{documentId}/edit). Once you have a document ID, you can insert content using batchUpdate, set permissions using the Drive API, and get the document URL. Reading document content uses documents.get, which returns the complete document structure as a nested JSON object. The body.content array contains structural elements: paragraphs, tables, and section breaks. Each paragraph has a paragraphStyle indicating whether it is a heading, normal text, title, or list item. Within paragraphs, textRun elements contain the actual text content and formatting (bold, italic, foreground color, font size). Parsing this structure to display as HTML requires traversing the element tree and mapping structural types to HTML elements. For the most common use case — replacing template placeholders with dynamic values — use batchUpdate with replaceAllText requests. This is far simpler than calculating character offsets. Define placeholder strings in your template document (e.g., {{CLIENT_NAME}}, {{DATE}}, {{PROJECT_SCOPE}}) and batch-replace them all with actual values in a single API call.

Bolt.new Prompt

Create two API routes for Google Docs operations. First: /api/docs/create that accepts a POST with title, and optional templateId (if provided, copy that document using Drive API instead of creating empty). Return the new documentId and editUrl. Second: /api/docs/[docId]/content that reads the document using the Docs API and returns a simplified parsed structure: an array of content blocks each with type (heading1-6, paragraph, listItem, table) and text content. Use the authenticated OAuth client from the cookie.

Paste this in Bolt.new chat

app/api/docs/create/route.ts
1// app/api/docs/create/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3import { google } from 'googleapis';
4import { getAuthenticatedClient } from '@/lib/get-google-client';
5
6export async function POST(request: NextRequest) {
7 try {
8 const { title, templateId } = await request.json() as {
9 title: string;
10 templateId?: string;
11 };
12
13 const auth = await getAuthenticatedClient();
14
15 if (templateId) {
16 // Copy an existing template document
17 const drive = google.drive({ version: 'v3', auth });
18 const copy = await drive.files.copy({
19 fileId: templateId,
20 requestBody: { name: title },
21 });
22 const docId = copy.data.id!;
23 return NextResponse.json({
24 documentId: docId,
25 editUrl: `https://docs.google.com/document/d/${docId}/edit`,
26 viewUrl: `https://docs.google.com/document/d/${docId}/view`,
27 });
28 }
29
30 // Create a new empty document
31 const docs = google.docs({ version: 'v1', auth });
32 const doc = await docs.documents.create({
33 requestBody: { title },
34 });
35
36 const docId = doc.data.documentId!;
37 return NextResponse.json({
38 documentId: docId,
39 editUrl: `https://docs.google.com/document/d/${docId}/edit`,
40 viewUrl: `https://docs.google.com/document/d/${docId}/view`,
41 });
42 } catch (error) {
43 const message = error instanceof Error ? error.message : 'Failed to create document';
44 return NextResponse.json({ error: message }, { status: 500 });
45 }
46}
47
48// Replace template placeholders in a document
49// app/api/docs/[docId]/replace/route.ts
50export async function POST_replace(request: NextRequest, { params }: { params: { docId: string } }) {
51 const { replacements } = await request.json() as {
52 replacements: Record<string, string>;
53 };
54 const auth = await getAuthenticatedClient();
55 const docs = google.docs({ version: 'v1', auth });
56
57 const requests = Object.entries(replacements).map(([placeholder, value]) => ({
58 replaceAllText: {
59 containsText: { text: `{{${placeholder}}}`, matchCase: true },
60 replaceText: value,
61 },
62 }));
63
64 await docs.documents.batchUpdate({
65 documentId: params.docId,
66 requestBody: { requests },
67 });
68
69 return NextResponse.json({ success: true });
70}

Pro tip: When creating documents from templates, copy the template using the Drive API (files.copy) rather than creating a blank document and inserting content. Copying preserves all formatting, styles, headers, footers, and images from the template — you just replace the placeholder text.

Expected result: POST /api/docs/create with { title: 'Q4 Report' } creates a new Google Doc and returns its documentId and edit URL. Opening the edit URL in a browser shows the document in Google Docs.

4

Embed Google Docs for simple read-only display

For use cases where you only need to display a Google Doc within your app without editing or extracting content, iframe embedding is much simpler than the full OAuth integration. Google provides a dedicated embed URL for any document that has been shared with 'Anyone with the link can view' permissions. The embed URL format is: https://docs.google.com/document/d/{documentId}/pub?embedded=true. This renders the document content as clean HTML in an iframe, with Google's styling applied. No API key, no OAuth, no server-side code needed — just a React component with an iframe element. This approach is perfect for: public documentation pages, help articles maintained in Google Docs, terms of service or privacy policy pages, or any content where your team writes in Google Docs and wants to display it live in your app without a CMS migration. When someone updates the doc in Google Docs, the embedded version updates automatically. The limitations are meaningful: you cannot extract or restyle the text content, the iframe shows Google's formatting (which you cannot override), and the embed URL only works for publicly shared documents. Private documents require the OAuth flow. Also note that the embedded Docs view does not render the document's print layout — it renders a web-optimized version that may look slightly different from the editor view. For Bolt's WebContainer preview, iframe embedding works without any configuration — just drop in the embed URL. This is the fastest way to get Google Docs content into a Bolt app during initial prototyping.

Bolt.new Prompt

Create a GoogleDocEmbed React component that accepts a documentId prop and renders the document as an iframe using the Google Docs publish embed URL. Add a loading state shown while the iframe loads. Add an 'Open in Google Docs' button that links to the full document editor URL. Style the iframe to take the full width of its container with a minimum height of 600px. Include a note in the component JSDoc that the document must have 'Anyone with the link can view' sharing enabled.

Paste this in Bolt.new chat

components/GoogleDocEmbed.tsx
1// components/GoogleDocEmbed.tsx
2'use client';
3
4import { useState } from 'react';
5
6interface GoogleDocEmbedProps {
7 /** Google Document ID from the URL: /document/d/{documentId}/edit */
8 documentId: string;
9 /** Minimum height of the embed iframe in pixels. Default: 600 */
10 minHeight?: number;
11 /** Show the 'Open in Google Docs' link. Default: true */
12 showOpenLink?: boolean;
13}
14
15/**
16 * Embeds a Google Doc as an iframe using the published embed URL.
17 * REQUIREMENT: The document must have sharing set to
18 * 'Anyone with the link can view' in Google Docs share settings.
19 */
20export default function GoogleDocEmbed({
21 documentId,
22 minHeight = 600,
23 showOpenLink = true,
24}: GoogleDocEmbedProps) {
25 const [isLoaded, setIsLoaded] = useState(false);
26
27 const embedUrl = `https://docs.google.com/document/d/${documentId}/pub?embedded=true`;
28 const editUrl = `https://docs.google.com/document/d/${documentId}/edit`;
29
30 return (
31 <div className="relative w-full border rounded-lg overflow-hidden">
32 {!isLoaded && (
33 <div
34 className="absolute inset-0 flex items-center justify-center bg-gray-50"
35 style={{ minHeight: `${minHeight}px` }}
36 >
37 <div className="text-gray-400 flex flex-col items-center gap-2">
38 <div className="w-8 h-8 border-2 border-gray-300 border-t-blue-500 rounded-full animate-spin" />
39 <p className="text-sm">Loading document...</p>
40 </div>
41 </div>
42 )}
43 <iframe
44 src={embedUrl}
45 onLoad={() => setIsLoaded(true)}
46 style={{ minHeight: `${minHeight}px`, width: '100%', border: 'none' }}
47 title="Google Document"
48 sandbox="allow-scripts allow-same-origin"
49 />
50 {showOpenLink && (
51 <div className="border-t px-4 py-2 bg-gray-50 flex justify-end">
52 <a
53 href={editUrl}
54 target="_blank"
55 rel="noopener noreferrer"
56 className="text-sm text-blue-600 hover:underline"
57 >
58 Open in Google Docs
59 </a>
60 </div>
61 )}
62 </div>
63 );
64}

Pro tip: If the iframe shows 'Sorry, unable to open the file at this time' or a Google login page, the document's sharing settings are still set to private. In Google Docs, click Share → Change to Anyone with the link → Viewer → Done. The embed URL only works for viewer-accessible documents.

Expected result: The GoogleDocEmbed component renders the Google Doc content inside your Bolt app. The document text, headings, and formatting are visible in the preview, and the 'Open in Google Docs' link opens the document editor in a new tab.

Common use cases

Contract generation from form data

When a user fills out a form in your Bolt app (client name, project scope, pricing), automatically create a Google Doc using a template document, replacing placeholder text with the actual values. The generated document is ready to share with the client for signing.

Bolt.new Prompt

Create a Next.js app that generates Google Docs contracts. When a user submits a form with client name, project description, and total price, call the Google Docs API to create a new document based on a template document ID. Replace the placeholders {{CLIENT_NAME}}, {{PROJECT_DESCRIPTION}}, and {{TOTAL_PRICE}} using the Docs API batchUpdate with replaceAllText requests. Return the new document's URL.

Copy this prompt to try it in Bolt.new

Document content viewer with custom styling

Build a custom document viewer that fetches a Google Doc's content through the API and renders it with your app's own typography and styling, rather than showing it in Google's iframe. This is useful for help centers, knowledge bases, or content platforms where you want consistent branding.

Bolt.new Prompt

Build a Google Docs content viewer that fetches document content using the Google Docs API and renders it as styled React components. Parse the document's body elements — paragraphs, headings (HEADING_1 through HEADING_6), and lists — and render them with Tailwind CSS typography classes. Handle bold, italic, and link formatting within text runs.

Copy this prompt to try it in Bolt.new

Meeting notes auto-population

Before a meeting, automatically create a Google Doc with the meeting agenda, attendee list, and action items sections pre-populated from your app's meeting data. The document link is sent to participants so everyone has a structured notes template ready when the meeting starts.

Bolt.new Prompt

Create an API route that creates a meeting notes Google Doc. Accept meeting title, date, attendees array, and agenda items array as input. Create a new Google Doc with the title as the document title, a formatted attendees list as a table, agenda items as a numbered list, and empty sections for Notes and Action Items. Return the document ID and shareable link.

Copy this prompt to try it in Bolt.new

Troubleshooting

OAuth callback returns 'redirect_uri_mismatch' error from Google

Cause: The redirect URI sent in the authorization request does not exactly match one of the URIs registered in Google Cloud Console. Google performs a strict string comparison including protocol, path, and trailing slashes.

Solution: In Google Cloud Console → APIs & Services → Credentials, open your OAuth 2.0 Client ID and verify the Authorized redirect URIs. Copy one exactly (character for character) into your GOOGLE_REDIRECT_URI environment variable. Common mismatches: http vs https, missing or extra trailing slash, localhost vs 127.0.0.1.

OAuth callback works but subsequent API calls return 401 after one hour

Cause: The access token has expired and the refresh token is not being used to obtain a new one. This happens when access_type was not set to 'offline' in the auth URL, so no refresh token was issued.

Solution: Regenerate the auth URL with access_type: 'offline' and prompt: 'consent'. The user must re-authorize to receive a new refresh token. After that, the googleapis library automatically uses the refresh token when the access token expires, provided you call oauth2Client.setCredentials(tokens) before each API call.

typescript
1// Correct auth URL generation:
2const authUrl = oauth2Client.generateAuthUrl({
3 access_type: 'offline', // Required for refresh token
4 prompt: 'consent', // Forces new refresh token even if already authorized
5 scope: ['https://www.googleapis.com/auth/documents'],
6});

Google OAuth login page appears in the Bolt preview but after authorizing, the page shows a 404 or no redirect happens

Cause: The OAuth callback URL points to your deployed app's domain, but the Bolt preview runs on a different URL. Intuit redirects to the registered domain, which the WebContainer cannot intercept.

Solution: Deploy your app to Netlify or Bolt Cloud first. Register the deployed HTTPS URL (e.g., https://your-app.netlify.app/api/google/callback) in Google Cloud Console. Test the complete auth flow on the deployed site. For local development outside Bolt, add http://localhost:3000/api/google/callback as a second authorized redirect URI.

documents.get returns document structure but extracting text is unclear — nested objects everywhere

Cause: The Google Docs API document model is a deeply nested tree of structural elements, not a flat text string. Each paragraph contains elements, each element may be a textRun with content or an inlineObjectElement for images.

Solution: Use a recursive extraction pattern that traverses the body.content array and extracts text from nested textRun.content fields. The helper function below extracts all text content as a plain string from any Google Docs API response.

typescript
1function extractText(doc: GoogleDocsDocument): string {
2 const lines: string[] = [];
3 for (const element of doc.body?.content ?? []) {
4 if (element.paragraph) {
5 const text = element.paragraph.elements
6 ?.map((el) => el.textRun?.content ?? '')
7 .join('');
8 if (text?.trim()) lines.push(text.replace(/\n$/, ''));
9 }
10 }
11 return lines.join('\n');
12}

Best practices

  • Always deploy before testing the OAuth flow — Google's redirect URI must be a publicly accessible HTTPS URL that the WebContainer cannot provide during development.
  • Store OAuth tokens in a database for multi-user apps, not in cookies or environment variables. Tokens expire and refresh, so they need to be updatable at runtime.
  • Use replaceAllText in batchUpdate for template-based document generation — it is simpler and more reliable than calculating character offsets for insertions.
  • Request only the scopes your app needs: use https://www.googleapis.com/auth/documents for Docs access and https://www.googleapis.com/auth/drive.file to only access files your app creates, rather than the broader drive scope.
  • For read-only public content display, prefer iframe embedding over the API — it requires no authentication setup and automatically reflects document updates.
  • Cache read API responses when document content does not change frequently. The Docs API has per-user rate limits; excessive reads on the same documents can trigger 429 errors.
  • Never expose your Google Client Secret or OAuth tokens in client-side React code. All Google API calls must go through server-side Next.js API routes.

Alternatives

Frequently asked questions

Can I test the Google Docs API in Bolt's preview without deploying?

Partially. Outbound API calls to read and create documents work fine once you have a valid access token. However, the OAuth flow — where Google redirects back to your app after authorization — requires a deployed URL that the WebContainer cannot provide. Deploy first to complete auth, obtain tokens, then you can use those tokens to test most API operations in development.

Does Bolt.new have a native Google Docs integration?

No. Google Docs is not one of Bolt's native connectors. You implement the integration using Next.js API routes and the googleapis npm package. Bolt's AI generates most of the boilerplate code when prompted, but you need to set up credentials in Google Cloud Console manually.

How do I allow users to connect their own Google account rather than using my service account?

The OAuth 2.0 flow described in this guide is exactly the mechanism for user-specific access. Each user who authorizes your app receives their own tokens, stored in your database associated with their user ID. When they make requests, use their stored tokens to call the Docs API on their behalf. This is the standard pattern for apps that read or edit documents in users' own Google Drive.

What is the Google Docs API rate limit?

The Google Docs API allows 300 read requests per minute and 60 write requests per minute per user. For a dashboard accessed by many users simultaneously, each user has their own quota so the total throughput scales. If you hit rate limits (429 error), implement exponential backoff retry logic. Caching frequently-read documents is the most effective way to stay within limits.

Can I insert images into Google Docs through the API?

Yes, using the insertInlineImage request in batchUpdate. You provide a URI pointing to a publicly accessible image (Google fetches it from the URL you provide) and the insertion location index within the document. The image must be accessible over HTTPS without authentication — you cannot reference private S3 or local file system paths.

RapidDev

Talk to an Expert

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

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

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.