This article describes the method to create a visual dashboard from a TimeTonic table’s data, using Google Sheets as the calculation and visualization engine. Each time a row is created or modified in TimeTonic, the data is automatically synchronized to Google Sheets via a webhook.
General Principle
The system is based on three connected components. Each update on the TimeTonic side is automatically reflected in Google Sheets, which calculates statistics and generates the charts displayed in your dashboard.
An automation scenario triggers a webhook every time a row is created or modified in your table.
An Apps Script receives the data and writes it into a dedicated tab. Other tabs calculate statistics and display charts.
A Smart Page integrates the published dashboard, accessible to your team without leaving the workspace.
On the TimeTonic Side: Create the Automation Scenario
In your TimeTonic table, go to Automate and create a new automation scenario. Follow these four steps to configure it.
Select When a record view is saved to capture both the creation and subsequent modifications of a row.
You synchronize all rows. The script logic automatically avoids duplicates.
Method POST, no authentication type, data structure JSON List with variables from your table fields to synchronize.
Insert a temporary URL in the field. It will be replaced by the URL generated by Apps Script upon deployment.
A created row can be progressively enriched, for example through fields filled later or values calculated by other scenarios. The trigger When a record view is saved captures every record, ensuring your Sheet always reflects the current state of your table.
On the Google Sheets Side: Structure Your File into Three Tabs
Create a Google Sheet and organize it into three distinct tabs. Each plays a specific role in the data processing chain.
Tab 1: Raw Data
Receives rows sent by TimeTonic via the webhook. Each column corresponds to a field in your table. This tab is the source of all statistics.
Tab 2: Stats
Contains calculation tables using SUMIF and COUNTIF formulas that read from Raw Data. This is the engine of your dashboard: everything is calculated here.
Tab 3: Dashboard
Hosts the charts built from the Stats tables. This is the tab you will publish and that will be displayed in your TimeTonic Smart Page.
Install the Apps Script
The Apps Script acts as a receptionist between TimeTonic and Google Sheets. It receives data sent by the webhook and writes it into the Raw Data tab, avoiding duplicates through update logic.
In your Google Sheet, go to Extensions → Apps Script. A new window opens.
Delete the default code, paste the script, then replace the SPREADSHEET_ID variable with your Sheet’s ID (visible in the URL between /d/ and /edit).
Deploy → New deployment → Web app. Execute as: Me. Who has access: Anyone. Accept Google authorization.
Google generates a webhook URL ending with /exec. Copy it and paste it into the URL field of the Call Webhook action in your TimeTonic scenario.
Here is the example script in Google Sheet.
/**
* TimeTonic → Google Sheet Webhook Receiver
*
* Receives intervention data from TimeTonic automation
* and writes it into the "Raw Data" sheet.
*
* Features:
* - UPSERT logic: 1 row per intervention (updates existing rows, avoids duplicates)
* - Auto-calculates concat keys for COUNTIF/SUMIF formulas
* - Handles FR and US numeric formats (comma and dot decimals)
* - Forces number format on cells (avoids Google Sheets locale issues)
*/
// === CONFIGURATION ===
// Replace with your own Spreadsheet ID (the part between /d/ and /edit in your Sheet URL)
const SPREADSHEET_ID = "1ilnTpPZabmUfFz1o3CC39kYYB4mRQ34Hc8B8ieHja4Q";
const SHEET_NAME = "Raw Data";
// Column where Intervention # is stored (column D = 4th column)
const INTERVENTION_NUM_COL = 4;
// === MAIN FUNCTIONS ===
function getSheet() {
const spreadsheet = SpreadsheetApp.openById(SPREADSHEET_ID);
const sheet = spreadsheet.getSheetByName(SHEET_NAME);
if (!sheet) {
throw new Error("Sheet '" + SHEET_NAME + "' not found");
}
return sheet;
}
/**
* Webhook endpoint called by TimeTonic automation
*/
function doPost(e) {
try {
const sheet = getSheet();
const payload = JSON.parse(e.postData.contents);
// Extract year and month from date (for concat keys)
const dateStr = payload.date || "";
const { year, month } = parseDate(dateStr);
// Build the 3 concat keys used by Stats sheet COUNTIF formulas
const statsKeyType = year && month
? year + "-" + month + "-" + (payload.type || "")
: "";
const statsKeyStatus = year && month
? year + "-" + month + "-" + (payload.status || "")
: "";
const statsKeyTech = year && month
? year + "-" + month + "-" + (payload.technician || "")
: "";
const totalHours = toNumber(payload.total_hours);
const interventionNum = toNumber(payload.intervention_num);
if (!interventionNum && interventionNum !== 0) {
throw new Error("Missing intervention_num in payload");
}
const rowValues = [
dateStr, // A : Date
year, // B : Year
month, // C : Month
interventionNum, // D : Intervention #
payload.title || "", // E : Title
payload.type || "", // F : Type
payload.status || "", // G : Status
payload.customer || "", // H : Customer
payload.site || "", // I : Site
payload.technician || "", // J : Technician
totalHours, // K : Total Hours
statsKeyType, // L : Stats Key Type
statsKeyStatus, // M : Stats Key Status
statsKeyTech // N : Stats Key Tech
];
// UPSERT: search existing row with same Intervention #
const existingRow = findRowByInterventionNum(sheet, interventionNum);
let targetRow, action;
if (existingRow 0) {
targetRow = existingRow;
action = "updated";
} else {
sheet.insertRowBefore(2);
targetRow = 2;
action = "inserted";
}
// Force number format BEFORE writing (fixes FR locale issue)
sheet.getRange(targetRow, 4).setNumberFormat("0"); // Intervention #
sheet.getRange(targetRow, 11).setNumberFormat("General"); // Total Hours
sheet.getRange(targetRow, 1, 1, rowValues.length).setValues([rowValues]);
return ContentService
.createTextOutput(JSON.stringify({
status: "ok",
action: action,
row: targetRow,
intervention_num: interventionNum
}))
.setMimeType(ContentService.MimeType.JSON);
} catch (error) {
return ContentService
.createTextOutput(JSON.stringify({ status: "error", message: error.toString() }))
.setMimeType(ContentService.MimeType.JSON);
}
}
/**
* Find existing row by Intervention #
* Returns row number (1-indexed) if found, 0 if not found
*/
function findRowByInterventionNum(sheet, interventionNum) {
const lastRow = sheet.getLastRow();
if (lastRow Build Calculation Tables in the Stats Tab
In the Stats tab, create calculation zones using two simple functions that read data from Raw Data: SUMIF and COUNTIF.
SUMIF sums a value filtered by a criterion:
COUNTIF counts the number of occurrences of a value in a column:
Create Charts in the Dashboard Tab
For each calculation table created in the Stats tab, generate a chart by following these four steps.
In the Stats tab, select the cell range corresponding to your calculation table.
Menu Insert → Chart. Google Sheets automatically suggests a suitable chart type which you can modify: bars, lines, doughnut, or pie.
Modify the title, colors, legend, and chart type via the customization panel on the right.
Click the three dots on the chart → Copy chart. Paste it into the Dashboard tab and arrange it as you like.
Publish the Dashboard in Secure Mode
Three precautions to take in order to protect your source data and expose only the dashboard.
Right-click on the Raw Data tab → Hide sheet. Do the same for the Stats tab. Only the Dashboard tab remains accessible.
File → Share → Publish to the web. Select only the Dashboard tab (not the entire document). Format: Web page. Publish and copy the generated URL.
Share button → General access: Anyone with the link, role Viewer. In advanced settings, uncheck options for downloading, copying, and printing to prevent any data exfiltration.
Embed the Dashboard in a TimeTonic Smart Page
Final step: display your dashboard directly in TimeTonic via the Smart Page module.
In your TimeTonic workspace, click Add then select the Smart Page module.
Insert the URL generated in the previous step and name your Smart Page.
The dashboard displays in read-only mode within your workspace, updated with each change in the TimeTonic table.
Learn More
Watch the video tutorial
The complete method in 5 minutes, step by step.
Learn More
Master Automations
All triggers and actions available in TimeTonic.
Learn More
Use Smart Pages
Integrate external content into your TimeTonic workspace.