# Dropbox Tag Sync Bring Dropbox web tags down to your computer so you can search for tagged files in Finder (macOS) or File Explorer (Windows) as if they were first-class local tags. ## The problem this solves Dropbox lets you add **tags** to files from its web interface. Those tags live in Dropbox's cloud metadata — they are *not* stored inside the files themselves. The Dropbox desktop app syncs file **contents**, but it does not copy tags onto your local files. As a result, tags you rely on for search and organization show up on dropbox.com but are invisible to Finder, Spotlight, File Explorer, and Windows Search. This tool closes that gap. It connects to Dropbox, reads each file's tags, and writes them to your local files in a form your operating system treats as a first-class tag. ## Quick start ``` pip install -r requirements.txt python tagsync.py wizard ``` That's it. The wizard detects your OS, finds your Dropbox folder, walks you through creating a read-only Dropbox access token, previews what will be tagged, applies the tags, and offers to install a background scheduler so new tags keep flowing down automatically. Everything after that is optional — if you want to re-run a sync, check status, or manage the schedule, use the other subcommands below. ## Requirements - **Python 3.9+** - The packages in `requirements.txt` (`pip install -r requirements.txt`) - **Windows only:** [ExifTool](https://exiftool.org/) on your `PATH` ## What's in this repo | File / folder | Purpose | | ------------------------ | ------------------------------------------ | | `tagsync.py` | Single CLI entry point | | `tagsync/` | Package with all the logic | | `requirements.txt` | Python dependencies | | `README.md` | This document | Inside `tagsync/`: | File | Purpose | | ------------------------- | --------------------------------------------- | | `wizard.py` | Interactive setup flow | | `core.py` | Dropbox listing, tag fetching, sync loop | | `config.py` | Settings file + secure token storage | | `detect.py` | OS / Dropbox folder / dependency detection | | `platform_macos.py` | Finder-xattr writer + launchd scheduler | | `platform_windows.py` | ExifTool-based XMP writer + Task Scheduler | ## Commands All commands are run as `python tagsync.py `. | Command | What it does | | ------------------------------ | ---------------------------------------------------- | | `wizard` | Interactive setup (run this first) | | `run` | Perform a one-shot sync using saved settings | | `run --dry-run` | Show what would change without touching any files | | `status` | Show config, token presence, and schedule state | | `schedule install` | Install the background scheduled task | | `schedule install --interval 30` | Install, running every 30 minutes | | `schedule uninstall` | Remove the background scheduled task | | `schedule status` | Show whether the scheduler is installed and loaded | | `reset --all` | Clear stored token, settings, and local state DB | | `reset --token` | Clear only the token | ## How it works 1. You create a Dropbox access token with **read-only** metadata scope. The wizard walks you through this. The token lives in your OS keyring (macOS Keychain or Windows Credential Manager). 2. The tool lists every file in your Dropbox and asks Dropbox which tags each file has. 3. For files whose tags have changed since the last run, it writes those tags to the local copy. 4. A small SQLite cache remembers what was written so subsequent runs only touch files whose tags actually changed. Nothing is ever deleted from Dropbox. The tool only **reads** from Dropbox and **writes** to local files on your machine. ## The important platform difference macOS and Windows store "file tags" in fundamentally different ways, and that shapes what happens under the hood. ### macOS — clean and invisible macOS has a universal, built-in tag system. Tags are stored in an **extended attribute** (`xattr`) alongside the file, not inside it. The tool writes the xattr directly. Consequences: - Every file type can be tagged (text, zip, source code, anything). - The file's contents are untouched, so Dropbox does **not** see the file as modified and does **not** re-upload it. - The file's modification time does not change. ### Windows — embeds tags into the file Windows has no universal tag store. The "Tags" field in Explorer is actually the **XMP:Subject** metadata field embedded inside the file. This is a limitation of the operating system, not the tool. Consequences: - Only file formats that support XMP (images, PDFs, Office docs, most audio and video) can be tagged. The tool skips unsupported formats by default and can optionally write a `.tags.json` sidecar next to them instead. - Because the tag lives inside the file, writing it **does** modify the file. Dropbox will notice and re-upload the file once. After that first sync, tags are stored in both the cloud and the local copy, and future runs only touch files whose Dropbox tags change again. - If Dropbox Smart Sync leaves some files online-only, tagging one would trigger a download. The tool can skip online-only files (on by default in the wizard). > **Plan for the first Windows run.** If there are many tagged files, > the first run will queue a large number of re-uploads as each file > gets its tags embedded. Schedule it overnight, on a good connection, > and expect a one-time spike in Dropbox activity. Subsequent runs are > quiet. ## One-time Dropbox app setup The wizard will open this page and walk you through it, but for reference: 1. Go to and click **Create app**. 2. Choose: - **Scoped access** - **Full Dropbox** - A name of your choosing (e.g. `tag-sync`) 3. Open the **Permissions** tab and enable: - `files.metadata.read` 4. Click **Submit**. 5. On the **Settings** tab, scroll to **OAuth 2 → Generated access token** and click **Generate**. Paste that token into the wizard. The generated token only has permission to read file metadata. It cannot modify anything in Dropbox even if it leaked. ## Where things are stored | Item | Location | | ------------------ | ---------------------------------------------------- | | Token (preferred) | macOS Keychain / Windows Credential Manager | | Token (fallback) | `~/.dropbox_tag_sync/token` (mode 0600) | | Settings | `~/.dropbox_tag_sync/config.json` | | Local state cache | `~/.dropbox_tag_sync/state.db` | | Log (macOS) | `~/Library/Logs/dropbox-tag-sync.log` | | launchd plist | `~/Library/LaunchAgents/com.dropboxtagsync.agent.plist` | | Windows task | Task Scheduler, name: `DropboxTagSync` | ## Troubleshooting **"not found locally"** — the file exists in Dropbox but hasn't synced down yet. Let Dropbox finish syncing, or (on Windows) mark the file as "always keep on this device" if it's online-only. **Windows tags don't show up in Explorer after a run** — Explorer's Tags column may be hidden; right-click a column header and add **Tags**. Windows Search may need a few minutes to re-index. **"exiftool not found"** — install it from and confirm `exiftool -ver` works in a terminal. **The state cache got into a weird state** — run `python tagsync.py reset --state`. The next run will re-examine every file; no data is lost. **The token is wrong or revoked** — run `python tagsync.py reset --token`, then `python tagsync.py wizard` to enter a new one. ## Safety summary - **Read-only** with Dropbox (token scope: `files.metadata.read`). - **Non-destructive on macOS**: only extended attributes are written. - **Content-modifying on Windows**: rewrites the XMP metadata section of supported files (one-time re-upload per tagged file is expected). - **Idempotent**: safe to run as often as you like. - **Resumable**: if interrupted, the next run picks up where it left off. - **One-way**: tags flow cloud → local only. Tagging on the web is still the source of truth.