Skip to content
notionsolutions

A practical library for building,
organizing and working in Notion.

Workflow guides

Notion Time Tracking: Log Hours per Client with Buttons, Formulas or a Tracker

Notion has no timer property, so time tracking means a Time entries database with Start and End dates, a dateBetween formula for minutes, rollups for project totals and Start and Stop buttons that fill in the time. Here's where that's enough and when Toggl or Everhour should hold the hours.

Published
White ceramic strips with steel start and end clips, each wired to one blue-edged frosted glass block, beside a stopwatch with a plain dial
Each work session gets its own row, and the project adds up the minutes you bill from.

Notion doesn't have a timer property or a button that counts time for you. Instead you log Start and End times in a database and let a formula add them up, add Start and Stop buttons that fill those times in, or use a tracker's extension that puts its timer on Notion pages. For a freelancer billing a few clients, I'd use the buttons, because the hours sit on the project records you invoice from. Pick a tracker for several timers at once, approved timesheets or invoicing from tracked hours.

If you've kept Toggl open next to Notion because Notion has no clock, this guide shows what the Notion-only setup can replace and where it stops: the database, the four formulas, the totals per project and client, the buttons, and the point where a tracker earns its place.

Pick the route that matches how you bill

All three routes end with minutes per work session that add up to hours per project. They differ in who presses the clock and where the hours are stored.

Three ways to track time with Notion, compared on what matters for billing
QuestionManual Start and End entriesStart and Stop buttonsExtension tracker
How a session startsYou type Start and End into a new row.A button adds the row and fills Start with the current time.A tracker button on the Notion page starts that tracker's timer.
Where the hours liveNotion propertiesNotion propertiesIn the tracker, unless you sync them back to Notion
Several timers at onceRows are independent, so nothing stops you.One running timer in the simple version; Matthias Frank adds a "This page" filter so Stop ends only the current page's timer.Frank's Toggl-to-Notion sync is his route when a team needs several timers.
Billing totalsRollups, column sums and a Billed checkboxRollups, column sums and a Billed checkboxThe tracker's own reports; Everhour says it turns tracked time into invoices.
Notion planNo button or automation needed. Free includes one chart.Buttons work on every plan. Notion flags Send mail to and Send webhook as paid-only, not the two actions used here.Depends on the tracker. Frank notes parts of his Toggl workflow may need a paid Toggl plan.
Main failureAn End left on the wrong day gives a negative duration.A forgotten Stop leaves a session running.Project totals in Notion stay empty, and Toggl maps only the task name from Notion.

I'd build the manual version first, on one project, and add the buttons once its totals match what you expected. The buttons only fill in two dates. If a formula is wrong, they just produce wrong numbers faster.

Build a Time entries database with one row per session

Keep sessions in their own database rather than adding Start and End dates to the project itself. A project gets worked on many times, and a single date range on the project page can hold only one of those sessions. With a row per session, you keep every block of work, and you can mark Tuesday's session billed without touching Wednesday's.

  1. Create a database called Time entries. Name each row after the work, such as "Homepage copy, round 2".
  2. Create Start and End as Date properties and switch on Include time for both. A Notion Date property accepts a date or a date range, and Include time lets you "choose an exact time, not just a day."
  3. Add Project, a Relation to your Projects database. Limit it to 1 page so a session can't land on two projects, and switch on Show on Projects so each project lists its own sessions. Both settings are in the relation setup Notion describes.
  4. If you plan to use buttons, add Timer, a Select property with the options Running and Stopped. Manual entries can skip it.
  5. Add Billed, a Checkbox you tick once a session is on an invoice.
  6. Finish with the formula properties Minutes, Hours and Billed minutes from the next section.

Relate sessions to the record you bill against. I'd relate them to the project, because that's where a fixed fee, a budget or an invoice usually attaches. If you don't have a Projects database tied to Clients yet, the client project tracker setup builds one, and the relations and rollups guide explains the two-way link.

You can relate sessions to Tasks instead if you prefer starting a timer from a task, but know the limit before you build. Notion's help answers "Can I rollup a rollup?" with "Unfortunately not," so a task's total won't roll up a second time into its project.

Three linked tables: Time entries with Start, End, Project, Timer, Billed and formula fields, Projects summing Minutes logged, and Clients totaled through a filtered Projects view
Minutes roll up once, to the project; client totals come from a filtered Projects view.

Turn Start and End into minutes, hours and billable time

Minutes are the number you keep. Hours, billable quarter hours and the clock-style display are all built from it.

Minutes

if(empty(prop("End")), 0, dateBetween(prop("End"), prop("Start"), "minutes"))

In Notion's formula reference, dateBetween "Returns the difference between two dates," and "minutes" is one of its units. Put End first. The reference's own example with the later date first returns 357; with the earlier date first, its range example returns -365. The empty() check covers a session that's still running: empty() returns true for an empty value, so the row shows 0 until it has an End.

