# Automate the syncing of Discourse queries to Google Sheets

**URL:** https://meta.discourse.org/t/automate-the-syncing-of-discourse-queries-to-google-sheets/394473
**Category:** Integrations
**Tags:** data-explorer, how-to, google
**Created:** [27 januari 2026 om 18:31 UTC](https://meta.discourse.org/t/automate-the-syncing-of-discourse-queries-to-google-sheets/394473 "2026-01-27T18:31:01Z")
**Posts on this page:** 1
**Page:** 1

<div class="post-metadata">

### Author: ![Discourse](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/discourse/32/148734_2.png) [@Discourse](https://meta.discourse.org/u/Discourse)
#### Post date: [27 januari 2026 om 18:31 UTC](https://meta.discourse.org/t/automate-the-syncing-of-discourse-queries-to-google-sheets/394473/1 "2026-01-27T18:31:01Z")

</div>

# Sync Discourse [Data Explorer](https://meta.discourse.org/t/32566?silent=true) queries to Google Sheets

> 🔖 This how-to guide explains how to automate importing Discourse [Data Explorer](https://meta.discourse.org/t/32566?silent=true) query results into Google Sheets using Google Apps Script.
> 
> 🙋 Required user level: Administrator

## Overview

By connecting Google Sheets to your Discourse site’s [Data Explorer](https://meta.discourse.org/t/32566?silent=true) plugin, you can automatically pull query results on a schedule. This is useful for creating dashboards, tracking metrics, or sharing reports with team members who don’t have Discourse admin access.

## Prerequisites

Before you begin, ensure you have:

- The [Data Explorer](https://meta.discourse.org/t/32566) plugin enabled on your Discourse site
- A saved [Data Explorer](https://meta.discourse.org/t/32566?silent=true) query you want to sync
- Admin access to your Discourse site
- A Google account with access to Google Sheets

## Step 1: Prepare Discourse

### Get your query ID

1. Navigate to your Discourse site’s Admin panel
2. Go to **Plugins** → [Data Explorer](https://meta.discourse.org/t/32566?silent=true)
3. Open the query you want to sync
4. Look at the URL in your browser’s address bar—it will look like `.../queries/123`. The number at the end is your **query ID**

### Generate an API key

1. Go to **Admin → Advanced → API Keys**

2. Click **New API Key**

3. Configure the key:

4. Click **Save** and **copy the API key immediately** —you won’t be able to see it again

For more details on API keys, see: [Create and configure an API key](https://meta.discourse.org/t/create-and-configure-an-api-key/230124)

## Step 2: Set up Google Apps Script

Google Apps Script includes `UrlFetchApp` as a built-in service—you don’t need to install anything. Simply type it into the code editor and the script engine recognizes it automatically.

1. Open your Google Sheet
2. Go to **Extensions** → **Apps Script**
3. Delete any existing code in `Code.gs` and paste the following:

```javascript
function syncDiscourseData() {
  // ============ CONFIGURATION ============
  const DISCOURSE_URL = "https://your-forum.com"; // Your Discourse URL (no trailing slash)
  const QUERY_ID = "123"; // Your Data Explorer query ID
  const API_KEY = "your_api_key_here"; // Your API key
  const API_USERNAME = "system"; // Username for API requests
  // ========================================
  
  const url = `${DISCOURSE_URL}/admin/plugins/discourse-data-explorer/queries/${QUERY_ID}/run.csv`;
  
  const options = {
    "method": "post",
    "headers": {
      "Api-Key": API_KEY,
      "Api-Username": API_USERNAME
    }
  };

  try {
    const response = UrlFetchApp.fetch(url, options);
    const csvData = response.getContentText();
    const data = Utilities.parseCsv(csvData);
    
    const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
    
    // Clear existing data and write new data
    sheet.clear(); 
    sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
    
    // Add a "Last Updated" timestamp two columns after the data
    const timestampCell = sheet.getRange(1, data[0].length + 2);
    const now = new Date();
    timestampCell.setValue("Last Updated: " + Utilities.formatDate(now, Session.getScriptTimeZone(), "yyyy-MM-dd HH:mm:ss"));
    timestampCell.setFontWeight("bold");
    
    Logger.log("Successfully synced " + (data.length - 1) + " rows");
    
  } catch (e) {
    Logger.log("Error: " + e.toString());
  }
}

```

1. Update the configuration values at the top of the script:
  - Replace `https://your-forum.com` with your Discourse URL
  - Replace `123` with your query ID
  - Replace `your_api_key_here` with your API key

## Step 3: Run and authorize the script

1. Click the **Save** icon (💾) and name your project (e.g., “Discourse Sync”)

2. Click the **Run** button (▶)

3. A popup will appear asking for authorization:

4. Check your Google Sheet—the data should now appear

> 💡 If you encounter errors, click **View** → **Logs** in the Apps Script editor to see detailed error messages.

## Step 4: Set up automated sync (optional)

To run the sync automatically on a schedule:

1. In the Apps Script editor, click the **Triggers** icon (🕐) in the left sidebar

2. Click **+ Add Trigger** (bottom right)

3. Configure the trigger:

4. Click **Save**

## Handling queries with parameters

If your [Data Explorer](https://meta.discourse.org/t/32566?silent=true) query uses parameters, add them to the request payload:

```javascript
const options = {
  "method": "post",
  "headers": {
    "Api-Key": API_KEY,
    "Api-Username": API_USERNAME
  },
  "payload": {
    "params": JSON.stringify({
      "start_date": "2024-01-01",
      "category_id": "5"
    })
  }
};

```

> ⚠ All parameter values must be strings, even for numeric parameters.

For more details on running parameterized queries, see: [Run Data Explorer queries with the Discourse API](https://meta.discourse.org/t/run-data-explorer-queries-with-the-discourse-api/120063)

## Handling large datasets

CSV exports default to a maximum of 10,000 rows. For larger datasets, implement pagination in your query using `LIMIT` and `OFFSET` parameters:

```sql
--[params]
-- integer :limit = 1000
-- integer :page = 0

SELECT *
FROM your_table
OFFSET :page * :limit
LIMIT :limit

```

Then modify your script to loop through pages until no more results are returned.

## Troubleshooting

| Issue | Solution |
| --- | --- |
| 403 Forbidden error | Verify your API key has the “run queries” scope and the username has admin access |
| 404 Not Found error | Check that the query ID is correct and the query exists |
| Empty results | Verify the query returns data when run directly in [Data Explorer](https://meta.discourse.org/t/32566?silent=true) |
| Rate limiting errors | Discourse limits [Data Explorer](https://meta.discourse.org/t/32566?silent=true) API requests to 2 per 10 seconds by default. Add delays between requests if needed |

## Additional resources

- [Discourse Data Explorer](https://meta.discourse.org/t/discourse-data-explorer/32566)
- [Run Data Explorer queries with the Discourse API](https://meta.discourse.org/t/run-data-explorer-queries-with-the-discourse-api/120063)
- [Create and configure an API key](https://meta.discourse.org/t/create-and-configure-an-api-key/230124)
- [Google Apps Script UrlFetchApp documentation](https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app)

> Last edited by @MarkDoerr 2026-02-25T00:37:36Z
> 
> Last checked by @MarkDoerr 2026-01-27T18:31:42Z
> 
> > **Check document**
> >
> > Perform check on document:
