← Guides

Export reviews to a spreadsheet

A one-off CSV for Excel, or a Google Sheet that refreshes itself.

New here?

Repuso collects customer reviews from Google, TripAdvisor, Trustpilot, the App Store and 50+ other platforms, and serves them through one REST API in a single JSON schema - with rating history, sentiment, AI summaries and webhooks on new reviews. You point it at a public profile; it keeps that profile current and tells you when something changes.

This guide assumes you already have an API key and at least one profile connected. Both take about two minutes: start with the quickstart, or get a key in the console - the trial is 10 days and needs no card.

1. A one-off CSV

The whole export is a loop and a writer. Reviews come back in one schema regardless of platform, so the columns are the same whether the row came from Google or TripAdvisor.

import csv, requests

API, AUTH = "https://api.repuso.com/public/v1", ("", "YOUR_API_KEY")
COLS = ["id","type","profile_id","from_name","rating_value","rating_scale",
        "sentiment","posted_on","text"]

def rows():
    params = {"limit": 100}
    while True:
        page = requests.get(f"{API}/reviews/get", params=params, auth=AUTH, timeout=30).json()
        for r in page["items"]:
            yield {c: r.get(c, "") for c in COLS}
        if not page.get("has_more"):
            break
        params["before_ts"] = page["next_before_ts"]
        params["before_id"] = page["next_before_id"]

with open("reviews.csv", "w", newline="", encoding="utf-8") as f:
    w = csv.DictWriter(f, fieldnames=COLS)
    w.writeheader()
    w.writerows(rows())

Open it in Excel, Numbers or Sheets. Two details worth knowing before you hand it to someone: rating_value is not always out of five - divide by rating_scale if you are averaging across platforms - and review text can contain newlines, which is why this uses a real CSV writer rather than joining strings with commas.

2. Narrow it before you export

Filtering server-side beats exporting everything and deleting rows afterwards:

# only the negative ones, this year, from two profiles
?max_rating=3&since=2026-01-01&profiles=49331,49334

# only reviews mentioning delivery
?q=delivery

# only reviews with photos or video
?media_only=true

# translated into English on the way out
?translate=en

3. A Google Sheet that updates itself

If the point is a shared sheet rather than a file, skip the CSV. This Apps Script rewrites a tab from the API, and a time-based trigger keeps it current with nothing running on your side.

function refreshReviews() {
  const KEY = "YOUR_API_KEY";
  const headers = { Authorization: "Basic " + Utilities.base64Encode(":" + KEY) };
  const sheet = SpreadsheetApp.getActive().getSheetByName("Reviews");

  let url = "https://api.repuso.com/public/v1/reviews/get?limit=100";
  const out = [["Date","Platform","Rating","Author","Sentiment","Review"]];

  while (url) {
    const page = JSON.parse(UrlFetchApp.fetch(url, { headers }).getContentText());
    page.items.forEach(r => out.push([
      r.posted_on, r.type, r.rating_value, r.from_name, r.sentiment, r.text
    ]));
    url = page.has_more
      ? `https://api.repuso.com/public/v1/reviews/get?limit=100&before_ts=${page.next_before_ts}&before_id=${page.next_before_id}`
      : null;
  }

  sheet.clear();
  sheet.getRange(1, 1, out.length, out[0].length).setValues(out);
}

In the Apps Script editor: Triggers → add a time-driven trigger on refreshReviews, hourly or daily. Write the values in one setValues call as above rather than appending row by row - Apps Script quotas punish per-row writes, and a few thousand reviews will time out.

Keeping it fast on a big account

Exporting everything every hour is wasteful once you are past a few thousand reviews. Store the newest posted_on you exported and pass it back as since, then append only what is new. Or take a webhook and write rows as reviews arrive.

← All guides