FriTTo + Excel: Export Your Time Data in One Click with Office Scripts
Why Excel Still Rules
Your team tracks time in FriTTo. Your finance department works in Excel. And your project managers build their own pivot tables. Sound familiar? No matter how powerful your time tracking platform is, the data needs to land where your people actually work — and for most organizations, that place is still Microsoft Excel.
That’s exactly why we built FriTTo API-first from day one. Instead of forcing you into our reporting format, we give you the tools to pull your data into any environment you choose.
Today we’ll show you how to connect FriTTo directly to Excel using Office Scripts — no technical detours, no manual exports, no copy-paste marathons.
What You’ll Get
We’ve prepared a ready-to-use Excel template with a built-in Office Script that calls the FriTTo API and populates your spreadsheet automatically. Here’s what’s inside:
- Sheet — Settings — enter your API URL, date range, and API key. That’s all the configuration you need.
- Sheet — Data — after running the script, your time records appear here with full detail: date, client, project, description, tracked minutes, billable status, approval status, employee info, and cost rates.
- Office Script (TypeScript) — a lightweight script that reads your settings, calls the FriTTo REST API, and writes the results directly into Excel. Auto-formatted headers, auto-fit columns, and auto-filter enabled.
How It Works: Step by Step
Step 1: Open the Template
Download the FriTTo Export Template and open it in Excel for the web or desktop version (Microsoft 365 required for Office Scripts).
Step 2: Configure Your Settings
On the Settings sheet, fill in four fields:
- API Base URL — the URL is already pre-filled:
https://api.steinpilz-fritto.de. No changes needed here. - FROM Date — start of the period you want to export.
- TO Date — end of the period.
- API Key — your personal API key from FriTTo (see below how to create one).
Step 3: Create an API Key in FriTTo
Log into FriTTo and click on your profile icon in the top-right corner. Scroll down to the Personal API Tokens section and click Add API token. Give the token a name (e.g., “excel”), set an expiration date, and copy the generated key. Paste it into the API Key field on the Settings sheet — done.
Important: The data export is only available to users with one of the following roles: Administrator, Department Manager, Manager, or Reviewer. You can verify your access by checking whether the menu item Reports → All Time Reports is visible in the FriTTo interface.
Step 4: Add the Script
Go to the Automate tab in the Excel ribbon, click New Script, and select Create in Code Editor. Replace the displayed code entirely with the following script:
/**
* Fritto Export — Office Script (TypeScript)
*
* Reads settings from the "Settings" sheet, calls the TimeTracker API,
* and populates the "Data" sheet with exported time records.
*
* How to use:
* 1. Open the Excel file in Excel for the web or Excel desktop (Microsoft 365)
* 2. Go to the "Automate" tab
* 3. Click "New Script", paste this code, and save
* 4. Fill in the Settings sheet and click "Run" in the script editor
*/
async function main(workbook: ExcelScript.Workbook): Promise<void> {
const settingsSheet = workbook.getWorksheet("Settings");
if (!settingsSheet) {
throw new Error("Settings sheet not found.");
}
// Read inputs
const apiUrl = toString(settingsSheet.getRange("B1").getValue()).trim();
const fromDate = formatDateValue(settingsSheet.getRange("B2").getValue());
const toDate = formatDateValue(settingsSheet.getRange("B3").getValue());
const apiKey = toString(settingsSheet.getRange("B4").getValue()).trim();
// Validate
if (!apiUrl) throw new Error("API Base URL is required.");
if (!fromDate) throw new Error("FROM date is required.");
if (!toDate) throw new Error("TO date is required.");
if (fromDate > toDate) throw new Error("FROM date must be earlier than or equal to TO date.");
if (!apiKey) throw new Error("API Key is missing.");
// Build request URL
const baseUrl = apiUrl.replace(/\/+$/, "");
const requestUrl = `${baseUrl}/api/app/export-to-excel?From=${fromDate}&To=${toDate}`;
// Fetch data from API
console.log(`Fetching data from: ${requestUrl}`);
const response = await fetch(requestUrl, {
method: "GET",
headers: {
"X-Api-Key": apiKey,
"Accept": "application/json",
},
});
if (!response.ok) {
const body = await response.text();
switch (response.status) {
case 400:
throw new Error(`Bad request (HTTP 400). Details: ${body.substring(0, 300)}`);
case 401:
throw new Error("Authentication failed. Please check your API Key.");
case 403:
throw new Error("Access denied. Your API Key does not have permission to access this data.");
case 404:
throw new Error("API endpoint not found. Please check the API Base URL.");
default:
throw new Error(`Server error (HTTP ${response.status}). Please try again later.`);
}
}
const result: { items: ExportEntry[] } = await response.json();
const items = result.items;
// Populate Data sheet
const dataSheet = workbook.getWorksheet("Data");
if (!dataSheet) {
throw new Error("Data sheet not found.");
}
// Clear existing data
const usedRange = dataSheet.getUsedRange();
if (usedRange) {
usedRange.clear();
}
// Remove existing auto-filter
const existingFilter = dataSheet.getAutoFilter();
if (existingFilter.getIsDataFiltered()) {
existingFilter.remove();
}
if (items.length === 0) {
console.log("No data found for the specified date range.");
return;
}
// Headers
const headers = [
"Date", "Client", "Project", "Description", "Task URL",
"Tracked Minutes", "Billable?", "Approved?",
"First Name", "Last Name", "Employee Groups", "Cost Rate", "Currency",
];
// Write headers
const headerRange = dataSheet.getRangeByIndexes(0, 0, 1, headers.length);
headerRange.setValues([headers]);
headerRange.getFormat().getFont().setBold(true);
headerRange.getFormat().getFill().setColor("#4472C4");
headerRange.getFormat().getFont().setColor("#FFFFFF");
headerRange.getFormat().setRowHeight(30);
// Build data rows
const rows: (string | number)[][] = items.map((item) => [
item.date ?? "",
item.client ?? "",
item.project ?? "",
item.description ?? "",
item.taskUrl ?? "",
item.trackedMinutes ?? 0,
item.isBillable ? "Yes" : "No",
item.isApproved ? "Yes" : "No",
item.firstName ?? "",
item.lastName ?? "",
item.employeeGroups ?? "",
item.costRate ?? "",
item.currency ?? "",
]);
// Write data
const dataRange = dataSheet.getRangeByIndexes(1, 0, rows.length, headers.length);
dataRange.setValues(rows);
// Auto-fit columns
dataSheet.getUsedRange()?.getFormat().autofitColumns();
// Apply auto-filter
dataSheet.getAutoFilter().apply(dataSheet.getUsedRange());
console.log(`${items.length} records exported successfully.`);
}
/** Convert Excel cell value (string, number, or Date serial) to yyyy-mm-dd string. */
function formatDateValue(value: string | number | boolean): string {
if (value === null || value === undefined || value === "") return "";
if (typeof value === "number") {
// Excel date serial number -> yyyy-mm-dd
const date = new Date(Math.round((value - 25569) * 86400 * 1000));
const y = date.getUTCFullYear();
const m = String(date.getUTCMonth() + 1).padStart(2, "0");
const d = String(date.getUTCDate()).padStart(2, "0");
return `${y}-${m}-${d}`;
}
return value.toString().trim();
}
/** Safely convert a cell value to string. */
function toString(value: string | number | boolean): string {
if (value === null || value === undefined) return "";
return value.toString();
}
interface ExportEntry {
date: string;
client: string;
project: string;
description: string;
taskUrl: string;
trackedMinutes: number;
isBillable: boolean;
isApproved: boolean;
userId: string;
firstName: string;
lastName: string;
employeeGroups: string;
costRate: number | null;
currency: string | null;
}
Tip: After saving, click the three dots and select + Add in Workbook to add a convenient Run button directly in your spreadsheet.
Step 5: Run
Click Run — either from the Run button in the Office Script editor or from the green Run button on the Data sheet that you added in the previous step. The script fetches your time records from the FriTTo API and fills the Data sheet. Headers are formatted, columns auto-sized, and filters applied. Your data is now ready for analysis.
What Can You Do with the Data?
Once your time records are in Excel, the possibilities are wide open:
- Pivot tables — break down billable hours by client, project, or team member in seconds.
- Cost analysis — combine tracked minutes with cost rates to calculate project profitability.
- Client invoicing — filter by client and date range, export to your billing workflow.
- Approval tracking — quickly see which entries are approved and which are still pending.
- Scheduled refresh — combine the Office Script with Power Automate to run the export automatically — daily, weekly, or monthly.
Why This Matters
Most time trackers offer CSV export at best — a one-time, manual process that breaks the moment your data changes. With FriTTo’s API and Office Scripts, you get a live connection between your time tracking data and your spreadsheet. Update the date range, click Run, and you have fresh data in seconds.
This is what API-first means in practice: your data, your format, your workflow — no compromises.