Skip to main content

How to Integrate Google Sheets Batch API with Salesforce Apex: Step-by-Step Guide

Synchronizing high-volume data between Salesforce and Google Workspace is a common architectural requirement. Instead of making individual HTTP callouts for every single row—which quickly burns through Salesforce governor limits—you can leverage Google Sheets batch APIs to read and write large sets of spreadsheet data in a single roundtrip.

In plain words: A Google batch integration bundles multiple spreadsheet updates or reads into one HTTP request from Salesforce Apex, drastically saving API limits and cutting transaction times.

1. Configuring Google Cloud Console

Before writing Apex callouts, configure your Google Cloud project to allow authorized OAuth 2.0 communication:

Step-by-Step Google Cloud Setup:
  • Step 1: Log in to the Google Cloud Console and create a dedicated project.
  • Step 2: Under APIs & Services > Library, search for and enable the Google Sheets API and Google Drive API.
  • Step 3: Navigate to Credentials > Create Credentials > OAuth client ID.
  • Step 4: Select Web application, and register your Salesforce callback URL under Authorized redirect URIs (e.g., https://yourMyDomain.my.salesforce.com/services/authcallback/GoogleSheets).
  • Step 5: Copy your generated Client ID and Client Secret.

2. Modern Authentication: Named Credentials vs. Custom OAuth

While you can write custom OAuth token exchange logic in Apex, Salesforce's native integration tooling eliminates boilerplate authentication code.

Developer Trap: Never hardcode your client_secret or manage refresh token rotations manually inside an Apex class. Hardcoded secrets create security vulnerabilities and risk breaking if tokens expire mid-transaction. Always store authentication parameters inside Named Credentials with an Auth. Provider.

3. Implementing the Batch Callout in Apex

Google Sheets provides dedicated batch endpoints (such as batchUpdate and values:batchUpdate) that accept clean JSON payloads representing multiple cell operations.

Apex Service: Executing Google Sheets Batch Updates

public with sharing class GoogleSheetsBatchService {

    // Named Credential endpoint (callout:Google_Sheets_NC maps to https://sheets.googleapis.com)
    private static final String ENDPOINT = 'callout:Google_Sheets_NC/v4/spreadsheets/';

    /**
     * Updates multiple cell ranges in a Google Sheet in a single request
     * @param spreadsheetId Target Google Sheet file ID
     * @param sheetTabName Name of sheet tab (e.g., Sheet1)
     */
    public static HttpResponse sendBatchValueUpdate(String spreadsheetId, String sheetTabName) {
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        
        request.setEndpoint(ENDPOINT + EncodingUtil.urlEncode(spreadsheetId, 'UTF-8') + '/values:batchUpdate');
        request.setMethod('POST');
        request.setHeader('Content-Type', 'application/json');

        // Construct Google batch payload
        Map<String, Object> payload = new Map<String, Object>();
        payload.put('valueInputOption', 'USER_ENTERED');

        List<Map<String, Object>> dataList = new List<Map<String, Object>>();
        
        // Range 1: Header / Status Column
        Map<String, Object> updateBlock = new Map<String, Object>();
        updateBlock.put('range', sheetTabName + '!A1:C1');
        updateBlock.put('values', new List<List<String>>{
            new List<String>{'Account Name', 'Industry', 'Sync Status'}
        });
        dataList.add(updateBlock);

        // Range 2: Record Data
        Map<String, Object> dataBlock = new Map<String, Object>();
        dataBlock.put('range', sheetTabName + '!A2:C3');
        dataBlock.put('values', new List<List<String>>{
            new List<String>{'Acme Corp', 'Technology', 'Processed'},
            new List<String>{'Global Media', 'Entertainment', 'Processed'}
        });
        dataList.add(dataBlock);

        payload.put('data', dataList);
        request.setBody(JSON.serialize(payload));

        HttpResponse response = http.send(request);
        
        if (response.getStatusCode() == 200) {
            System.debug('Batch sync successful: ' + response.getBody());
        } else {
            System.debug(LoggingLevel.ERROR, 'Sync error: ' + response.getStatusCode() + ' - ' + response.getBody());
        }

        return response;
    }
}

4. Triggering the Batch Callout from Apex

To execute the sync from an anonymous execution block, Flow action, or Queueable worker, invoke your service method:

// Execute batch update using your target Spreadsheet ID
String targetSpreadsheetId = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms';
GoogleSheetsBatchService.sendBatchValueUpdate(targetSpreadsheetId, 'Sheet1');

5. Architecture & Governor Limit Best Practices

Integration Summary Matrix:
  • Salesforce Callout Limits: Up to 100 HTTP callouts per synchronous transaction; total request timeout maximum of 120 seconds.
  • Google Sheets Quota: Standard limit is 300 read/write requests per minute per project (batching prevents hitting per-minute limits).
  • Asynchronous Execution: Wrap large sync jobs in Queueable Apex or Batch Apex to keep UI transactions responsive.
Core Rule: Use Google Sheets values:batchUpdate with native Salesforce Named Credentials to ensure secure, token-managed data transfers without exceeding governor limits.

Summary

Batching your API payloads transforms sluggish point-to-point data pushes into an enterprise-ready pipeline. By replacing custom token management with Salesforce Named Credentials and grouping updates into JSON batch requests, your Apex integrations stay secure, maintainable, and well within platform limits.