Skip to main content

How to Create a Saved Report and Import Data into Google Sheets

How to Create a Saved Report and Import Data into Google Sheets

J
Written by Jorge Rubia

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

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: importCsvAppend

  • Event 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.

Did this answer your question?