# OpenTickly
> Compatible with the Toggl API. Your data stays yours.
OpenTickly is an open-source Toggl alternative: 100% Toggl API-compatible, one-command Docker self-hosting, your data stays yours. No seat limits — free for individuals and teams.
## Key Facts
- Website: https://opentoggl.com/
- Live demo: https://track.opentoggl.com
- Repository: https://github.com/CorrectRoadH/OpenTickly
- License: AGPL-3.0
- Install: `docker compose up -d` (Go backend, React frontend, PostgreSQL)
- API compatibility: Toggl Track v9, Reports v3, Webhooks v1
- Platforms: CasaOS, Synology, fnOS, any Docker host
- Pricing: free and open source, no seat limits, no premium tier
## Features
- **Drop-in compatible** — Works with the Toggl API. Your existing tools and integrations carry over.
- **Deploy in minutes** — One docker compose command. Runs on CasaOS, Synology, fnOS.
- **Free & open source** — No seat limits, no tiers. Self-hosted and hosted are the same product.
## FAQ
### Can it replace Toggl Track?
Yes. OpenTickly is compatible with Toggl's Track, Reports, and Webhooks APIs. If your tools talk to Toggl via its API, they should work with OpenTickly without changes.
### Can I bring my Toggl data?
Yes. You can import Toggl export files — your history comes with you.
### What do I need to self-host?
Docker. One docker compose up -d brings up the full stack (Go backend, React frontend, PostgreSQL). We also have guides for Synology, CasaOS, and fnOS.
### Are hosted and self-hosted the same?
Yes. Same code, same features. No premium tier, no feature gating.
### Why AI-friendly?
Stable API, solid docs, self-hostable. Agents and scripts can integrate without third-party rate limits getting in the way.
## Documentation
- https://opentoggl.com/docs
- https://opentoggl.com/docs/getting-started
- https://opentoggl.com/docs/migrate-from-toggl
- https://opentoggl.com/docs/api-compatibility
- https://opentoggl.com/docs/admin-email-sso
- https://opentoggl.com/docs/self-hosting
- https://opentoggl.com/docs/ai-integration
# Configure SMTP Email and SAML SSO (/docs/admin-email-sso)
Self-hosted OpenTickly stores SMTP settings at the instance level and SAML 2.0 single sign-on settings at the workspace level. Configure the public Site URL first because email links and SAML Service Provider URLs depend on it.
## Configure the public Site URL [#configure-the-public-site-url]
Sign in as an instance administrator and open **Instance Admin → Configuration**. Set **Site URL** to the public HTTPS origin users open, for example `https://time.example.com`.
Do not use an internal container hostname or append an API path. After changing the public domain, recheck email links and the SAML values shown to your identity provider.
## Configure outgoing SMTP email [#configure-outgoing-smtp-email]
In **Instance Admin → Configuration → Email / SMTP**, enter:
| Field | Meaning |
| ------------- | -------------------------------------------------------------------- |
| Sender Name | Display name shown on messages |
| Sender Email | From address accepted by your mail provider |
| SMTP Host | Mail server hostname |
| SMTP Port | Provider port; commonly `587` for STARTTLS or `465` for implicit TLS |
| SMTP Username | Account used to authenticate |
| SMTP Password | Password or provider-issued app password |
OpenTickly uses implicit TLS on port 465. On other ports it upgrades with STARTTLS when the server advertises support.
Save the settings, enter a recipient under **Send Test Email**, and send a test. The result distinguishes connection, authentication, rejected-recipient, and timeout failures so you can check the relevant provider setting or firewall rule.
SMTP is required for member invitations, password resets, and email verification. After a test message arrives, enable **Email Verification** if every newly registered user should confirm their address.
Keep SMTP credentials out of screenshots, support tickets, source control, and shared shell
history. Rotate the credential if it is exposed.
## Configure workspace SAML SSO [#configure-workspace-saml-sso]
Open **Workspace Settings → Single Sign-On** as a workspace administrator.
1. Enter a profile name and the email domain that should route to this workspace.
2. Copy the generated **Entity ID**, **ACS URL**, **Sign-in URL**, and **Metadata URL** into a new SAML application at your identity provider.
3. Prefer the identity provider's metadata URL. If it is unavailable, enter the IdP sign-in URL, entity ID, and X.509 signing certificate manually.
4. Run **Test configuration** before enabling SSO.
5. Run **Test login** with a user from the claimed domain and inspect the returned email, name, domain match, and assertion attributes.
6. Save the configuration, then enable single sign-on.
The email domain is the routing key on the public **SSO** login screen. An enabled domain can belong to only one workspace. The SAML assertion must return an email address, either through a recognized email attribute or an email-formatted NameID.
## Safe rollout checklist [#safe-rollout-checklist]
* Keep an existing password-authenticated administrator session open while testing.
* Test with a non-critical user before directing the whole domain to SSO.
* Confirm the IdP uses the exact generated Entity ID and ACS URL.
* Confirm the instance is reachable over HTTPS from users and the identity provider.
* Retest after changing the public Site URL, reverse proxy, certificate, or identity-provider metadata.
* Do not disable your fallback login method until another administrator has completed SSO successfully.
For general deployment and reverse-proxy context, see [Self-Hosting](/docs/self-hosting). For scripts and tokens, see [Toggl API Compatibility](/docs/api-compatibility).
# AI Integration (/docs/ai-integration)
Use [`CorrectRoadH/toggl-cli`](https://github.com/CorrectRoadH/toggl-cli) to hook up Claude Code, OpenClaw, Hermes Agent, Codex, Cursor and other AI agents — letting them drive your OpenTickly instance directly from the command line to auto-track time, start and stop timers, and manage projects and tags.
* `toggl` CLI — operate directly from the command line
* `SKILL.md` skill pack — install into an agent environment, one-command use
## Install [#install]
```bash
npm install -g @correctroadh/toggl-cli
npx skills add CorrectRoadH/toggl-cli
```
## Configure [#configure]
The CLI is compatible with both Toggl and OpenTickly, and defaults to the official Toggl API. To point it at your own instance, pass `--api-type opentoggl` and `--api-url` during auth:
Because Toggl has a 30 requests/hour API limit, we strongly recommend pairing the CLI with OpenTickly to unlock the full potential of AI agents:
```bash
toggl auth --api-type opentoggl --api-url https://your-instance.com/api/v9
```
You can find `YOUR_API_TOKEN` in the OpenTickly web UI under your avatar → Profile → API Token.
## References [#references]
* [`CorrectRoadH/toggl-cli`](https://github.com/CorrectRoadH/toggl-cli) repository
* `skills/toggl-cli/SKILL.md` skill pack definition
# Toggl API Compatibility (/docs/api-compatibility)
OpenTickly exposes Toggl-compatible public API surfaces so existing scripts, CLIs, and agents can use a self-hosted instance. The repository tracks the upstream Toggl Track v9, Reports v3, and Webhooks v1 contracts.
## Base URLs [#base-urls]
Replace `https://your-instance.example` with the public URL of your OpenTickly server.
| API | Base URL |
| ----------- | ----------------------------------------------- |
| Track v9 | `https://your-instance.example/api/v9` |
| Reports v3 | `https://your-instance.example/reports/api/v3` |
| Webhooks v1 | `https://your-instance.example/webhooks/api/v1` |
Use HTTPS whenever a client connects across an untrusted network. The Docker container listens behind the port you publish; TLS normally terminates at your reverse proxy.
## Get an API token [#get-an-api-token]
Sign in to the OpenTickly web app, open your avatar menu, choose **Profile**, and find **API Token**. Treat the token like a password: do not commit it, paste it into issue reports, or expose it in client-side logs.
Toggl-compatible Basic authentication uses the API token as the username and the literal value `api_token` as the password:
```bash
curl --user "${OPENTICKLY_API_TOKEN}:api_token" \
https://your-instance.example/api/v9/me
```
Set `OPENTICKLY_API_TOKEN` in your local secret manager or shell environment before running the request.
## Repoint an existing integration [#repoint-an-existing-integration]
Most clients need two changes:
1. Replace the official Toggl API host with the matching OpenTickly base URL.
2. Supply the API token created by your OpenTickly user.
For [`toggl-cli`](https://github.com/CorrectRoadH/toggl-cli), the explicit configuration is:
```bash
toggl auth \
--api-type opentoggl \
--api-url https://your-instance.example/api/v9
```
If a third-party client hard-codes Toggl's hostname and offers no base-URL setting, it cannot be repointed through configuration alone.
## Verify compatibility for your workflow [#verify-compatibility-for-your-workflow]
Compatibility is most useful when tested against the endpoints your integration actually calls. Before a production cutover:
1. Read the current user with `GET /api/v9/me`.
2. List the target workspace, projects, tags, and recent time entries.
3. Create and stop a test time entry.
4. Run the report query used by your automation.
5. Create a disposable webhook subscription if your workflow depends on webhooks.
6. Confirm error handling, pagination, dates, time zones, and token rotation.
The upstream OpenAPI files in the repository are the compatibility reference. Implementation coverage continues to evolve, so test the concrete operations your client requires and report a reproducible mismatch in [GitHub Issues](https://github.com/CorrectRoadH/OpenTickly/issues).
For unattended automation, keep the instance URL and token outside source code, give the user only the workspace access it needs, and rotate the token if it is exposed.
# Changelog (/docs/changelog)
OpenTickly ships continuously. The authoritative source of every release — with diffs, commit ranges, and upgrade notes — is GitHub Releases.
* Latest and historical releases: [github.com/CorrectRoadH/OpenTickly/releases](https://github.com/CorrectRoadH/OpenTickly/releases)
* Full commit history: [github.com/CorrectRoadH/OpenTickly/commits/main](https://github.com/CorrectRoadH/OpenTickly/commits/main)
* Docker images: [hub.docker.com/r/correctroad/opentickly](https://hub.docker.com/r/correctroad/opentickly)
## How releases are cut [#how-releases-are-cut]
OpenTickly is developed in the open on GitHub. Every release is a tagged commit on `main`, published automatically to Docker Hub and to the hosted demo at [track.opentoggl.com](https://track.opentoggl.com). Self-hosted users pull the new image and rerun `docker compose up -d` to upgrade.
## Upgrade notes [#upgrade-notes]
Most releases are drop-in compatible: the Toggl Track API surface is stable, and the Postgres schema is migrated forward automatically on startup. Breaking changes — if any — are called out in the matching GitHub Release with an explicit **"Upgrade"** section and a migration plan.
If an upgrade fails, open an issue at [github.com/CorrectRoadH/OpenTickly/issues](https://github.com/CorrectRoadH/OpenTickly/issues) with the release tag and the failing log.
## API compatibility pledge [#api-compatibility-pledge]
OpenTickly tracks the public Toggl Track v9, Reports v3, and Webhooks v1 contracts. Existing Toggl integrations, CLIs, and MCP tools should continue to work across releases without changes. When a Toggl endpoint is added or adjusted upstream, OpenTickly aims to match within the following release cycle.
# Getting Started with OpenTickly (/docs/getting-started)
This guide takes you from a blank account to a useful first report. You can explore the hosted demo first or run the same application on infrastructure you control.
## Choose how to run OpenTickly [#choose-how-to-run-opentickly]
| Option | Best for | What to do |
| ----------- | ------------------------------------------------------- | ----------------------------------------------------------------------------- |
| Hosted demo | Evaluating the interface before installing | Open [track.opentoggl.com](https://track.opentoggl.com) and create an account |
| Self-hosted | Keeping the application and database on your own server | Follow the [Docker self-hosting guide](/docs/self-hosting) |
The demo and self-hosted editions use the same core workflows. A self-hosted instance gives you control of the application, PostgreSQL database, backups, network access, and upgrade schedule.
## Create your account and workspace [#create-your-account-and-workspace]
1. Register with your name, email address, and password.
2. Open the workspace created during onboarding.
3. Check the workspace time zone before recording team activity.
4. Add a project if you want the first entry to appear in project reports.
A workspace is the reporting and collaboration boundary. Projects, clients, tags, members, billable rates, and time entries belong to a workspace.
## Record your first time entry [#record-your-first-time-entry]
1. Open **Timer**.
2. Enter a concrete description such as `Write onboarding guide`.
3. Select a project and optional tags.
4. Start the timer, then stop it when the work is complete.
Use manual mode when you already know the start and end times. The calendar and list views show the same underlying entries, so you can choose the editing style that fits the task.
## Review where the time went [#review-where-the-time-went]
Open **Reports** and choose a date range. Start with the summary view, then group or filter by project, client, user, tag, billable state, or description when you need a narrower answer.
Useful checks for a new workspace:
* Does the total match the time you expected to record?
* Are entries assigned to the correct project and client?
* Are billable and non-billable entries separated correctly?
* Do team members use the same tags for the same type of work?
## Bring existing data or integrations [#bring-existing-data-or-integrations]
* Moving from Toggl Track: follow [Migrate from Toggl to OpenTickly](/docs/migrate-from-toggl).
* Reusing a CLI, script, or agent: read [Toggl API compatibility](/docs/api-compatibility).
* Automating time capture with an agent: connect [toggl-cli and an AI agent](/docs/ai-integration).
## Recommended next steps [#recommended-next-steps]
1. Create clients and projects that match how you report work.
2. Invite teammates and verify their workspace roles.
3. Decide how the self-hosted database will be backed up.
4. Add one repeatable review habit, such as a daily timer check or weekly project report.
OpenTickly becomes more useful when descriptions, projects, and tags answer real questions. Start with the smallest structure you can apply consistently, then add detail only when a report needs it.
# What Is OpenTickly (/docs)
OpenTickly is a free, private-first, AI-friendly alternative to Toggl.
OpenTickly was previously named OpenToggl. The project has been rebranded to OpenTickly; older references to OpenToggl refer to the same project.
Toggl is a great product, but it's expensive and your data doesn't really belong to you. On top of that, the 30 requests/hour API limit is painful — an AI agent can burn through an hour's quota in a single minute.
OpenTickly aims to stay aligned with Toggl, so you can move your data in and out between the two without any loss. Keep every workflow and habit you already have. Nothing changes — it just gets better, cheaper, and more private.
## Scope of Feature Development [#scope-of-feature-development]
OpenTickly's roadmap only considers features Toggl already has, plus extensions that don't touch user data. The benefit:
* You can always walk your data back to Toggl — no vendor lock-in.
Examples: instance management, AI-related extensions. Even if a change would be useful or popular, if it would fork user data away from Toggl, it won't be accepted.
# Migrate from Toggl to OpenTickly (/docs/migrate-from-toggl)
OpenTickly provides an import workflow for moving an existing Toggl Track account without rebuilding every workspace by hand. Use the account export archive for account structure, then add detailed time-entry CSV files to the target workspace.
Keep the original export files until you have checked the imported workspaces and report totals.
An import is not a backup of the source Toggl account.
## Before you migrate [#before-you-migrate]
1. Create or sign in to the destination OpenTickly account.
2. Confirm the destination instance has enough storage for the uploaded files and PostgreSQL data.
3. Pick a cutover time so new entries are not created in both systems during validation.
4. Keep a record of the date range and workspace covered by every CSV export.
## Step 1: export your Toggl account archive [#step-1-export-your-toggl-account-archive]
Open [Toggl Track settings](https://track.toggl.com/settings) and request the account data export. Download the resulting ZIP file without changing its internal files.
The archive import creates a new organization in OpenTickly. In the OpenTickly web app:
1. Open **Import**.
2. Enter a name for the imported organization.
3. Select the Toggl export ZIP.
4. Start the import and wait for the success or failure message.
OpenTickly processes imports as jobs. Do not close the workflow or upload the same archive again while the first job is still running.
## Step 2: import detailed time entries [#step-2-import-detailed-time-entries]
Export detailed time entries from Toggl as CSV for the date ranges you need. Back in **Import**:
1. Select the destination organization and workspace.
2. Choose one or more CSV files.
3. Upload them and wait for each import job to finish.
4. Repeat for another workspace only after confirming the destination selector.
Naming files by workspace and date range, such as `consulting-2025-q4.csv`, makes missing or repeated ranges easier to spot.
## Validate the result [#validate-the-result]
Check the migration before treating OpenTickly as the system of record:
* Compare organization and workspace names.
* Open representative clients, projects, tags, and members.
* Compare a known day, week, and month in **Reports**.
* Check running entries and entries that cross midnight.
* Check billable state, duration, description, project, user, and tags on a sample of entries.
* Record any failed job message before retrying or opening an issue.
Report totals are the strongest end-to-end check because they reveal missing ranges, wrong workspace targets, and entries that were exported twice.
## Cut over safely [#cut-over-safely]
Once validation passes, tell team members which system should receive new entries. Keep the Toggl exports and a database backup of the new OpenTickly instance for a rollback window that fits your organization.
Next, read [Getting started](/docs/getting-started) for workspace habits or [API compatibility](/docs/api-compatibility) to repoint scripts and integrations.
# Practices & Workflow (/docs/practices)
Here's how the author uses OpenTickly day to day.
## Let the agent start the timer [#let-the-agent-start-the-timer]
I don't click "Start" in the Web UI. I just tell OpenClaw "I'm going to work on X," and the agent starts a time entry via [`toggl-cli`](https://github.com/CorrectRoadH/toggl-cli). I usually don't stop it manually either — when I switch tasks I say "I'm going to do something else now," and a new time entry starts, which automatically closes the previous one.
## Feed the agent your weekly plan and principles [#feed-the-agent-your-weekly-plan-and-principles]
I give the agent my personal mission, this week's goals, and my daily principles straight from Obsidian as context. So when I say "I'm going to scroll Xiaohongshu for two hours," it pushes back: "Your plan for this week is to finish feature X — are you sure you want to switch to Y?"
I also run a 4-quadrant system, so I use six tags in total: important, not important, urgent, not urgent, focused, unfocused. The AI tags the first four at the start of a task; for the last two, it asks me when the task ends whether I was focused. At the end of the day I can see the time distribution across quadrants plus my focused vs. unfocused ratio.
## A nightly cron for AI review [#a-nightly-cron-for-ai-review]
I have a cron job that pulls the day's time distribution and asks the AI for a review:
* Is the time split across quadrants (important / urgent) reasonable?
* Did I improve over yesterday or this week's average?
* Did any unexpected time sinks show up?
* Did today's work drift from this week's plan?
This would be painful on official Toggl — the 30 requests/hour API limit means one review run can easily burn the whole quota just from the AI poking around.
# Self-Hosting (/docs/self-hosting)
Running OpenTickly on your own machine only takes a single `docker-compose.yml`. Here's the full path from zero to working.
## System Requirements [#system-requirements]
* Any Linux, macOS, or Windows machine with **Docker Engine 20.10+** and **Docker Compose v2**
* About 1 GB of RAM and 1 GB of disk
* One free TCP port (default `8080`)
If you don't have Docker yet, follow the [official install guide](https://docs.docker.com/engine/install/) first.
***
## Deploy the Server [#deploy-the-server]
### Step 1 — Download `docker-compose.yml` [#step-1--download-docker-composeyml]
Create a new directory and pull down the official compose file:
```bash
mkdir -p opentickly && cd opentickly
wget -O docker-compose.yml \
https://raw.githubusercontent.com/CorrectRoadH/OpenTickly/main/docker-compose.yml
```
This compose file defines three containers:
* **OpenTickly** — Web UI + REST API (exposed on `8080`)
* **`postgres`** — Database (internal network only, not exposed)
* **`redis`** — Cache and background task queue (internal network only, not exposed)
### Step 2 — (Optional) Configure `.env` [#step-2--optional-configure-env]
Defaults work out of the box. To change the port or passwords, create a `.env` in the same directory:
```bash
# Exposed port for the web UI and API
OPENTOGGL_PORT=8080
# Strongly recommend switching to strong passwords before going to production
OPENTOGGL_POSTGRES_PASSWORD=postgres
OPENTOGGL_REDIS_PASSWORD=opentoggl
```
These three variables are the **only** overridable settings in the entire compose file — everything else (database name, user, images, internal connection strings) is hard-coded to avoid config drift. If you need deeper customization, edit `docker-compose.yml` directly.
Always change both passwords in production. The defaults are only suitable for local tinkering.
Even though Postgres/Redis don't expose ports to the host, setting passwords is basic hygiene
against lateral movement inside your network.
### Step 3 — Start the Containers [#step-3--start-the-containers]
```bash
docker compose up -d
```
***
## Access the Web App [#access-the-web-app]
Open `http://:8080` in a browser, register the first account, and start tracking time.
### Mobile [#mobile]
There's no official mobile app yet, but you can add the web UI to your phone's home screen (PWA). Third-party Toggl clients such as timery — we're currently reaching out to their developers about OpenTickly support.
***
## Hook Up AI Agents [#hook-up-ai-agents]
OpenTickly has no 30 requests/hour rate limit, which means Claude, Cursor, and similar agents can go all-in. Pair it with [`toggl-cli`](/docs/ai-integration) to install the skill pack into an agent environment, and in a few minutes you can have AI start/stop timers and tidy up projects for you.
## Upgrade [#upgrade]
```bash
docker compose pull
docker compose up -d
```
***
## Deploy to NAS / Homelab [#deploy-to-nas--homelab]
OpenTickly runs on anything that supports Docker Compose. The flows below are just the same steps wrapped in each platform's UI — the underlying commands are identical.
### CasaOS [#casaos]
1. Open the CasaOS dashboard
2. Go to **App Store** → **Custom Install** → **Import docker-compose**
3. Paste the contents of [`docker-compose.yml`](https://raw.githubusercontent.com/CorrectRoadH/OpenTickly/main/docker-compose.yml)
4. Set the **Web UI** port to `8080` and save
5. Launch from the dashboard
Access via `http://:8080`.
### ZimaOS [#zimaos]
ZimaOS (the official OS for Zimablade / Zimacube) shares the same App Store as CasaOS, so the steps are identical: **App Store** → **Custom Install** → **Import docker-compose**, then paste the compose file.
### Synology [#synology]
Synology DSM 7.2+ supports Docker Compose through **Container Manager**:
1. Open **Container Manager** → **Project** → **Create**
2. Set a project name, e.g. `opentickly`
3. Choose **Use docker-compose.yml** and paste the [compose file](https://raw.githubusercontent.com/CorrectRoadH/OpenTickly/main/docker-compose.yml)
4. Click through the wizard to finish
If `8080` conflicts with DSM, add `OPENTOGGL_PORT=9090` (or any free port) in the environment
settings before creating the project.
### fnOS [#fnos]
[fnOS](https://www.fnnas.com) ships with a built-in Docker panel:
1. Open the **Docker** app from the fnOS desktop
2. In the left sidebar, choose **Compose** → **New Project**
3. Project name `opentickly`, leave the storage path at its default
4. Paste the [compose file](https://raw.githubusercontent.com/CorrectRoadH/OpenTickly/main/docker-compose.yml) into **Compose Content**
5. Click **Deploy** and wait for all three containers to turn green
### Other Platforms [#other-platforms]
The following platforms follow the same Docker Compose flow:
* **Unraid** — Community Applications or Compose Manager plugin
* **TrueNAS SCALE** — Custom app + Docker Compose
* **Proxmox LXC** — Install Docker inside an LXC container, then follow the [Deploy the Server](#deploy-the-server) steps
***
## Configuration Reference [#configuration-reference]
The entire compose file only has three overridable settings:
| Variable | Default | Description |
| ----------------------------- | ----------- | --------------------------------------------- |
| `OPENTOGGL_PORT` | `8080` | Exposed port for the web UI and API |
| `OPENTOGGL_POSTGRES_PASSWORD` | `postgres` | Postgres password (must change in production) |
| `OPENTOGGL_REDIS_PASSWORD` | `opentoggl` | Redis password (must change in production) |
Everything else (database name, user, image tags, internal connection strings, volume names) is hard-coded in `docker-compose.yml`. If you need to change it, edit the file.
### Health Check Endpoints [#health-check-endpoints]
| Path | Purpose |
| ---------- | --------------------------------------- |
| `/readyz` | Readiness check (depends on DB + Redis) |
| `/healthz` | Liveness check (is the process running) |
***
## Next Steps [#next-steps]
* [AI Integration](/docs/ai-integration) — Connect Claude, Cursor, and friends to your own instance
* [GitHub Repository](https://github.com/CorrectRoadH/OpenTickly) — Source, Issues, Discussions
* Hitting issues during deployment? Let us know in [Issues](https://github.com/CorrectRoadH/OpenTickly/issues)