HOW-TO · DATA SYNC

Put a Salesforce report into a Google Sheet automatically.

By Chris Davidson, founder of yForest · Updated September 26, 2026

Exporting the same Salesforce report every Monday gets old. A scheduled sync does it without you.

Start 14-day free trial Download on theMac App Store

No credit card. 14 days. Cancel in one click.

macOS 15+ · Apple Silicon native · 14-day free trial · No credit card

Quick answer: Add Salesforce and Google Sheets connections, then build a Data Sync: write a SOQL query as the source, map its columns to a sheet tab, and choose Insert, Update or Upsert. Schedule it so the sheet stays current without a manual export. Pipelines tier.

The report that has to live in a spreadsheet

Salesforce reports are fine inside Salesforce. The trouble starts when someone who doesn't have a Salesforce license, a distributor, a board member, an ops manager in another tool, needs the numbers in a spreadsheet they can open without logging in anywhere. The usual fix is exporting a report by hand every Monday. This replaces that with a sync that writes straight into a Google Sheet on whatever schedule you set.

Before you start

Steps

  1. Add your Salesforce connection under Databases if you haven't already.
  2. Add the target Google Sheet as a connection: click the + next to Databases and pick Google Sheets, then authorize and pick the sheet and tab.
  3. Open Pipelines → Build and click New Sync.
  4. On the left, pick Salesforce as your source and write the SOQL query for the rows you want.
  5. On the right, pick the Google Sheets connection and the target tab.
  6. Drag columns across, or click AI Map to pair them by name.
  7. Pick a MODE: Insert to append rows, Update or Upsert to refresh existing ones.
  8. Click Dry Run, check the preview, then Save and schedule it, or run it now.

A worked example

A sales ops manager needs this month's open opportunities refreshed in a shared sheet every morning, without opening Salesforce:

SELECT Id, Name, Amount, StageName, CloseDate, Owner.Name
FROM Opportunity
WHERE CloseDate = THIS_MONTH
AND IsClosed = false;

Map Name, Amount, StageName, CloseDate and Owner.Name to columns in a tab named Open Pipeline. Set MODE to Upsert with MATCH ON set to Id, so a deal that moves from Negotiation to Closed Won updates its existing row in the sheet instead of adding a second one underneath it.

Check it worked

Dry Run shows the rows before anything writes to the sheet. After a scheduled run, spot-check a few opportunity IDs against Salesforce directly, and confirm the sheet's row count is climbing or holding steady the way you'd expect, not silently duplicating on every run.

Troubleshooting

If you seeFix
Rows duplicating each runSwitch MODE from Insert to Upsert with Id as the MATCH ON field.
SOQL syntax errorSalesforce SOQL isn't quite standard SQL; check field API names and relationship syntax like Owner.Name rather than a plain join.
Google Sheets authorization expiredRe-authorize the Google Sheets connection under Databases; OAuth tokens expire periodically.

What this doesn't do

This isn't a live, two-way link. Edits made directly in the Google Sheet don't flow back into Salesforce, and the sheet only reflects Salesforce as of the last sync run. For a genuinely bidirectional workflow you'd need a different tool built around continuous sync in both directions; for a scheduled read-only refresh into a spreadsheet people already live in, this covers the actual use case cleanly.

A second worked example: a renewals list for customer success

A CS team wants a running list of accounts renewing in the next 60 days, refreshed every morning without anyone touching Salesforce:

SELECT Id, Account.Name, Amount, CloseDate, Owner.Name
FROM Opportunity
WHERE CloseDate <= NEXT_N_DAYS:60
AND StageName = 'Closed Won'
AND Contract_End_Date__c <= NEXT_N_DAYS:60;

This one's simpler than the pipeline example: no owner relationship field, no stage filter, just a date window. Map it to a Renewals tab, set MODE to Upsert with MATCH ON set to Id, and schedule it for 6 AM so the list is current before the team's first stand-up.

Formatting numbers and dates once they land in the sheet

Google Sheets applies its own default formatting to incoming values, which sometimes means a currency field like Amount arrives as a plain number without a dollar sign, or a date arrives as a raw timestamp rather than a readable date. Set the column format once directly in the sheet, on the header row or the whole column, rather than in QueryFlow; formatting is a spreadsheet concern, and it sticks across future syncs since the sync only writes values into existing cells.

Large exports and Salesforce API limits

Salesforce enforces API call and row limits per org, and a SOQL query pulling tens of thousands of records at once can bump into them, particularly on an org already running other integrations against the same limits. For a report in the low thousands of rows, this rarely matters. For anything larger, narrowing the query's date range or filtering more aggressively keeps each run well under the ceiling instead of risking a failed sync during your busiest reporting week.

QueryFlow Studio $9.99/mo · $99/yr
QueryFlow Pipelines $29.99/mo · $199.99/yr

Frequently asked

Do edits in the Google Sheet flow back to Salesforce?

No, this is one-way, Salesforce to the sheet. Editing the sheet directly doesn't change Salesforce.

Can I use an existing Salesforce report instead of writing SOQL?

The source is a SOQL query; you can usually rebuild an existing report's filters as a query fairly directly.

What if the sheet already has rows in it?

Use Upsert with a MATCH ON key like the record Id so the sync updates existing rows instead of duplicating them.

Can I sync to a specific tab in a multi-tab spreadsheet?

Yes, pick the exact tab when you set up the Google Sheets connection.

Stop exporting the same report by hand.

14-day free trial, no card. Set it up once, let it run every morning.

Start 14-day free trial

No credit card. 14 days. Cancel in one click.