Weekly
Turn your week's calendar into a timesheet by client
Every Friday your calendar events are sorted by client or project and written to your timesheet sheet with the hours for each.
- Runs
- Weekly
- Apps
- Google Calendar, Google Sheets
- AI
- Yes, uses the built-in AI allowance
- Access
- Calendar read; Sheets edit (only the sheets you pick when connecting)
Send this to your assistant
Create a ClickRuntime automation: every Friday, read my Google Calendar for the week, assign each event to a client or project, and add the hours to my Timesheet sheet.
First time? Adding ClickRuntime to your assistant takes about two minutes.
Why use it
Why teams use this automation
A freelance consultant bills four clients by the hour. Her calendar shows exactly where the time went, but each Friday she rebuilds it into a timesheet by hand and still forgets the short calls, which adds up to unbilled hours every month.
Turning the calendar you already keep into timesheet rows, sorted by client, means billable time is captured without a separate tracking habit.
What you get out of it
Short calls get billed too
Every event is counted, including the 15-minute catch-ups that tend to fall off a hand-written timesheet.
No separate time tracker
Your calendar is already the record of your week. There is no timer to start or forget.
Invoices are quicker to prepare
Hours grouped by client in a sheet can be totalled and copied straight into an invoice.
A record you can show a client
Each row has the date, meeting title and duration, which answers most questions about a bill.
How it works
What happens, step by step
Every Friday afternoon ClickRuntime reads your Google Calendar events for the past week.
It leaves out all-day events, declined invitations and private events.
AI assigns each event to one of your clients or projects, and the length of each event is worked out.
Each event is added as a row in your Timesheet sheet with the date, title, client and hours.
Before it runs live
- Connect Google Calendar
- Connect your Google Sheets account and pick the spreadsheets it may use
What you get
Build your own
Need it to work differently?
Your own rules
Conditions, thresholds, filters and exceptions, written the way you'd explain them to a colleague.
Any number of apps
One automation can read from one app and update several others. Over 248 apps are ready, and anything with an API works too.
AI where it helps
Summaries, classification, extraction and drafts use ClickRuntime's built-in AI, with no extra key.
On a schedule or on each event
Runs as often as every 5 minutes, or the moment an app sends an event, and keeps track of what it already handled.
Changes you can ask for
- Run it at a different time, more or less often, or only on weekdays
- Change what the AI looks for, or how it writes the result
- Add another app, for example also send it to Slack
- Combine it with other Google Calendar and Google Sheets steps into one automation
Under the hood
The code that runs this automation
from datetime import datetime, timedelta, timezone
from clickruntime import on_trigger, credentials, http, ai
SHEET, CLIENTS = "your-spreadsheet-id", ["Northwind", "Acme", "Contoso", "Internal"]
@on_trigger
def run(event):
h = {"Authorization": f"Bearer {credentials.connection('google', 'work')}"}
end = datetime.now(timezone.utc)
events = http.get("https://www.googleapis.com/calendar/v3/calendars/primary/events", headers=h, params={
"timeMin": (end - timedelta(days=7)).isoformat(), "timeMax": end.isoformat(), "singleEvents": True}).json().get("items", [])
events = [e for e in events if "dateTime" in e.get("start", {}) and e.get("visibility") != "private"]
if not events:
return {"rows": 0}
lines = "\n".join(f"{i}. {e.get('summary', '')} | {', '.join(a['email'] for a in e.get('attendees', []))}" for i, e in enumerate(events))
labels = ai.generate(f"Clients: {', '.join(CLIENTS)}. For each numbered event reply one client per line, or unassigned.\n{lines}",
max_output_tokens=20 * len(events)).text.strip().splitlines()
rows = []
for i, e in enumerate(events):
s, f = datetime.fromisoformat(e["start"]["dateTime"]), datetime.fromisoformat(e["end"]["dateTime"])
client = labels[i].split(". ", 1)[-1].strip() if i < len(labels) else "unassigned"
rows.append([s.date().isoformat(), e.get("summary", ""), client, round((f - s).total_seconds() / 3600, 2)])
http.post(f"https://sheets.googleapis.com/v4/spreadsheets/{SHEET}/values/Timesheet!A:D:append", headers=h,
params={"valueInputOption": "USER_ENTERED"}, json={"values": rows})
return {"rows": len(rows)}FAQ
Common questions
How does it know which client an event belongs to?
Does it count personal events?
Can I review it before invoicing?
What permissions does it need?
Does it need AI?
How many runs does it use?
Can I change how it works?
Related
You might also like
Schedule backlog refinement meetings from your sheet
Before each sprint, the top backlog items are picked from your sheet and refinement meetings are put in the team's calendars.
See how it worksSchedule study sessions around your calendar until the exam
Your syllabus topics are turned into study sessions placed in your free time, all finished before the exam date.
See how it worksPut birthdays, anniversaries and probation dates on the calendar
Birthdays, work anniversaries and probation end dates from your employee sheet appear as calendar events ahead of time.
See how it worksKeep exploring
Set up “Turn your week's calendar into a timesheet by client” from your assistant
Copy the prompt above, or connect your assistant first. Free plan, no credit card.