Aftrad allows you to save any Statistics view as a report and expose it as a public endpoint — so you can automatically pull that data into Google Sheets on a scheduled basis. This is useful for building dashboards or tracking performance over time without manual exports.
Step 1 — Configure your report in Statistics
Go to Statistics and apply the filters, dimensions, and metrics you need for your report.
Step 2 — Publish the report
Once your view is ready, click the Publish button in the top-right corner.
A side panel will appear. Fill in:
Report name — give it a descriptive name (e.g. Yesterday - 2239 - Solar panels)
Mark this report public — enable this toggle to generate a public URL
Then click Publish.
Step 3 — Open your Saved Reports
After publishing, the report title will appear at the top of the Statistics view. Click on Saved reports in the top-right area to access all your saved reports.
Step 4 — Get your report URL
In the Saved Reports list, find your report. If it is published, you will see a CSV button in the Public URL column. Click the copy icon next to it to copy your report's CSV endpoint URL.
Save this URL — you will need it in the next steps.
Step 5 — Set up Google Apps Script
Open a Google Sheet, then go to Extensions → Apps Script.
In the Apps Script editor, paste the following code and replace "PASTE HERE YOUR REPORT URL" with the CSV URL you copied in Step 4:
Code
Code
function importCsvAppend() {
const url = "PASTE HERE YOUR REPORT URL";
const sheetName = "data";
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName(sheetName) || ss.insertSheet(sheetName);
const resp = UrlFetchApp.fetch(url, {
muteHttpExceptions: true,
followRedirects: true,
headers: {
"User-Agent": "Mozilla/5.0",
"Accept": "text/csv,application/csv,text/plain,*/*",
},
});
const code = resp.getResponseCode();
if (code !== 200) {
throw new Error(`CSV fetch failed: HTTP ${code}`);
}
const content = resp.getContentText().replace(/^\uFEFF/, "");
const csvValues = Utilities.parseCsv(content, ";");
if (!csvValues || csvValues.length < 2) return;
const header = csvValues[0];
let rows = csvValues.slice(1);
// Write header if the sheet is empty
if (sheet.getLastRow() === 0) {
sheet.getRange(1, 1, 1, header.length).setValues([header]);
}
// Text columns (not converted to number)
const textCols = new Set([0, 1, 2, 3, 4]);
function parseValue(value, colIndex) {
if (value === null || value === undefined || value === "") return "";
const str = String(value).trim();
// Parse date
if (colIndex === 0 && /^\d{4}-\d{2}-\d{2}$/.test(str)) {
const [y, m, d] = str.split("-").map(Number);
return new Date(y, m - 1, d);
}
if (textCols.has(colIndex)) {
return str;
}
// Parse number
const normalized = str.replace(/\s/g, "").replace(",", ".");
const num = Number(normalized);
return isNaN(num) ? str : num;
}
rows = rows.map(r => r.map((cell, i) => parseValue(cell, i)));
// Unique key to avoid duplicate rows
const keyIdx = [0, 1, 2, 4];
const lastRow = sheet.getLastRow();
const existingKeys = new Set();
if (lastRow >= 2) {
const range = sheet.getRange(2, 1, lastRow - 1, Math.max(...keyIdx) + 1).getValues();
for (const r of range) {
const key = keyIdx.map(i => {
const v = r[i] instanceof Date
? Utilities.formatDate(r[i], Session.getScriptTimeZone(), "yyyy-MM-dd")
: String(r[i]).trim();
return v;
}).join("|");
existingKeys.add(key);
}
}
const newRows = [];
for (const r of rows) {
const key = keyIdx.map(i => {
const v = r[i] instanceof Date
? Utilities.formatDate(r[i], Session.getScriptTimeZone(), "yyyy-MM-dd")
: String(r[i]).trim();
return v;
}).join("|");
if (!existingKeys.has(key)) {
newRows.push(r);
existingKeys.add(key);
}
}
if (newRows.length) {
const startRow = sheet.getLastRow() + 1;
sheet.getRange(startRow, 1, newRows.length, header.length).setValues(newRows);
// Date format
sheet.getRange(startRow, 1, newRows.length, 1)
.setNumberFormat("yyyy-mm-dd");
// Number format:
// - integers with no decimals
// - decimals with up to 3 decimal places
if (header.length > 5) {
sheet.getRange(startRow, 6, newRows.length, header.length - 5)
.setNumberFormat("#.##0,###");
}
}
}
Step 6 — Name and save the project
Click on the project title ("Untitled project") at the top of the editor to rename it — for example, Import Stats Aftrad. This makes it easier to identify later.
Step 7 — Run the script
Click the Run button in the toolbar. Make sure the function selected in the dropdown is importCsvAppend.
Step 8 — Review permissions
The first time you run the script, Google will ask you to authorise it. Click Review permissions, then select your Google account and grant the required access (Google Sheets and external connections).
Step 9 — Check the Execution log
Once the script finishes, the Execution log at the bottom of the editor will show Execution started and Execution completed. If there are any errors, they will appear here.
Step 10 — Check the data in your spreadsheet
Go back to your Google Sheet. You will find a new tab called data containing all the imported rows from your Aftrad report.
Step 11 — Schedule automatic execution (optional)
You can configure the script to run automatically on a schedule — for example, every day — so your sheet always stays up to date.
In the Apps Script editor, click the Triggers icon (clock) in the left sidebar, then click Add Trigger in the bottom-right corner.
Function to run:
importCsvAppendEvent source: Time-driven
Type of time-based trigger: Day timer
Time of day: your preferred window (e.g. 7:00 a.m. – 8:00 a.m.)
Click Save.
Note: The script is designed to append data rather than overwrite it. Each time it runs, it only adds rows that don't already exist in the sheet, avoiding duplicates. This makes it ideal for tracking daily performance over time.