Hours

round(prop("Minutes") / 60, 2)

With two arguments, round() rounds to that many decimal places; the reference's example is round(1.234, 2) = 1.23.

Billed minutes

ceil(prop("Minutes") / 15) * 15

ceil() "Returns the smallest integer greater than or equal to the number," so any started quarter hour counts as a full one. Swap in floor() to round down, or round() for the nearest quarter. The formula handles the arithmetic; whether a 7-minute call goes on the invoice as 15 minutes is a call for you and your contract, not for Notion.

Clock-style display (optional)

let(m, prop("Minutes"), format(floor(m / 60)) + ":" + if(m % 60 < 10, "0", "") + format(m % 60))

let() stores Minutes under the short name m, the % operator gives the remainder (the reference shows 5 % 10 = 5), and format() "Returns the value formatted as text." The if() adds the leading zero, so 7 minutes reads 0:07 rather than 0:7. Frank's tutorial shows his own version built from floor() and format(). The result is text, and Notion's Sum calculation for rollups works only on Number properties, so keep rolling up Minutes and use this one for display. The let() and lets() guide covers the naming rules.

If the editor rejects a formula with a type error, check that Start and End are Date properties and not text; the date formula errors guide walks through the fixes. Counting in minutes also sidesteps the day-counting question that the dateBetween off-by-one guide deals with.

Check the formulas against seven sample sessions

Here's what the four formulas return for seven sample sessions, worked from the documented definitions of dateBetween(), round(), ceil(), floor() and %. Times are entered to the minute, and the last two rows show the two mistakes you'll meet most: an End left on the wrong day and a timer still running.

Seven sample sessions run through the Minutes, Hours, Billed minutes and clock-style formulas
Session (Start to End)MinutesHoursBilled minutesClock-style
Mon 9:00 AM to 9:07 AM70.12150:07
Mon 9:30 AM to 10:22 AM520.87600:52
Tue 1:00 PM to 2:45 PM1051.751051:45
Tue 11:40 PM to Wed 12:25 AM450.75450:45
Wed 4:10 PM to 4:31 PM210.35300:21
Tue 11:40 PM to Tue 12:25 AM (End left on Tuesday)-1395-23.25-1395Fix the End date first
Running (End empty)0000:00

I'd leave the clock-style column alone on a negative row. Notion's reference shows no example of % on a negative number, and the row needs a corrected End anyway.

Total the hours on projects and clients

In Projects, add a Rollup called Minutes logged: pick the Time entries relation, the Minutes property and the Sum calculation, which "Computes the sum of the numeric properties for related pages." Then add a formula round(prop("Minutes logged") / 60, 2) for hours, since the formula reference lists rollups among the properties a formula can read.

Client totals need one more step because Notion won't roll up a rollup. Open a Projects table view filtered to one client and use Calculate on the Minutes logged column, then Sum; Notion's help shows this column calculation working on rollup columns in tables and boards. If you want the number on the client record itself, add a Client relation to Time entries as well and roll that up, at the cost of one more field to fill on every session.

Two more views on Time entries cover most billing questions. An Unbilled view filtered to Billed unchecked, with a Sum calculation on Billed minutes, shows what's ready to invoice. A view filtered to the week you're reviewing, with a Sum on Minutes, shows where the week went. The guide to database views for client work helps you pick layouts and filters, and the weekly review dashboard is a natural home for the weekly view.

For a chart, build it on Time entries, not on Projects. Notion's chart axes can't show rollups, so hours per day come from Start on the X axis and the Hours formula, summed, on the Y axis. Free workspaces can create one chart and paid plans unlimited, and a chart displays "up to 200 groups and 50 subgroups at a time (for example, 200 days on the X-axis)." If a rollup shows 0 or a number you can't explain, the rollup troubleshooting guide traces the source value and relation.

One export detail matters if you build invoices in a spreadsheet: when you export Time entries as CSV, Notion says relation properties "export as plain text URLs," so the Project column arrives as links rather than project names.

Add Start and Stop buttons

Notion's buttons are available on all plans. The two actions this setup uses are Add page to, which "will add a page to a database of your choosing, and edit the properties of that page," and Edit pages in, which "will edit pages and properties in a database of your choosing." In a button's fields, @ inserts a date, person, page or group, and ∑ creates a formula.

Matthias Frank's time-tracking tutorial builds both buttons inside a template of the database you track time for, which here is Projects. Following his recipe with this article's property names:

  1. Open a Projects template, type / and select Button. Name it Start.
  2. Choose Add page to and pick Time entries. Set Start to the current time, Project to the page you're on, and Timer to Running. Frank's version fills Start "with the current time." Button fields accept a ∑ formula, and now() returns the current date and time, so now() in the Start field does that job.
  3. Add a second button named Stop. Choose Edit pages in, pick Time entries and filter it to entries where Timer is Running. Set End to the current time and Timer to Stopped.
  4. Optionally add a linked view of Time entries to the template, filtered to the current page, so each project shows its own sessions. Frank does this in his template.

The Stop filter decides how many timers you can run. Frank's update notes that buttons now support a "This page" filter that stops only the timers connected to the current page, and that "Without that filter, clicking the button will stop all running timers, which means you can only have one timer running at a time." For a solo freelancer I'd keep the one-timer version: you bill one block of work at a time, and a Stop that ends everything never leaves a second timer running by accident.

Two settings break this recipe quietly. Don't select a database template inside the Start button's Add page to action, because Notion's troubleshooting says "The values from the template overwrite the values from the button." And the person clicking needs edit rights: Notion says that when a button adds or edits a page in a database, "the person who clicks the button must be an editor of the target database." If a subcontractor logs time as a guest, check their access to Time entries first; the guest vs member guide explains which role fits.

If you're unsure whether a click or a rule should stamp the time, the buttons vs. database automations guide compares the two.

Two panels: a Stop button filtered only to running entries stops all three sessions, while one also filtered to the current page stops only the Homepage copy session
Without the This page filter, one Stop click ends every running timer in Time entries.

Let an automation stamp the time on a paid plan

If you'd rather change Timer from a table or board than click a button, a database automation can fill in End for you. Notion says database automations are available on paid plans, and they can be created by paid plan users with full access to the database. Guests can't create them.

The setup is one trigger and one action. On Time entries, click the lightning bolt at the top of the database and choose New automation, set the trigger to Property edited with Timer set to Stopped, and add the action Edit property to fill End with a ∑ formula such as now(). The trigger, action and exception guide helps you decide which rows it should skip.

Two limits shape this. A button that creates a page also triggers database automations, so if you keep the Start button and add a Page added automation, pick one of them to stamp Start. And the recurring Every {frequency} trigger works with every action except Edit property, so a nightly rule can't close a forgotten timer. The Running view stays your check.

When an extension tracker is the better home for your hours

An extension tracker turns the question around: the clock and the hours stay in the tracker, and Notion supplies the page you click from.

The Toggl browser extension adds a timer to Chrome and other Chromium-based browsers and puts a Toggl button inside tools like Jira, GitHub, Zendesk and Notion. You have to enable each integration in the extension's Integrations tab before the button appears. For Notion, the extension maps the task name only, so an entry carries the task name and not your Notion project, client or tags. Toggl's docs say each mapping is a JSON definition you can edit from the extension's side panel if you want more.

Toggl's Q4 2024 update added pages such as Notion to auto-tracking: you choose how long you need to be on a page before tracking starts, and it stops when you close the tab. I'd review auto-tracked entries before billing them, because a tab left open keeps the timer going whether or not you're working. The same update added timesheet approvals with a way to spot overlapping time entries, on Toggl's Premium and Enterprise plans.

Everhour's Notion integration page says its controls "appear directly in the Notion interface," with a timesheet button for starting timers and adding time to tasks. By Everhour's own description, it sets hourly, fixed-fee or non-billable billing with budget limits, can auto-stop timers when a budget is exceeded, and exports invoices to QuickBooks or Xero. Only people on your Everhour team who installed its browser extension see the time data in Notion, so a client viewing a shared page won't. Clockify and TMetric describe the same pattern on their own Notion pages: an extension adds a timer button to Notion pages, and the reports stay in their apps.

In every one of these, the hours belong to the tracker. Frank's second method syncs them back with Toggl and Make, which he says "supports multiple timers running at the same time," while noting that parts of the workflow may require a paid Toggl plan.

For a solo freelancer who invoices from Notion, I'd stay with buttons. For a team that needs approved timesheets or invoices generated from tracked hours, I'd choose the tracker and let Notion hold the work rather than the clock.

What a Notion timer widget can and can't do

A Notion timer widget is a web page placed on your Notion page with an Embed block: choose Embed from the + menu and paste the widget's link. Notion embeds content from "over 1,900 domains via the Iframely service," and a site that blocks embedding shows a Failed to Load error. Notion's embed help also says embeds that require login to an external site won't work in the desktop or mobile apps, and that Iframely and the embedded app may receive viewers' IP addresses, which is worth knowing before you put one on a page a client opens.

A widget shows its own clock next to your work. It doesn't write a Start or End into your Time entries properties, so nothing it counts reaches your rollups. For hours you can bill from, use the buttons or a tracker integration.

Start with one project this week

Build Time entries with Start, End, Project and the Minutes formula, then log one project's sessions by hand for a week. When that project's Minutes logged matches the hours you'd have billed, add the Start and Stop buttons to the Projects template and the Hours and Billed minutes formulas to every row. If the week shows you need two timers at once or timesheets someone else approves, move the clock to a tracker and keep Notion for the work itself. If you'd rather start from a ready-made template, the freelancer templates shortlist covers the cost and access checks before you import one.

Turn tracked time into project data