Connect Bubble to Clockify using the API Connector plugin with a custom X-Api-Key header (not Bearer). Clockify has two separate API surfaces: the main CRUD API for time entry management and a Reports API for pre-aggregated summaries via POST. Build a team time-tracking dashboard with date-range reporting — Clockify's unlimited-user free tier makes this the most cost-effective internal tool option in this category.
| Fact | Value |
|---|---|
| Tool | Clockify |
| Category | Productivity |
| Method | Bubble API Connector |
| Difficulty | Intermediate |
| Time required | 2–3 hours |
| Last updated | July 2026 |
Build a Clockify team dashboard in Bubble without coding
Clockify's appeal for early-stage teams is its completely free unlimited-user tier — everyone tracks time at no cost. But the built-in Clockify dashboard is generic. Building a Bubble app on top of Clockify's API lets you create a custom view: show each team member's hours for the current sprint, compare billable vs. non-billable time by project, or display weekly summaries alongside your CRM data.
The key insight that makes this integration non-obvious for Bubble beginners: Clockify has two separate API base URLs and authentication headers. The main API (`api.clockify.me/api/v1`) handles CRUD operations on time entries, projects, users, and workspaces. The Reports API (`reports.api.clockify.me/v1`) returns pre-aggregated summaries that would otherwise require summing thousands of individual time entries in Bubble workflows — a slow and WU-expensive approach.
Another non-obvious detail: Clockify uses `X-Api-Key` as the authentication header, not the standard `Authorization: Bearer`. Using the wrong header name is the single most common reason the integration fails during setup. This tutorial shows you exactly how to configure both API groups with the correct header format and build a working dashboard with aggregated reports.
Integration method
Clockify's main API and Reports API via Bubble API Connector with a custom X-Api-Key header marked Private. Two separate API Connector groups are needed — one for each API base URL.
Prerequisites
- A Clockify account (free tier works for the main API; API access is available on all plans)
- The Clockify workspace ID — visible in the URL bar when you open Clockify: app.clockify.me/tracker (the segment after /tracker is not the workspace ID; look at your workspace URL in Settings → Workspace Settings)
- The API Connector plugin installed in your Bubble app (Plugins tab → Add plugins → search 'API Connector' by Bubble)
- Basic familiarity with Bubble's workflow editor, repeating groups, and input elements
Step-by-step guide
Get your Clockify API key and workspace ID
Log into Clockify and navigate to your profile by clicking your avatar in the top-right corner → Profile Settings. Scroll to the bottom of the Profile Settings page and look for the 'API' section. Click 'Generate' to create your API key and copy it immediately. Your Clockify workspace ID is found separately. Go to Settings → Workspace Settings in the left sidebar. The workspace ID appears in the browser URL bar as `app.clockify.me/settings/{workspaceId}`. Copy and save this ID — you will need it in every API call path. Note that the API key is personal to your account. If you are building a team dashboard, you can use your own key to access workspace-wide data (as long as your account has workspace admin permissions). For apps where individual users log their own time, each user would need to provide their own API key.
Pro tip: Store the workspace ID in a Bubble option set or as a hidden input element on your page so you can reference it in multiple API calls without hardcoding it in each call configuration.
Expected result: You have a Clockify API key (40-character hex string) and your workspace ID ready. Both are saved somewhere accessible during the Bubble setup process.
Create the Clockify Main API Connector group
In your Bubble app, open the Plugins tab and confirm the API Connector plugin (by Bubble) is installed. Click 'Add another API' and name it 'Clockify Main'. IMPORTANT: Set the authentication type to 'No authentication' — do not use 'Bearer' or 'Basic Auth'. Instead, manually add a custom header. Click 'Add shared header for all calls' and enter: - Key: `X-Api-Key` - Value: your Clockify API key - Tick the 'Private' checkbox Clockify specifically requires the header name to be `X-Api-Key` — using `Authorization: Bearer your_key` causes a 401 error on every request. This is the single most common setup mistake for this integration. Set the base URL to `https://api.clockify.me/api/v1`. Add a Content-Type header: `Content-Type: application/json` (mark this one as non-private since it is not sensitive).
1{2 "api_name": "Clockify Main",3 "base_url": "https://api.clockify.me/api/v1",4 "headers": [5 {6 "key": "X-Api-Key",7 "value": "<private>",8 "private": true9 },10 {11 "key": "Content-Type",12 "value": "application/json",13 "private": false14 }15 ]16}Pro tip: The X-Api-Key header name is case-sensitive on some server configurations. Enter it exactly as shown with the capital A and K — X-Api-Key — not X-API-Key or x-api-key.
Expected result: The 'Clockify Main' API group appears in your API Connector list with the X-Api-Key header showing a Private lock icon.
Add and initialize the projects and users calls
Inside the Clockify Main API group, click 'Add another call'. Name it 'Get Projects'. Set method to GET and path to `/workspaces/{workspaceId}/projects`. Add a path parameter: workspaceId (text, static — enter your actual workspace ID as the default value, or make it dynamic if the workspace ID varies). Click 'Initialize call'. Bubble sends the real GET request and Clockify returns a JSON array of project objects. Bubble detects fields including id, name, hourlyRate, clientId, and color. Set 'Use as' to 'Data' and tick 'List'. Add a second call: 'Get Users'. Path: `/workspaces/{workspaceId}/users`. Initialize with your workspace ID. This populates a team member dropdown for filtering the reports view. For time entries, add call 'Get Time Entries': path `/workspaces/{workspaceId}/user/{userId}/time-entries` with both workspaceId and userId as parameters. Note that time entry durations return as ISO 8601 format strings (e.g., `PT2H30M` meaning 2 hours 30 minutes). In Bubble, display these in a text element using the raw string for now — Step 6 handles formatting.
1GET https://api.clockify.me/api/v1/workspaces/{workspaceId}/projects2X-Api-Key: <private>34GET https://api.clockify.me/api/v1/workspaces/{workspaceId}/users5X-Api-Key: <private>67GET https://api.clockify.me/api/v1/workspaces/{workspaceId}/user/{userId}/time-entries8X-Api-Key: <private>Pro tip: Running time entries (ones that have not been stopped yet) have a null duration field. Add a conditional in your repeating group: 'When current cell's time entry's timeInterval duration is empty, display Running… in orange text instead of a duration.'
Expected result: Three initialized calls appear in the Clockify Main group. The projects call returns your workspace projects, users call returns team members, and time-entries call returns individual log entries with ISO 8601 duration strings.
Create the Clockify Reports API Connector group
The Reports API is a completely separate base URL and requires its own API Connector group. Click 'Add another API' again and name it 'Clockify Reports'. Add the same X-Api-Key private header as before (the same API key works for both APIs). Set the base URL to `https://reports.api.clockify.me/v1`. Add a call named 'Summary Report'. Set method to POST — this is critical. The Reports API endpoint is POST, not GET. Bubble beginners commonly configure this as GET and receive empty results with no error message. Set the path to `/workspaces/{workspaceId}/reports/summary`. Add workspaceId as a path parameter. Set the body type to 'JSON' and add the request body: Initialize the call with real values: use a date range from last week to today, and a grouping that suits your dashboard. After initialization, Bubble detects the response fields including totals and groupOne items. Set 'Use as' to 'Data' — not a list, since the summary report returns a single object with nested groupings.
1POST https://reports.api.clockify.me/v1/workspaces/{workspaceId}/reports/summary2X-Api-Key: <private>3Content-Type: application/json45{6 "dateRangeStart": "<dateRangeStart>",7 "dateRangeEnd": "<dateRangeEnd>",8 "summaryFilter": {9 "groups": ["USER", "PROJECT"]10 },11 "exportType": "JSON"12}Pro tip: The dateRangeStart and dateRangeEnd values must be in ISO 8601 format: '2026-07-01T00:00:00Z'. In Bubble, format date picker values using the 'formatted as' operator with format string 'YYYY-MM-DDTHH:mm:ssZ' before passing them to the API call.
Expected result: The 'Clockify Reports' group has an initialized Summary Report POST call. Bubble shows the response structure including totals.totalTime, groupOne array, and individual member/project breakdown data.
Build the team timesheet repeating group
On your Bubble page, add two Date/Time Picker inputs: 'Week Start' and 'Week End'. Set their default values to the start and end of the current week using Bubble date expressions. Add a Repeating Group. Set its data source to 'Get data from an external API → Clockify Reports - Summary Report'. Pass the date picker values as dateRangeStart and dateRangeEnd parameters (formatted as ISO 8601 strings). Inside the repeating group cell, add: - Text element: current cell's data's groupOne's name (user name) - Text element: current cell's data's duration formatted (note: report durations come back in seconds as an integer — divide by 3600 to display hours) - A horizontal bar element (a resizable Group with background color) whose width is a percentage of the max hours in the dataset To show the hours-worked bar proportionally, set the Group width condition: '(current cell's groupOne's duration / max(all groupOne durations)) * 100' as a percentage. Bubble's expression editor supports basic math operations. Add a 'Refresh' button that triggers the API call to reload when the date range changes.
Pro tip: Clockify's summary report 'duration' values in the response are in seconds (integer). Convert to hours by dividing by 3600. To display as 'Xh Ym', use Bubble's math: hours = floor(duration/3600), minutes = floor((duration mod 3600)/60). Display as concatenated text: hours:value + 'h ' + minutes:value + 'm'.
Expected result: The repeating group displays team members with their total hours for the selected date range. Changing the date pickers and clicking Refresh re-runs the Reports API call and updates the display.
Handle pagination and add project-filter dropdown
Clockify's main API paginates time entries at a maximum of 200 entries per page (page-size parameter). For teams with high time entry volume, you need pagination. On Bubble's free plan, display only the first page (add `page-size=200` and `page=1` as query params). On paid plans, use a Backend Workflow loop to fetch subsequent pages. For the dashboard filter, add a Dropdown element above the repeating group with its choices set to 'Get data from an external API → Clockify Main - Get Projects'. Show the project name field as the display. When the user selects a project, re-run the Summary Report call with an additional filter in the request body: Also add an 'All Projects' option (value: empty string) that removes the project filter. For the project breakdown view, add a second repeating group below the summary that shows individual time entries for the selected user and project using the Clockify Main 'Get Time Entries' call. RapidDev's team has built time-tracking dashboards exactly like this for multiple Bubble clients — if you want a custom solution with multi-workspace support or Stripe billing integration, book a free scoping call at rapidevelopers.com/contact.
1// Reports API body with project filter2{3 "dateRangeStart": "<dateRangeStart>",4 "dateRangeEnd": "<dateRangeEnd>",5 "summaryFilter": {6 "groups": ["USER", "PROJECT"],7 "filterGroupIds": ["<projectId>"]8 },9 "exportType": "JSON"10}Pro tip: Backend workflow pagination for Clockify requires Bubble's Starter plan. For teams with fewer than 200 time entries per reporting period (most early-stage teams), the single-page approach works fine and avoids the paid plan requirement.
Expected result: The dashboard has a project filter dropdown. Selecting a project re-runs the summary report filtered to that project. The time entries repeating group shows individual log lines for the selected user and project with ISO 8601 durations converted to human-readable format.
Common use cases
Weekly team hours dashboard by project
Build a Bubble page that shows each team member's logged hours for the current week grouped by project. Use the Clockify Reports API POST call with a JSON body specifying the date range and groupBy settings. Display the results in a repeating group with team member names and hours per project — no manual summing required.
Create a Bubble page with a date range picker. When the date range changes, call the Clockify Reports API: POST https://reports.api.clockify.me/v1/workspaces/{workspaceId}/reports/summary with a JSON body containing dateRangeStart, dateRangeEnd, and groupings for user and project. Display results in a repeating group showing user name, project name, and total duration in hours.
Copy this prompt to try it in Bubble
Time entry creation widget embedded in a Bubble CRM
Embed a Clockify time-logging widget directly into a Bubble CRM or project portal. Team members can select a project from a dropdown (populated from the Clockify projects endpoint) and log time without opening the Clockify app. The POST /time-entries call creates the entry on their behalf using their own API key.
Add a 'Log Time' panel to a Bubble project record page. Include a project dropdown populated by GET https://api.clockify.me/api/v1/workspaces/{workspaceId}/projects. Add start time, end time inputs, and a description text input. On submit, call POST /workspaces/{workspaceId}/time-entries with a JSON body. Show a success message on completion.
Copy this prompt to try it in Bubble
Billable hours report for client invoicing
Create a Bubble report page that totals billable hours by client for a selected date period, ready to reference when generating invoices. Use the Clockify Reports API detailed report endpoint to pull billable time entries grouped by client. Display a summary table with project name, billable hours, and estimated invoice amount based on a rate input.
Build a Bubble page with a month picker and a rate-per-hour number input. Call the Clockify Reports API summary endpoint with billable=true filter. Display a repeating group grouped by project showing total billable hours, and calculate the invoice subtotal by multiplying hours by the rate input.
Copy this prompt to try it in Bubble
Troubleshooting
All API calls return 401 Unauthorized
Cause: The API key is invalid, expired, or configured with the wrong header name. The most common cause is using 'Authorization: Bearer' instead of 'X-Api-Key' as the header name.
Solution: Open your Clockify Profile Settings → API section and verify your API key. In the Bubble API Connector, confirm the header key is exactly 'X-Api-Key' (not 'Authorization', not 'X-API-Key'). Regenerate the API key in Clockify if needed and update the header value in Bubble.
The Summary Report POST call returns empty results or a 400 error
Cause: The Reports API call is configured as GET instead of POST, or the request body is missing or malformed. The Reports API requires POST with a JSON body containing dateRangeStart, dateRangeEnd, and summaryFilter.
Solution: In the Bubble API Connector call for Summary Report, confirm the method is set to POST (not GET). Confirm the body type is 'JSON' and the body contains valid JSON with dateRangeStart and dateRangeEnd fields in ISO 8601 format (e.g., '2026-07-01T00:00:00Z'). Use Bubble's 'Initialize call' to send a test request and confirm a valid response.
Initialize call fails with 'There was an issue setting up your call'
Cause: Bubble's API Connector requires a real successful response to detect field structure. This error appears when the API returns an empty response, a non-200 status, or when the call parameters are incomplete during initialization.
Solution: Enter valid static default values for all parameters before initializing. For the workspace ID parameter, enter your actual workspace ID as the default value. For date range parameters in the Reports API, enter real ISO 8601 date strings (e.g., '2026-07-01T00:00:00Z' and '2026-07-07T23:59:59Z'). Bubble must receive a real JSON response with data to detect field names.
Running time entries show null or blank duration in the repeating group
Cause: Active (currently running) Clockify time entries have no end time and therefore no calculated duration — the timeInterval.end and timeInterval.duration fields are null.
Solution: Add a conditional to the duration text element in your repeating group: 'When this element's data source's timeInterval duration is empty, display Running… instead of the duration value.' Use a different text color (orange) to visually distinguish active from completed entries.
Backend workflow pagination is greyed out or unavailable
Cause: Backend Workflows (API Workflows) are a paid Bubble feature not available on the Free plan.
Solution: Upgrade to Bubble's Starter plan ($32/mo) to access Backend Workflows. As a workaround on the free plan, add page-size=200 to your time entries call and accept the 200-entry limit for the initial display. For the Reports API, pagination is less of an issue since the summary endpoint aggregates data server-side.
Best practices
- Use the X-Api-Key header name exactly as written — case and hyphen placement matter. Mark it Private in Bubble API Connector so it stays server-side.
- Create two separate Bubble API Connector groups: one for api.clockify.me (CRUD) and one for reports.api.clockify.me (aggregated reports). Mixing them in one group causes URL conflicts.
- Prefer the Clockify Reports API for dashboard summaries instead of fetching all individual time entries and summing them in Bubble workflows. The Reports API is faster and uses far fewer Workload Units.
- Format date inputs as ISO 8601 strings before passing them to the Clockify API. Use Bubble's 'formatted as' date expression with format 'YYYY-MM-DDTHH:mm:ssZ'.
- Handle null duration values for running time entries with a Bubble conditional — show 'Running…' text instead of blank. This prevents confusing gaps in your repeating group.
- Add Privacy Rules (Data tab → Privacy) to any Clockify data you store in Bubble's database, restricting access to authenticated users with appropriate roles.
- For pagination, limit initial loads to the first 200 entries using page-size=200 and use a 'Load more' button that increments the page parameter rather than auto-loading all pages — this controls WU consumption and keeps page load fast.
Alternatives
Harvest includes time tracking plus built-in invoicing, expense tracking, and team billing rate management. Clockify's core advantage is its completely free unlimited-user tier. If your Bubble app needs to generate invoices or manage billable rates per client, Harvest is worth the cost. If you want a free time-tracking backend for a Bubble internal tool, Clockify is the better fit.
Asana is a full project management platform (timelines, dependencies, portfolios) with time tracking as a secondary feature via integrations. Clockify is purpose-built for time tracking. For Bubble apps focused on task and project management, use Asana; for apps focused purely on time logging and reporting, Clockify is simpler to integrate.
Notion is a workspace platform that includes database views usable for simple time tracking. Its API is significantly more complex than Clockify's for time-specific use cases. Clockify is the better choice when time tracking and reporting is the core feature; Notion is better when time tracking is one column in a broader project or knowledge management database.
Frequently asked questions
Why do I need two separate API Connector groups for Clockify?
Clockify has two completely separate API servers with different base URLs: api.clockify.me for CRUD operations (creating, reading, updating time entries, projects, and users) and reports.api.clockify.me for aggregated report data. Bubble API Connector groups are scoped to one base URL, so you need two separate groups. Both groups use the same X-Api-Key authentication header.
What is ISO 8601 duration format and how do I display it in Bubble?
Clockify returns individual time entry durations as ISO 8601 duration strings like PT2H30M (2 hours 30 minutes) or PT45M (45 minutes). Bubble cannot directly parse this format into numbers. To display hours and minutes, either use the Reports API which returns durations in seconds (divide by 3600 for hours), or use Bubble's text operators to extract the number between 'H' and the end of the string. For display purposes, the Reports API seconds-based format is far easier to work with.
Does Clockify's free plan include API access?
Yes. Clockify's REST API is available on all plans including the free tier. The free plan supports unlimited users and unlimited time tracking. Some advanced features like custom fields and SSO require paid plans, but the core time entries, projects, users, and reports endpoints are accessible with a free account.
Can multiple Bubble users log their own time using their own Clockify accounts?
Yes, but you need to collect and store each user's API key securely in Bubble. Create a Bubble User data type field (type: text, name: clockify_api_key) and let users enter their own key in their profile settings. When making Clockify API calls, dynamically pass the current user's API key as the X-Api-Key header value. Note: storing API keys in Bubble user records requires robust privacy rules to prevent key exposure.
How do I get pre-aggregated team reports instead of summing thousands of individual time entries?
Use the Clockify Reports API (reports.api.clockify.me) instead of the main API. The Summary Report endpoint accepts a POST request with a date range and grouping settings, and returns pre-computed totals — total hours per user, per project, or per client. This is much faster than fetching all individual time entries and summing them in Bubble workflows, and it uses far fewer Workload Units.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation