> 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/settings/synchronization/media-servers/plex.md).

# 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/settings/connections/media-servers/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.

That matters because when you later syncs history back from Plex to a tracker, CrossWatch send those Plex timestamps back to the tracker as if they were the real watch dates. This can overwrite the user’s historical watch timeline.
{% 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/settings/configure-pairs/features/progress.md).

### Friend and shared account behavior

When you select a Plex friend or shared user from the server owner’s profile, CrossWatch can try to use Plex’s server-scoped shared token for that user.

Support is limited:

* **History** — supported
* **Progress** — supported
* **Ratings** — not supported
* **Watchlist** — not supported
* **Playlists** — not supported

Ratings are blocked for shared users because Plex can return the server owner’s ratings instead of the shared user’s ratings.

Watchlist is blocked because Plex watchlist lives in account-level cloud data.

{% hint style="warning" %}
Use the owner’s Plex profile for shared-user history and progress only.

Use the friend’s own Plex login if you need watchlist or ratings.
{% endhint %}

### 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.
* If `plex.baseurl` uses `https://`, the certificate must validate correctly from the CrossWatch container. Invalid or rejected certificates can cause `HTTPSConnectionPool` or `SSLError` failures.
* Friend/shared account support is best-effort.
* Shared-user support depends on Plex’s server-scoped token behavior and may change in the future.
* Selecting a friend from the owner’s Plex profile does not grant access to that friend’s personal watchlist or ratings data.
* Setup details: [Auth: Plex](/crosswatch/settings/connections/media-servers/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, and the optional `goal` query parameter:

```
GET https://wiki.crosswatch.app/crosswatch/settings/synchronization/media-servers/plex.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
