WorkestraDocs
PlatformTime Tracking

Calendar Import

Connect Google Calendar or Microsoft 365 — meeting events appear as ghost blocks on your week, one click converts them into tracked time entries.

Calendar Import

The single biggest reason to abandon a standalone tracker like Toggl: your meetings already live in Google Calendar. Time Tracking syncs them in as ghost blocks on the calendar view, and a + convert button turns each meeting into a tracked entry with the right project, contact, and description pre-filled.

Calendar view with ghost blocks

Screenshot needed — /time/timer Calendar view with semi-transparent ghost blocks for unconverted Google Calendar events, hover state showing the '+ convert' CTA.

Connect a calendar

  1. Open /time/settings/integrations.
  2. Under External Calendars, click Connect on Google Calendar or Outlook (Microsoft 365). iCal subscription is also supported.
  3. OAuth in the standard flow, grant read access to your primary calendar (and any others you want to sync).
  4. Within ~1 minute, your last 7 days of events appear in the Calendar view at /time/timer?view=calendar.

The same OAuth connection is shared with the Scheduling module — if you've connected your calendar there, no separate setup is needed.

How events become entries

Calendar events from your connected calendars render as semi-transparent ghost blocks in the Calendar view, anchored to the event's actual start/end times. They're visibly different from real time entries:

Visual signalMeans
Solid colored blockReal time entry (already tracked)
Ghost / striped blockConnected-calendar event, not yet converted
Dimmed ghostEvent you've explicitly dismissed (one-time)

Hover any ghost block → a + convert button appears. Click it → a small dialog opens with:

  • Description pre-filled from the event title
  • Entity pre-filled if any attendee email matches a CRM contact (suggests the contact's open deal)
  • Start / end copied from the event
  • Billable toggle defaulted from your workspace setting
  • Tag chips empty by default

Confirm → a new time_entries row is created with source = 'imported'. The ghost block on the calendar turns into a solid block.

Auto-tagging from attendees

When you convert an event, the import bridge inspects the attendee list:

  • For each attendee email, look up crm_contacts.email in the workspace.
  • If exactly one contact matches, suggest that contact in the entity picker.
  • If the contact has an open deal, suggest the deal as the entity (more specific than the contact).
  • If no attendees match, no suggestion (the picker stays open for you to choose).

This is a heuristic — you always confirm before the entry is created.

Dismissing events

Some calendar entries aren't time-trackable: standups, lunch, all-day events, OOO. Click Dismiss on a ghost block to hide it. Dismissed events stay hidden across refreshes and are excluded from the convert flow.

You can un-dismiss from /time/timer?view=calendar → settings dropdown → "Show dismissed events".

Sync schedule

Calendar imports are refreshed by a daily cron (4 AM workspace-local). The cron pulls the rolling last 7 days for every user with a connected calendar. New events added after the last sync show up at the next refresh.

To force a sync now: open the Calendar view and click the refresh icon next to the week navigator.

What gets stored

A time_calendar_imports row carries:

ColumnMeaning
providergoogle / m365 / ical
external_calendar_idThe connected calendar
external_event_idThe source event id (so we don't re-import)
title, started_at, ended_at, attendees, location, descriptionSnapshotted from the event
time_entry_idSet when you convert, links to the created time_entries row
dismissed_atSet when you dismiss the event

Already-imported events (with time_entry_id set) are skipped on subsequent syncs even if the source event was edited. Edit the linked time entry directly if the meeting changed.

Privacy

Connected calendars are per-user, not per-workspace. Your calendar data is visible only to you in /time/timer?view=calendar — teammates don't see your meetings. The only data that lands in the workspace is what you explicitly convert into a time entry.

You can revoke access any time from /time/settings/integrations → External Calendars → Disconnect.


Next steps

  • Timer — the composer + Calendar / List / Timesheet views
  • Integrations — webhooks, AI tools, public REST API