Importing from Toggl, Clockify, TimeChimp and Harvest
Import time entries from Toggl Track, Clockify, TimeChimp and Harvest CSV exports: recognised columns, date and duration formats, matching to people and placements, dry run, person mapping and POST /import/time-entries.
Last updated: · Markdown version
Switching tools should not cost you your history. Export the detailed time report from your current tracker as CSV and import it. Every entry becomes a claim with source import (see sources and conflicts); entries are summed per placement per day, like every other source.
Ways to run it:
- Dashboard: "Importeren" → tab "Uren uit Toggl, Clockify, TimeChimp of Harvest". Upload (.csv or .xlsx), check the review, link unknown people, then "Importeer".
- API:
POST /import/time-entries {csv, provider?, dryRun, personMap?}(write key). See the API reference.
Recognised exports
The provider is detected from the header row; pass provider to force it. Headers are compared case-insensitively, ignoring spaces and punctuation (Duration (h) = durationh).
| Provider | Export | Columns used |
|---|---|---|
Toggl Track (toggl) |
Reports → Detailed → Export CSV | User/Member, Email, Client, Project, Task, Description, Start date, Start time, End time/Stop time, Duration (hh:mm:ss) |
Clockify (clockify) |
Reports → Detailed → Export CSV | User, Email, Client, Project, Task, Description, Start Date, Start Time, End Time, Duration (h) (hh:mm:ss) or Duration (decimal) |
Harvest (harvest) |
Reports → Detailed time → Export CSV | Date, Client, Project, Task, Notes, Hours (decimal), First Name, Last Name; Started At/Ended At when timestamp timers are on |
TimeChimp (timechimp) |
Uren → Exporteren | Dutch or English: Datum/Date, Medewerker/Employee/User, E-mailadres/Email, Klant/Customer, Project, Taak/Task, Opmerking/Notes, Starttijd/Start, Eindtijd/End, Uren/Hours (decimal) or Duur |
TimeChimp export templates vary per account, so its columns are matched by alias. If your file is not recognised, rename the headers to one of the names above. The mapping lives in @tt/core (IMPORT_PROVIDERS) as data, with fixture files and tests per provider.
Unused columns (billable, rates, tags) are listed in unmappedHeaders. Amounts are never imported.
Values
- Dates:
YYYY-MM-DD,DD-MM-YYYY,DD.MM.YYYYand slashed dates. For slashed dates the file decides: a first part above 12 means day/month, a second part above 12 means month/day. Otherwise Clockify defaults to month/day (its US default) and the others to day/month. - Times:
08:00,08:00:00, 12-hour08:00:00 PM, or ISO timestamps (the local clock time is kept). - Durations:
hh:mm(:ss)(seconds round to the nearest minute; hours may exceed 24 in totals) or decimal hours (7.5,7,50). Without a duration, minutes come from start and end (overnight when end ≤ start). Entries of 0 minutes or over 24 hours are rejected.
Matching
- Person: the explicit mapping from the review (
personMap), else the e-mail address, else the full name (accents, case and punctuation ignored; ambiguous names do not match). - Placement: the person's active placement on that date. With several, the one whose client name (or placement reference) equals the entry's client or project. A single placement is used even if the client name differs; the review then notes
opdrachtgever "X" ≠ Y. - Day: entries are summed per placement per date. Clock times are kept when all entries of the day have them: earliest start, latest end, and the gaps become the break.
Rows that do not match are listed in unmatched with a reason (Medewerker niet gevonden, Geen actieve plaatsing op deze datum, Meerdere plaatsingen; opdrachtgever niet herkend) and are skipped. Unknown people are also listed in unknownPeople; pass personMap: { "<key>": "<personId>" } and run the dry run again.
Dry run, commit and re-imports
dryRundefaults totrueand changes nothing. Each day gets a status:new,duplicate(already imported),locked(the day is exported or locked: book a correction in an open period) orerror.- With
dryRun: false,newdays are stored through the normal claim path (permission check, matching, conflicts,claim.createdwebhook) and becomeimported. - Claim ids are derived from the content (org, provider, placement, date, minutes, times), so importing the same export twice creates no duplicates. A changed entry is a new claim; the newest claim per source wins.
- Imported hours start as
draft. When the worker also logged the day in the app, a difference becomes a normal conflict. - Up to 20,000 entries (5 MB) per request.