Menü
05.03.2026 · Efficiency,
Excel

FriTTo + Excel: Export time data with one click using Office Scripts

Learn all about modern time tracking, productivity and the latest trends in the world of work.

zurück zu allen Artikeln

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. (More about access permissions in Fritto). 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) — Deutsche Version
 *
 * Liest Einstellungen vom Blatt "Einstellungen", ruft die TimeTracker-API auf
 * und füllt das Blatt "Daten" mit den exportierten Zeiteinträgen.
 *
 * Verwendung:
 *   1. Öffnen Sie die Excel-Datei in Excel für das Web oder Excel Desktop (Microsoft 365)
 *   2. Gehen Sie zum Reiter "Automatisieren"
 *   3. Klicken Sie auf "Neues Skript", fügen Sie diesen Code ein und speichern Sie
 *   4. Füllen Sie das Blatt "Einstellungen" aus und klicken Sie im Skript-Editor auf "Ausführen"
 */

async function main(workbook: ExcelScript.Workbook): Promise<void> {
    const settingsSheet = workbook.getWorksheet("Einstellungen");
    if (!settingsSheet) {
        throw new Error("Blatt 'Einstellungen' nicht gefunden.");
    }

    // Eingaben lesen
    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();

    // Validierung
    if (!apiUrl) throw new Error("API-Basis-URL ist erforderlich.");
    if (!fromDate) throw new Error("VON Datum ist erforderlich.");
    if (!toDate) throw new Error("BIS Datum ist erforderlich.");
    if (fromDate > toDate) throw new Error("VON Datum muss vor oder gleich dem BIS Datum liegen.");
    if (!apiKey) throw new Error("API-Schlüssel fehlt.");

    // Anfrage-URL erstellen
    const baseUrl = apiUrl.replace(/\/+$/, "");
    const requestUrl = `${baseUrl}/api/app/export-to-excel?From=${fromDate}&To=${toDate}`;

    // Daten von API abrufen
    console.log(`Daten werden abgerufen von: ${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(`Ungültige Anfrage (HTTP 400). Details: ${body.substring(0, 300)}`);
            case 401:
                throw new Error("Authentifizierung fehlgeschlagen. Bitte überprüfen Sie Ihren API-Schlüssel.");
            case 403:
                throw new Error("Zugriff verweigert. Ihr API-Schlüssel hat keine Berechtigung für diese Daten.");
            case 404:
                throw new Error("API-Endpunkt nicht gefunden. Bitte überprüfen Sie die API-Basis-URL.");
            default:
                throw new Error(`Serverfehler (HTTP ${response.status}). Bitte versuchen Sie es später erneut.`);
        }
    }

    const result: { items: ExportEntry[] } = await response.json();
    const items = result.items;

    // Daten-Blatt befüllen
    const dataSheet = workbook.getWorksheet("Daten");
    if (!dataSheet) {
        throw new Error("Blatt 'Daten' nicht gefunden.");
    }

    // Vorhandene Daten löschen
    const usedRange = dataSheet.getUsedRange();
    if (usedRange) {
        usedRange.clear();
    }

    // Vorhandenen Auto-Filter entfernen
    const existingFilter = dataSheet.getAutoFilter();
    if (existingFilter.getIsDataFiltered()) {
        existingFilter.remove();
    }

    if (items.length === 0) {
        console.log("Keine Daten für den angegebenen Zeitraum gefunden.");
        return;
    }

    // Spaltenüberschriften
    const headers = [
        "Datum", "Kunde", "Projekt", "Beschreibung", "Aufgaben-URL",
        "Erfasste Minuten", "Abrechenbar?", "Genehmigt?",
        "Vorname", "Nachname", "Mitarbeitergruppen", "Kostensatz", "Währung",
    ];

    // Überschriften schreiben
    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);

    // Datenzeilen erstellen
    const rows: (string | number)[][] = items.map((item) => [
        item.date ?? "",
        item.client ?? "",
        item.project ?? "",
        item.description ?? "",
        item.taskUrl ?? "",
        item.trackedMinutes ?? 0,
        item.isBillable ? "Ja" : "Nein",
        item.isApproved ? "Ja" : "Nein",
        item.firstName ?? "",
        item.lastName ?? "",
        item.employeeGroups ?? "",
        item.costRate ?? "",
        item.currency ?? "",
    ]);

    // Daten schreiben
    const dataRange = dataSheet.getRangeByIndexes(1, 0, rows.length, headers.length);
    dataRange.setValues(rows);

    // Spaltenbreite automatisch anpassen
    dataSheet.getUsedRange()?.getFormat().autofitColumns();

    // Auto-Filter anwenden
    dataSheet.getAutoFilter().apply(dataSheet.getUsedRange());

    console.log(`${items.length} Einträge erfolgreich exportiert.`);
}

/** Excel-Zellwert (String, Zahl oder Datumsseriennummer) in yyyy-mm-dd String umwandeln. */
function formatDateValue(value: string | number | boolean): string {
    if (value === null || value === undefined || value === "") return "";

    if (typeof value === "number") {
        // Excel-Datumsseriennummer -> 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();
}

/** Zellwert sicher in String umwandeln. */
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.

Mehr News

Das könnte Ihnen auch gefallen

Adding New Employees and Assigning Groups — Here’s How It Works in Fritto

Learn all about modern time tracking, productivity and the latest trends in the world of work.
Read more

Request, approve, manage time off — here’s how it works with Fritto

Learn all about modern time tracking, productivity and the latest trends in the world of work.
Read more

Working Time Recording in Germany: What Businesses Need to Know Right Now

Learn all about modern time tracking, productivity and the latest trends in the world of work.
Read more