Sync Discourse Data Explorer queries to Google Sheets
This how-to guide explains how to automate importing Discourse Data Explorer 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 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 plugin enabled on your Discourse site
- A saved Data Explorer 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
- Navigate to your Discourse site’s Admin panel
- Go to Plugins → Data Explorer
- Open the query you want to sync
- 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
-
Go to Admin → Advanced → API Keys
-
Click New API Key
-
Configure the key:
- Description: Enter something descriptive like “Google Sheets Sync”
- User Level: Select “Single User” and choose an admin user, or select “All Users”
- Scope: Select “Granular”, then check run queries under the Data Explorer section
Using the granular “run queries” scope limits this API key to only running Data Explorer queries, which is more secure than using a global key. -
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
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.
- Open your Google Sheet
- Go to Extensions → Apps Script
- Delete any existing code in
Code.gsand paste the following:
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/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());
}
}
- Update the configuration values at the top of the script:
- Replace
https://your-forum.comwith your Discourse URL - Replace
123with your query ID - Replace
your_api_key_herewith your API key
- Replace
Step 3: Run and authorize the script
-
Click the Save icon (
) and name your project (e.g., “Discourse Sync”) -
Click the Run button (
) -
A popup will appear asking for authorization:
- Click Review Permissions
- Select your Google account
- If you see “Google hasn’t verified this app”, click Advanced → Go to [Project Name] (unsafe)
- Click Allow
-
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:
-
In the Apps Script editor, click the Triggers icon (
) in the left sidebar -
Click + Add Trigger (bottom right)
-
Configure the trigger:
-
Function to run:
syncDiscourseData - Event source: Time-driven
- Type of time based trigger: Choose your preferred frequency (e.g., Day timer, Hour timer)
- Time of day/interval: Select when you want the sync to run
-
Function to run:
-
Click Save
Handling queries with parameters
If your Data Explorer query uses parameters, add them to the request payload:
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
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:
--[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 |
| Rate limiting errors | Discourse limits Data Explorer API requests to 2 per 10 seconds by default. Add delays between requests if needed |
Additional resources
- Discourse Data Explorer
- Run Data Explorer queries with the Discourse API
- Create and configure an API key
- Google Apps Script UrlFetchApp documentation
Last edited by @MarkDoerr 2026-01-27T18:37:19Z
Last checked by @MarkDoerr 2026-01-27T18:31:42Z
Check document
Perform check on document: