Integrate Toggl Track with Lovable by creating a Supabase Edge Function that proxies the Toggl API v9 using HTTP Basic authentication with your base64-encoded API token. Store the token in Cloud → Secrets, build an Edge Function to handle time entries and project data, then prompt Lovable to create a time tracking dashboard with start/stop timer controls and weekly reports.
Build a Time Tracking Dashboard with Toggl Track and Lovable
Toggl Track is the go-to time tracking tool for freelancers, consultants, and small teams who want premium-quality reporting without the complexity of enterprise software. Its Pomodoro timer, one-click start/stop, and cross-platform apps make it easy to log time accurately. When you connect Toggl to a Lovable app, you can build internal dashboards that surface real-time productivity data, automate client billing reports, and give your team a single view of where hours are going — all without leaving your custom application.
The integration works through Toggl's public REST API v9. Unlike services that require OAuth flows for personal tokens, Toggl uses HTTP Basic authentication: you encode your API token as the username with the string 'api_token' as the password, Base64-encode the combined string, and pass it in the Authorization header on every request. Because this token is a secret credential, it must never appear in frontend code — Lovable routes it through a Supabase Edge Function running on Deno, which acts as an authenticated proxy. Your browser calls the Edge Function, the Edge Function calls Toggl, and the response flows back safely.
With this integration in place, you can let users start and stop timers directly from your Lovable app, see running timers in real time, browse time entries by project or client, and pull weekly or monthly summary reports. The Toggl Reports API (separate from the core API but using the same auth) provides aggregated data perfect for billing dashboards, utilization charts, and productivity scorecards.
Integration method
Toggl Track has no native Lovable connector, so all API calls are routed through a Supabase Edge Function running on Deno. The Edge Function encodes your Toggl API token in Base64 for HTTP Basic authentication and acts as a secure server-side proxy, keeping credentials out of the browser entirely. Lovable's AI generates the frontend timer controls, project selectors, and report dashboards that communicate with this Edge Function.
Prerequisites
- A Toggl Track account (free tier works) — sign up at toggl.com/track
- Your Toggl API token — found in Profile Settings → API Token at the bottom of the page
- A Lovable project with Lovable Cloud enabled (the default for all new projects)
- Basic familiarity with Lovable's chat interface and the Cloud → Secrets panel
- Your Toggl Workspace ID — visible in the URL when you visit toggl.com/app/workspaces
Step-by-step guide
Retrieve your Toggl API token and workspace ID
Retrieve your Toggl API token and workspace ID
Before writing any code, gather the two pieces of information you need to authenticate with Toggl: your personal API token and your workspace ID. Log in to Toggl Track at toggl.com/track and click your avatar in the top-left corner to open the profile menu. Select 'Profile Settings' from the dropdown. Scroll to the very bottom of the Profile Settings page where you'll find a section labeled 'API Token'. Click 'Click to reveal' to display your token — it looks like a 32-character hexadecimal string. Copy it to a safe temporary location like a password manager note. Next, find your workspace ID. Navigate to toggl.com/app/workspaces in your browser while logged in. The URL will change to something like toggl.com/app/workspaces/1234567/settings — the number in the URL is your workspace ID. You can also find it by going to any time entry view: the workspace ID appears in API response payloads as the 'wid' field. Write down both values because you'll need them in the next step. The Toggl API v9 base URL is https://api.track.toggl.com/api/v9 and the reports API lives at https://api.track.toggl.com/reports/api/v3. Both use the same API token for authentication via HTTP Basic auth, where the username is your API token and the password is the literal string 'api_token'.
Pro tip: Keep your API token private — it grants full access to your Toggl account including all workspaces. Never paste it into Lovable's chat window, especially on the free tier where chat history may be visible.
Expected result: You have your 32-character Toggl API token and numeric workspace ID ready to enter into Lovable Cloud Secrets.
Store your Toggl credentials in Cloud Secrets
Store your Toggl credentials in Cloud Secrets
With your API token and workspace ID in hand, you need to store them as encrypted secrets that your Edge Function can access at runtime. In Lovable, look at the top of the editor and click the '+' icon next to the Preview panel — this opens the Cloud tab. In the Cloud tab, find the 'Secrets' section in the left sidebar and click it to open the Secrets panel. Click 'Add new secret'. In the Name field type TOGGL_API_TOKEN exactly as written (all caps, underscore). In the Value field paste your 32-character API token. Click Save. Now add a second secret: click 'Add new secret' again. Name it TOGGL_WORKSPACE_ID and paste your numeric workspace ID as the value. Click Save. These secrets are now encrypted and stored server-side. They will be automatically injected into every Edge Function in your project as environment variables. Your Edge Function code will access them with Deno.env.get('TOGGL_API_TOKEN') and Deno.env.get('TOGGL_WORKSPACE_ID'). Lovable's security infrastructure — which blocks approximately 1,200 hardcoded API keys per day — will flag any attempt to use these values in frontend code, ensuring your Toggl credentials stay in the red zone where only Edge Functions can reach them.
Pro tip: After saving secrets, they take effect immediately for new Edge Function invocations. There is no need to redeploy or restart anything.
Expected result: Two secrets — TOGGL_API_TOKEN and TOGGL_WORKSPACE_ID — appear in your Cloud → Secrets panel with masked values.
Create the Toggl Edge Function proxy
Create the Toggl Edge Function proxy
Now ask Lovable to create the Edge Function that will authenticate with Toggl and proxy API requests from your frontend. This function handles the Base64 encoding of your API token for HTTP Basic auth, routes different actions (get projects, list time entries, start timer, stop timer, get reports) to the correct Toggl API endpoints, and returns structured JSON responses. Paste the following prompt into Lovable's chat interface. Lovable will generate the Edge Function code, create the file at supabase/functions/toggl-proxy/index.ts, and deploy it to your Cloud project automatically.
Create a Supabase Edge Function called 'toggl-proxy' at supabase/functions/toggl-proxy/index.ts. It should authenticate with the Toggl API v9 using HTTP Basic auth by reading TOGGL_API_TOKEN and TOGGL_WORKSPACE_ID from Deno.env.get(). Encode the auth string as btoa(apiToken + ':api_token'). The function should accept a POST request with a JSON body containing an 'action' field and optional 'payload'. Supported actions: 'get_projects' (GET /workspaces/{wid}/projects), 'get_current_entry' (GET /me/time_entries/current), 'get_time_entries' (GET /me/time_entries with optional start_date/end_date query params from payload), 'start_timer' (POST /workspaces/{wid}/time_entries with payload containing description and project_id), 'stop_timer' (PATCH /workspaces/{wid}/time_entries/{time_entry_id}/stop where time_entry_id comes from payload), 'get_weekly_report' (POST to https://api.track.toggl.com/reports/api/v3/workspace/{wid}/summary with start_date and end_date from payload). Return CORS headers for all responses. Handle errors by returning a 400 status with an error message.
Paste this in Lovable chat
1// supabase/functions/toggl-proxy/index.ts2import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';34const corsHeaders = {5 'Access-Control-Allow-Origin': '*',6 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',7};89serve(async (req) => {10 if (req.method === 'OPTIONS') {11 return new Response('ok', { headers: corsHeaders });12 }1314 try {15 const apiToken = Deno.env.get('TOGGL_API_TOKEN');16 const workspaceId = Deno.env.get('TOGGL_WORKSPACE_ID');1718 if (!apiToken || !workspaceId) {19 return new Response(20 JSON.stringify({ error: 'Toggl credentials not configured' }),21 { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }22 );23 }2425 const authHeader = 'Basic ' + btoa(apiToken + ':api_token');26 const togglBase = 'https://api.track.toggl.com/api/v9';27 const reportsBase = 'https://api.track.toggl.com/reports/api/v3';2829 const { action, payload = {} } = await req.json();3031 let togglUrl = '';32 let method = 'GET';33 let body: string | undefined;3435 switch (action) {36 case 'get_projects':37 togglUrl = `${togglBase}/workspaces/${workspaceId}/projects`;38 break;39 case 'get_current_entry':40 togglUrl = `${togglBase}/me/time_entries/current`;41 break;42 case 'get_time_entries': {43 const params = new URLSearchParams();44 if (payload.start_date) params.set('start_date', payload.start_date);45 if (payload.end_date) params.set('end_date', payload.end_date);46 togglUrl = `${togglBase}/me/time_entries?${params.toString()}`;47 break;48 }49 case 'start_timer':50 togglUrl = `${togglBase}/workspaces/${workspaceId}/time_entries`;51 method = 'POST';52 body = JSON.stringify({53 description: payload.description || '',54 project_id: payload.project_id || null,55 start: new Date().toISOString(),56 duration: -1,57 created_with: 'lovable-app',58 workspace_id: parseInt(workspaceId),59 });60 break;61 case 'stop_timer':62 togglUrl = `${togglBase}/workspaces/${workspaceId}/time_entries/${payload.time_entry_id}/stop`;63 method = 'PATCH';64 break;65 case 'get_weekly_report':66 togglUrl = `${reportsBase}/workspace/${workspaceId}/summary`;67 method = 'POST';68 body = JSON.stringify({69 start_date: payload.start_date,70 end_date: payload.end_date,71 grouping: 'projects',72 });73 break;74 default:75 return new Response(76 JSON.stringify({ error: `Unknown action: ${action}` }),77 { status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }78 );79 }8081 const togglRes = await fetch(togglUrl, {82 method,83 headers: {84 Authorization: authHeader,85 'Content-Type': 'application/json',86 },87 body,88 });8990 const data = await togglRes.json();9192 return new Response(JSON.stringify(data), {93 status: togglRes.status,94 headers: { ...corsHeaders, 'Content-Type': 'application/json' },95 });96 } catch (err) {97 return new Response(98 JSON.stringify({ error: err.message }),99 { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }100 );101 }102});Pro tip: The start_timer action sets duration to -1, which is Toggl's convention for a currently running timer. The actual duration is calculated when you call the stop_timer action.
Expected result: Lovable creates and deploys the toggl-proxy Edge Function. You can verify it exists by checking Cloud → Logs where the function will appear in the functions list.
Build the time tracking UI with start/stop controls
Build the time tracking UI with start/stop controls
With the Edge Function deployed, ask Lovable to build the frontend timer interface. This includes a project selector populated from your Toggl projects, a description input field, a start/stop button, and a live elapsed time counter that updates every second while a timer is running. The frontend calls the Edge Function for all Toggl operations — it never communicates with the Toggl API directly. The UI should handle three states: idle (no timer running, showing Start button), running (timer active, showing elapsed time and Stop button), and loading (API call in progress). The running timer display should poll the 'get_current_entry' action every 30 seconds to stay in sync with any external Toggl clients the user might also have open.
Build a time tracking page that uses the toggl-proxy Edge Function. At the top show a 'Current Timer' section: a dropdown to select a Toggl project (populated by calling the Edge Function with action 'get_projects'), a text input for a description, and a large Start Timer button. When a timer is running, replace the Start button with a Stop button and show the elapsed time in HH:MM:SS format updating every second. Below the timer section show a 'Today's Entries' list that fetches time entries for today using action 'get_time_entries' with today's date as start_date and end_date. Show each entry with its project name, description, and duration formatted as hours and minutes. At the bottom show the total hours logged today. Use a clean card layout with the timer section prominently displayed.
Paste this in Lovable chat
Pro tip: Toggl's API returns time entry durations as seconds when positive (completed entries) or as a negative Unix timestamp when the timer is running. Convert negative durations with: Math.floor(Date.now() / 1000) + duration to get elapsed seconds.
Expected result: A time tracking page renders with a project dropdown, description field, and Start Timer button. After loading projects from Toggl, the dropdown populates with your real project names.
Add weekly report dashboard with charts
Add weekly report dashboard with charts
Extend the app with a reports page that displays weekly time summaries pulled from the Toggl Reports API. This gives you a management-level view of where time is being spent without requiring anyone to log into Toggl directly. The reports endpoint returns aggregated totals by project, which you can display as a bar chart and a sortable summary table. Ask Lovable to create a separate route for the reports dashboard. The page should default to the current week (Monday to Sunday) and allow navigation to previous weeks using back/forward arrows. The summary data from the Toggl Reports API groups hours by project and includes sub-groupings by time entry description, giving you granular insight into task-level time allocation.
Create a Reports page accessible from a tab in the navigation. Show a date range header defaulting to the current Monday through Sunday. Add back/forward arrow buttons to navigate between weeks. When the page loads or the week changes, call the toggl-proxy Edge Function with action 'get_weekly_report' passing start_date and end_date as ISO date strings. Display the results as: 1) A large total hours number at the top of the page. 2) A horizontal bar chart showing hours per project using shadcn/ui chart components. 3) A table below with columns for Project, Hours, and Percentage of Total, sorted by hours descending. Show a loading skeleton while data is fetching. Handle the case where no entries exist for a week with a friendly empty state message.
Paste this in Lovable chat
Pro tip: The Toggl Reports API returns time in milliseconds (ms) rather than seconds. Divide by 3,600,000 to convert to hours. For complex reporting cases, RapidDev's team can help configure advanced Toggl API integrations including multi-user workspace reports and custom date aggregations.
Expected result: A reports page shows your current week's time data as a bar chart and summary table. Clicking the back arrow loads the previous week's data.
Common use cases
Freelancer billing dashboard with one-click time logging
Build a dashboard where you start a timer on a client project with a single click, see the running elapsed time update live, and stop it when the session ends. Each completed entry is stored in Toggl and your Lovable app shows a daily summary of billable hours per client, making it easy to generate invoices at the end of the month.
Create a time tracking dashboard connected to Toggl Track. Show a list of my Toggl projects in a dropdown. Add a 'Start Timer' button that creates a new time entry via the Edge Function with the selected project and a description field. Show the elapsed time for any currently running entry. Add a 'Stop' button that patches the running entry with the stop time. Below the timer, show today's completed entries grouped by project with total hours.
Copy this prompt to try it in Lovable
Team productivity report page with weekly summaries
Create an internal reporting page that pulls weekly time summary data from the Toggl Reports API for a given workspace. Display a bar chart of hours per day, a breakdown table by project, and a productivity score based on hours logged versus a weekly target. Useful for team leads who want to review utilization without logging into Toggl directly.
Build a weekly productivity report page that fetches time report data from Toggl via our Edge Function. Show the current week's total hours in a large number at the top. Add a bar chart with hours per day Monday through Friday. Below that show a table with columns for Project, Hours This Week, and Percentage of Total. Add a date range picker so I can switch between weeks. Pull the data from the Toggl Reports API summary endpoint.
Copy this prompt to try it in Lovable
Project time budget tracker with alerts
Build a project management view that shows each active Toggl project alongside a configurable hour budget stored in your Supabase database. As time entries are logged in Toggl, the integration fetches project totals and displays a progress bar. When a project reaches 80 percent of its budget, the card turns yellow; at 100 percent it turns red, giving project managers instant visibility into overruns.
Create a project budget tracking page. Fetch all active projects from Toggl via the Edge Function proxy and display each as a card. For each project show the total hours logged this month pulled from the Toggl Reports API. Add a 'Set Budget' input on each card that saves a monthly hour budget to Supabase. Show a progress bar comparing logged hours to the budget. Color the card yellow when over 80 percent and red when over 100 percent of budget.
Copy this prompt to try it in Lovable
Troubleshooting
Edge Function returns 403 Forbidden when calling the Toggl API
Cause: The HTTP Basic auth header is malformed. This typically happens when the API token or the literal string 'api_token' is not formatted correctly before Base64 encoding, or when the secret name in Deno.env.get() does not exactly match the name stored in Cloud → Secrets.
Solution: Open Cloud → Secrets and verify the secret is named exactly TOGGL_API_TOKEN with no spaces or extra characters. In the Edge Function code, confirm the auth string is constructed as apiToken + ':api_token' (colon then the literal text 'api_token'). The final encoded value should look like 'Basic ' followed by a long Base64 string. You can test the token manually by calling the Toggl API from the Toggl website's own documentation page to confirm the token is valid.
1const authHeader = 'Basic ' + btoa(apiToken + ':api_token');start_timer returns 400 Bad Request with 'workspace_id is required'
Cause: The time entry creation payload is missing the workspace_id field or it is being sent as a string instead of an integer. The Toggl API v9 requires workspace_id as a number in the POST body.
Solution: Ensure the TOGGL_WORKSPACE_ID secret contains only the numeric ID with no extra characters. In the Edge Function, parse it with parseInt(workspaceId) before including it in the request body. Also verify that the start field is a valid ISO 8601 timestamp string — Toggl rejects malformed date strings.
1workspace_id: parseInt(workspaceId, 10),get_weekly_report returns empty data even though entries exist in Toggl
Cause: The Toggl Reports API v3 uses a different date format than the core API. It expects dates as 'YYYY-MM-DD' strings without time components, and the date range must be inclusive of both endpoints. Additionally, the workspace ID in the reports URL path must match the workspace where entries were logged.
Solution: Format your start_date and end_date as 'YYYY-MM-DD' strings (e.g., '2026-03-23' not '2026-03-23T00:00:00Z'). Confirm the workspace ID used in the reports URL matches the workspace shown in Toggl's workspace settings. If you have multiple workspaces, make sure you are querying the correct one.
1const startDate = new Date(date).toISOString().split('T')[0]; // '2026-03-23'Running timer elapsed time display gets out of sync after a few minutes
Cause: The frontend calculates elapsed time from the start time stored in local state, but if the browser tab is backgrounded or the system clock drifts, the displayed time diverges from Toggl's server-side record. The initial start time may also be affected by timezone offset handling.
Solution: Store the timer's start time as a UTC ISO string from the Toggl API response and calculate elapsed seconds using Date.now() minus the parsed start time in milliseconds. Poll the 'get_current_entry' Edge Function action every 60 seconds to re-sync the start time from Toggl's server. Ensure you handle the timezone conversion correctly — Toggl stores times in UTC.
1const elapsedSeconds = Math.floor((Date.now() - new Date(entry.start).getTime()) / 1000);Best practices
- Never put your Toggl API token in frontend code or Lovable's chat prompt — always store it in Cloud → Secrets and access it exclusively through Edge Functions.
- Use the 'get_current_entry' action to check for a running timer when your app loads, so the UI correctly shows a running state if the user started a timer from the Toggl mobile app or website.
- Implement optimistic UI updates for the start/stop actions — update the local UI state immediately while the Edge Function call completes in the background to avoid the button feeling unresponsive.
- Cache the project list in component state or Supabase after the first fetch and refresh it only when the user explicitly requests it, since projects change infrequently and the Toggl API has rate limits.
- When displaying time durations, always normalize from Toggl's seconds-based format to human-readable HH:MM format before rendering — avoid showing raw second counts to users.
- Set a reasonable polling interval (30-60 seconds) for the current running entry rather than very short intervals, to avoid hitting Toggl's API rate limits during long work sessions.
- Use Toggl's project color field (returned in the projects list) to color-code time entries and report bars — this matches what users see in the native Toggl app and makes the integration feel familiar.
Alternatives
Clockify is a free-tier-first alternative to Toggl with a similar REST API structure, making it a good choice if cost is the primary concern and you need unlimited users on the free plan.
Harvest combines time tracking with invoicing in a single platform, making it a better fit if you need to generate client invoices directly from tracked time rather than just reporting.
Everhour integrates natively with project management tools like Asana and Trello and is a stronger choice if you want time tracking embedded directly inside your existing task management workflow.
Frequently asked questions
Does the Toggl integration work with the free Toggl plan?
Yes, the Toggl API v9 is available on all plan tiers including the free Starter plan. The API token and workspace ID work the same way regardless of your subscription. Some report endpoints may return less data on the free plan if certain features are gated, but the core time entry and project endpoints are universally available.
Can I track time for multiple Toggl workspaces from one Lovable app?
Yes, but you need to handle workspace selection in your app. The Toggl API endpoints are workspace-scoped, so you can store multiple workspace IDs and pass the selected one to the Edge Function as part of the request payload rather than reading it only from the environment variable. Update the Edge Function to accept an optional workspace_id in the payload that overrides the default from secrets.
How do I show time entries from all team members in a shared workspace?
The /workspaces/{wid}/time_entries endpoint returns entries for all workspace members when called with admin credentials. Replace the /me/time_entries endpoint with /workspaces/{workspaceId}/time_entries in the Edge Function's get_time_entries action and add user_ids as an optional filter in the query parameters. The API token used must belong to a workspace admin.
Why does my running timer show the wrong elapsed time when I first open the app?
This is usually a timezone issue. Toggl stores all timestamps in UTC, so when you parse the start time you must treat it as UTC. Use new Date(entry.start).getTime() to get the UTC millisecond timestamp, then subtract from Date.now() which is also UTC. Avoid any local timezone conversion when calculating elapsed time.
Can I connect Toggl to my Supabase database to persist entries locally?
Yes, and this is a useful pattern for building offline-capable dashboards. After fetching time entries from the Toggl API, the Edge Function can upsert them into a Supabase table using the Supabase admin client. This creates a local cache that your app can query even when the Toggl API is slow or unavailable, and enables complex SQL queries and joins that the Toggl API does not support natively.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation