> For the complete documentation index, see [llms.txt](https://wiki.crosswatch.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wiki.crosswatch.app/crosswatch/providers/synchronization/adapter-plex.md).

# Adapter: Plex

Plex adapter lets CrossWatch (CW) sync with Plex. It supports watchlist, history, ratings, and progress. It prefers stable external IDs.

{% hint style="info" %}
Connect Plex first. Use: [Plex (Authentication provider)](/crosswatch/providers/authentication/auth-media-servers/auth-plex.md).
{% endhint %}

### What it supports

* Direction: source or target in a pair (one-way or two-way)
* Features:
  * **Watchlist** (via Plex Discover)
  * **History** (via Plex Media Server)
  * **Ratings** (via Plex Media Server)
  * **Progress** (resume position)
  * **Playlists** (not supported)
* Indexing: present-state snapshot (reads “what exists now”)

### How matching works

CW tries to match by provider IDs first.

* Watchlist: GUID / external IDs from Plex Discover
* History + ratings: PMS items enriched with external IDs when available

{% hint style="warning" %}
Strict ID matching is the default.

If external IDs are missing, CrossWatch usually prefers a missing peer over a wrong match.

Enable the experimental fallback only if you accept the trade-offs.
{% endhint %}

### Watchlist behavior

* Read: pulls your watchlist from **Plex Discover**.
* Write: add/remove via Discover actions.
* No fuzzy title matching.

### History behavior

* Read: PMS play history for the selected user.
* Write:
  * Add = mark watched (Plex uses current server time)
  * Remove = unscrobble

{% hint style="warning" %}
Plex has no supported way to **backdate** a play.

If CrossWatch writes **History** into Plex, Plex records `watched_at` as **now**.

This affects history sync and **History** capture restores.
{% endhint %}

{% hint style="info" %}
Plex has “play history” and “marked watched”. Marked watched is optional and add-only. See below.
{% endhint %}

### Ratings behavior

* Read: scans libraries and keeps items with `userRating`.
* Write:
  * Add = rate (1–10)
  * Remove = clear rating (rating 0)

### Progress behavior

* Read: current resume position for items with progress.
* Write: set resume position (“Continue Watching”).
* Clear: not supported by Plex.

Related: [Progress](/crosswatch/configure-pairs/features/progress.md).

### Settings (advanced)

<details>

<summary>Common keys and knobs</summary>

Workers:

* `plex.rating_workers` (1–64)
* `plex.history_workers` (1–64)

Library filters:

* `plex.ratings.libraries` (section IDs)
* `plex.history.libraries` (section IDs)

Watchlist:

* `plex.watchlist_query_limit`
* `plex.watchlist_write_delay_ms`
* `plex.watchlist_allow_pms_fallback`

History:

* `plex.history_ignore_local_guid`
* `plex.history_ignore_guid_prefixes` (example: `local://`)
* `plex.history_require_external_ids`
* `plex.history.include_marked_watched`

Experimental:

* `plex.fallback_GUID`

</details>

<details>

<summary>Marked Watched (Plex “checkmark”) behavior</summary>

Plex has two different signals:

* **Play history**: real play events
* **Marked watched**: manual “mark as watched” state

If `plex.history.include_marked_watched = true`:

* CW also scans your libraries for items Plex considers watched
* It merges those into history **only if Plex provides a timestamp** (`lastViewedAt` / `viewedAt`)

This is **add-only**:

* Mark watched in Plex → can sync out
* Unmark watched in Plex → CW will **not** unwatch on other services

{% hint style="warning" %}
Marked Watched is intended for the PMS owner. it will automatically be disabled when used for home users or friends.
{% endhint %}

</details>

<details>

<summary>Experimental: GUID fallback</summary>

Fallback tries to recover IDs when PMS hydration fails (404) or IDs are missing.

Enable with `plex.fallback_GUID = true`.

The main purpose is to preserve old data once. Then you’re done.

In practice:

1. Create a temporary **Plex → provider X** pair.
2. Enable **Fallback GUID**.
3. Run sync to move the old data to provider X.
4. Remove that pair again.
5. Clean up everything.
6. Disable **Fallback GUID** in your next pair.

{% hint style="warning" %}
Enable this only temporarily.

Run it once, then disable it.

It costs extra API calls and CPU time.

It can slow runs and trigger timeouts or rate limits.
{% endhint %}

Used for:

* History rows that can’t be hydrated by `ratingKey`
* Rated items missing external IDs

Strategy (best-effort):

1. Query Plex metadata service for external IDs
2. For episodes, also hydrate the show via `grandparentRatingKey`
3. Use Discover title+year search as a last resort

To keep it fast and quiet, results are memoized:

* `/config/.cw_state/plex_fallback_memo.json`

Delete the file to force retries.

</details>

### Diagnostics

<details>

<summary>Unresolved (freeze) files</summary>

Items that can’t be matched or written are frozen to avoid repeat retries:

* Watchlist: `/config/.cw_state/plex_watchlist.unresolved.json`
* History: `/config/.cw_state/plex_history.unresolved.json`
* Ratings: `/config/.cw_state/plex_ratings.unresolved.json`

</details>

### Notes and limitations

* Prefer external IDs and stable libraries.
* Friend or shared Plex accounts need their own authenticated Plex profile.
* Selecting a friend from the owner’s Plex profile does not grant access to that friend’s personal watchlist, ratings, history, or progress data.
* Setup details: [Auth: Plex](/crosswatch/providers/authentication/auth-media-servers/auth-plex.md).
* Start one-way. Run one feature. Then expand.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wiki.crosswatch.app/crosswatch/providers/synchronization/adapter-plex.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
