{"id":13495171,"url":"https://github.com/arabcoders/watchstate","last_synced_at":"2026-02-01T17:07:34.811Z","repository":{"id":37006731,"uuid":"457795171","full_name":"arabcoders/watchstate","owner":"arabcoders","description":"Self-hosted service to sync your plex, jellyfin and emby play state. without relying on 3rd-party external services.","archived":false,"fork":false,"pushed_at":"2026-01-23T10:10:11.000Z","size":13040,"stargazers_count":1247,"open_issues_count":1,"forks_count":18,"subscribers_count":9,"default_branch":"master","last_synced_at":"2026-01-24T02:41:54.950Z","etag":null,"topics":["backup","docker","emby","jellyfin","matched","misidentified","mismatched","plex","watchstate","webhook"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arabcoders.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-02-10T13:39:00.000Z","updated_at":"2026-01-24T02:27:41.000Z","dependencies_parsed_at":"2025-12-19T02:05:30.941Z","dependency_job_id":null,"html_url":"https://github.com/arabcoders/watchstate","commit_stats":null,"previous_names":[],"tags_count":257,"template":false,"template_full_name":null,"purl":"pkg:github/arabcoders/watchstate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arabcoders%2Fwatchstate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arabcoders%2Fwatchstate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arabcoders%2Fwatchstate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arabcoders%2Fwatchstate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arabcoders","download_url":"https://codeload.github.com/arabcoders/watchstate/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arabcoders%2Fwatchstate/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28983495,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-01T16:29:42.054Z","status":"ssl_error","status_checked_at":"2026-02-01T16:29:41.428Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backup","docker","emby","jellyfin","matched","misidentified","mismatched","plex","watchstate","webhook"],"created_at":"2024-07-31T19:01:31.938Z","updated_at":"2026-02-01T17:07:34.803Z","avatar_url":"https://github.com/arabcoders.png","language":"PHP","readme":"# WatchState\n\n![Build Status](https://github.com/arabcoders/WatchState/actions/workflows/build.yml/badge.svg)\n![MIT License](https://img.shields.io/github/license/arabcoders/WatchState.svg)\n![Docker pull](https://img.shields.io/docker/pulls/arabcoders/watchstate.svg)\n![ghcr pull](https://ghcr-badge.elias.eu.org/shield/arabcoders/watchstate/watchstate)\n\nThis tool primary goal is to sync your backends **users** play state without relying on third party services, out of the\nbox, this tool support `Jellyfin`, `Plex` and `Emby` media servers.\n\n# Updates\n\n### 2025-10-29\n\nAfter more than **3.5 years**, **2.2k+ commits**, **900+ stars**, and **1 million+ downloads**, we’re happy to announce\nthe first stable release of **WatchState v1.0.0**.\n\nThis milestone marks the project’s maturity and reliability for production use. We extend our thanks to everyone who\nprovided feedback, reported bugs, and helped refine the tool your input has been invaluable.\n\nThe current feature set and stability meet our goals, so future work will focus on **maintenance and bug fixes**.\nFeedback and suggestions remain welcome, but **major new features** may be limited as we prioritize **stability and\nlong-term reliability**.\n\nPlease refer to [NEWS](/NEWS.md) for the latest updates and changes.\n\n------\n\n# Features\n\n* **Sub-users** support. `Multi-users`.\n* Sync backends play state (`many-to-many` or `one-way`).\n* Backup your backends play state into `portable` format.\n* Receive [webhook](guides/webhooks.md) events from media backends.\n* Find `un-matched` or `mis-matched` items.\n* Search your backend metadata.\n* Check if your media servers reporting same data via the parity checks.\n* Sync your watch [progress/play](FAQ.md#sync-watch-progress) state via webhooks or scheduled tasks.\n* Check if your media backends have stale references to old files.\n\nIf you like my work, you might also like my other project [YTPTube](https://github.com/arabcoders/ytptube), which is\nsimple and to the point yt-dlp frontend to help download content from all supported sites by yt-dlp.\n\n# Install\n\nIf you prefer video format [AlienTech42 YouTube Channel](https://www.youtube.com/@AlienTech42) had a video about\ninstalling WatchState using unraid [at this link](https://www.youtube.com/watch?v=XoztOwGHGxk). Much appreciated.\n\nPS: I don't know the channel owner, but I appreciate the effort. There is small mistake in the video regarding the\nwebhook URL, please copy the URL directly from the backends page. And this tool does support multi-users.\n\n----\n\nFirst, start by creating a directory to store the data, to follow along with this setup, create directory called `data`\nat your working directory. Then proceed to use your preferred method to install the tool.\n\n### Via compose file.\n\ncreate your `compose.yaml` next to the `data` directory, and add the following content to it.\n\n```yaml\nservices:\n    watchstate:\n        image: ghcr.io/arabcoders/watchstate:latest\n        # To change the user/group id associated with the tool change the following line.\n        user: \"${UID:-1000}:${UID:-1000}\"\n        container_name: watchstate\n        restart: unless-stopped\n        ports:\n            - \"8080:8080\" # The port which the watchstate will listen on.\n        volumes:\n            - ./data:/config:rw # mount ./data in current directory to container /config directory.\n```\n\nNext, to run the container, use the following command\n\n```bash\nmkdir -p ./data \u0026\u0026 docker compose up -d\n```\n\n### Via docker command.\n\n```bash\nmkdir -p ./data \u0026\u0026 docker run -itd --name watchstate \\\n          --user \"${UID:-1000}:${GID:-${UID:-1000}}\"  \\\n          --restart unless-stopped -p 8080:8080 \\\n          -v ./data:/config:rw \\\n          ghcr.io/arabcoders/watchstate:latest\n```\n\n\u003e [!IMPORTANT]\n\u003e It's really important to match the `user:`, `--user` to the owner of the `data` directory, the container is rootless,\n\u003e as such it will crash if it's unable to write to the data directory.\n\u003e\n\u003e It's really not recommended to run containers as root, but if you fail to run the container you can try setting the\n`user: \"0:0\"` or `--user '0:0'` if that works it means you have permissions issues. refer to [FAQ](FAQ.md) to\n\u003e troubleshoot the problem.\n\n### Unraid users\n\nFor `Unraid` users You can install the `Community Applications` plugin, and search for  **watchstate** it comes\npreconfigured. Otherwise, to manually install it, you need to add value to the `Extra Parameters` section in advanced\ntab/view. add the following value `--user 99:100`.\n\nThis has to happen before you start the container, otherwise it will have the old user id, and\nyou then have to run the following command from terminal `chown -R 99:100 /mnt/user/appdata/watchstate`.\n\n### Podman instead of docker\n\nTo use this container with `podman` set `compose.yaml` `user` to `0:0`. it will appear to be working as root inside the\ncontainer, but it will be mapped to the user in which the command was run under.\n\n# Management\n\nAfter starting the container, you can access the WebUI by visiting `http://localhost:8080` in your browser.\n\n\u003e [!NOTE]\n\u003e Note, For the first time, you will be prompted to create a new system user, this is a one time operation.\n\nTo add your backends, please click on the help button in the top right corner, and choose which method you\nwant [one-way](guides/one-way-sync.md) or [two-way](guides/two-way-sync.md) sync. and follow the instructions.\n\nOnce you have added your backends and imported your data you should see something like\n\n![WebUI](/screenshots/index.png)\n\n### Supported import methods\n\nCurrently, the tool supports three methods to import data from backends.\n\n- **Scheduled Tasks**.\n    - `A scheduled job that pull data from backends on a schedule.`\n- **On demand**.\n    - `Pull data from backends on demand. By running the import task manually.`\n- **Webhooks**.\n    - `Receive events from backends and update the database accordingly.`\n\n\u003e [!NOTE]\n\u003e Even if all your backends support webhooks, you should keep import task enabled. This help keep healthy relationship\n\u003e and pick up any missed events. For more information please check the [webhook guide](/guides/webhooks.md) to\n\u003e understand webhooks limitations.\n\n# FAQ\n\nTake look at this [frequently asked questions](FAQ.md) page, or the [guides](/guides/) for more in-depth guides on how\nto configure things.\n\n# Social channels\n\nIf you have quick questions or would like to chat with other users, you can join\nthe [Discord server](https://discord.gg/haUXHJyj6Y). Please note that this is a solo project, so replies may take some\ntime. I’m based in the `UTC+3` timezone.\n\n# Donate\n\nIf you’d like to show appreciation for my work, please note that I don’t accept donations. Instead, I encourage you to\ndonate to a children’s charity of your choice. For\nexample, [The International Make-A-Wish foundation](https://worldwish.org).\n","funding_links":[],"categories":["PHP","docker"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farabcoders%2Fwatchstate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farabcoders%2Fwatchstate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farabcoders%2Fwatchstate/lists"}