Updated Oct 2026

Export Google reviews to Google Sheets: three ways that actually work

Google Business Profile has no review export and no sync to Sheets. What works is the API, and there are three ways to use it: an Apps Script against the Business Profile API (every review of your own listings, free, after Google’s approval), the Places API (5 public reviews of any place, no approval), or a unified reviews API that also brings the other platforms into the same sheet. Pick by what you need; the scripts are below, ready to paste.

Option 1: Apps Script with the Business Profile API (all your reviews)

Prerequisites: you are an owner or manager of the listing, and the Apps Script is linked to a Google Cloud project with the Business Profile APIs enabled and API access approved. Until approval the quota is 0 and the script will fail with a 429.

  1. In the sheet: Extensions → Apps Script. Replace the code with the script below.
  2. Project settings → Show manifest, then in appsscript.json add "oauthScopes": ["https://www.googleapis.com/auth/business.manage", "https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/script.external_request"].
  3. Project settings → Change project → paste the Cloud project number that has the approval.
  4. Run importReviews once (it asks for authorisation), then Triggers → Add trigger, time-driven, daily.
Node.js
const ACCOUNT = "accounts/1234567890";      // from GET https://mybusinessaccountmanagement.googleapis.com/v1/accounts
const LOCATION = "locations/9876543210";    // from GET …/v1/{account}/locations?readMask=name,title
const STARS = { ONE: 1, TWO: 2, THREE: 3, FOUR: 4, FIVE: 5 };

function importReviews() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Reviews") || SpreadsheetApp.getActiveSpreadsheet().insertSheet("Reviews");
  if (sheet.getLastRow() === 0) sheet.appendRow(["id", "date", "rating", "author", "text", "reply", "updated"]);
  const known = new Set(sheet.getRange(2, 1, Math.max(sheet.getLastRow() - 1, 1), 1).getValues().flat());
  const headers = { Authorization: "Bearer " + ScriptApp.getOAuthToken() };
  let pageToken = "", rows = [];
  do {
    const url = `https://mybusiness.googleapis.com/v4/${ACCOUNT}/${LOCATION}/reviews?pageSize=50` + (pageToken ? `&pageToken=${pageToken}` : "");
    const res = UrlFetchApp.fetch(url, { headers, muteHttpExceptions: true });
    if (res.getResponseCode() !== 200) throw new Error(res.getContentText());
    const data = JSON.parse(res.getContentText());
    for (const r of data.reviews || []) {
      if (known.has(r.reviewId)) continue;
      rows.push([r.reviewId, r.createTime, STARS[r.starRating], r.reviewer.displayName, r.comment || "", (r.reviewReply || {}).comment || "", r.updateTime]);
    }
    pageToken = data.nextPageToken || "";
  } while (pageToken);
  if (rows.length) sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, rows[0].length).setValues(rows);
}

Multiple locations: list them with the Business Information API and loop. Ratings arrive as the enum ONE…FIVE; the script maps them. Edited reviews are not updated by this version (it skips known ids); compare updateTime if you need that.

Option 2: Places API (5 reviews, any place, no approval)

If a snapshot of the top 5 public reviews is enough, a Places API key (how to get one) and this script work in a minute, with no OAuth and no approval:

Node.js
const PLACE_ID = "ChIJN1t_tDeuEmsRUsoyG83frY4";
const KEY = PropertiesService.getScriptProperties().getProperty("GOOGLE_MAPS_API_KEY");

function importTop5() {
  const res = UrlFetchApp.fetch(`https://places.googleapis.com/v1/places/${PLACE_ID}`, { headers: { "X-Goog-Api-Key": KEY, "X-Goog-FieldMask": "displayName,rating,userRatingCount,reviews" } });
  const p = JSON.parse(res.getContentText());
  const sheet = SpreadsheetApp.getActiveSheet();
  sheet.clear();
  sheet.appendRow([p.displayName.text, p.rating, p.userRatingCount]);
  for (const r of p.reviews || []) sheet.appendRow([r.publishTime, r.rating, r.authorAttribution.displayName, (r.text || {}).text || ""]);
}

Store the key in Script properties, not in the code. You get at most 5 reviews, no replies, billed per request.

Option 3: one key, Google plus Tripadvisor, App Store, Trustpilot and more

Prisma reads the reviews of the locations you connect, on 50+ platforms, and returns them in one JSON, so one script fills one sheet with every platform. Google locations connect with a Google sign-in through Prisma’s own project; other platforms with a key or the listing URL.

Node.js
const PRISMA_KEY = PropertiesService.getScriptProperties().getProperty("PRISMA_API_KEY");

function importAllPlatforms() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName("Reviews") || ss.insertSheet("Reviews");
  if (sheet.getLastRow() === 0) sheet.appendRow(["id", "platform", "location", "date", "rating", "author", "text", "reply", "url"]);
  const known = new Set(sheet.getRange(2, 1, Math.max(sheet.getLastRow() - 1, 1), 1).getValues().flat());
  const headers = { Authorization: "Bearer " + PRISMA_KEY };
  const locs = {};
  for (const l of JSON.parse(UrlFetchApp.fetch("https://api.prismareviews.com/v1/locations", { headers }).getContentText()).data) locs[l.id] = l.name;
  let cursor = "", rows = [];
  do {
    const res = UrlFetchApp.fetch("https://api.prismareviews.com/v1/reviews?limit=100" + (cursor ? "&cursor=" + cursor : ""), { headers });
    const data = JSON.parse(res.getContentText());
    for (const r of data.data) {
      if (known.has(r.id)) continue;
      rows.push([r.id, r.platform, locs[r.location_id] || r.location_id, r.created_at, r.rating, r.author || "", r.text || "", r.reply ? r.reply.text : "", r.url || ""]);
    }
    cursor = data.next_cursor || "";
  } while (cursor);
  if (rows.length) sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, rows[0].length).setValues(rows);
}

Schedule it daily, or skip polling and let Prisma push: register a webhook with POST /v1/webhooks pointing at a Zapier or Make hook that appends the row (setup), or use the n8n node. A test key (pk_test_…) fills the sheet with sample reviews from every platform, so you can build the sheet before connecting anything.

What’s true today: Prisma reads Google reviews from the Google Maps listing (public, read-only) while Google reviews Prisma’s Business Profile API application. For the full history of your own Google listing right now, Option 1 is the route, if your project is approved.

Which option

You wantUse
Every review of listings you own, Google only, free, and you have (or can get) API approvalOption 1
A quick top-5 of any place, no approvalOption 2
Google plus the other platforms in one sheet, no approval on your sideOption 3

FAQ

Can I export all Google reviews to a spreadsheet for free?

Yes, if you own the listing and have Business Profile API access approved for a Cloud project: the Apps Script in this guide pulls every review with no cost. Without that approval, the Places API gives only 5 reviews, and Google Business Profile’s own export is manual.

Does Google Business Profile have a built-in review export?

No automatic export. You can read reviews in the Business Profile dashboard and copy them, but there is no CSV download and no sync; the API is the only automated route.

Can the same sheet hold Tripadvisor, App Store or Trustpilot reviews?

With a unified API, yes: the third script in this guide writes every platform’s reviews in the same columns, because they come back in one JSON shape.

Every platform's reviews in one sheet.

Get API key

2 locations free. Test keys fill the sheet with sample reviews today.

Get your API key in a minute

Free Spark plan: 2 locations, no card. Test keys return sample data on all 58 platforms, so you can build before connecting a real one.