[Announcement] Custom Metadata Providers

Note: This post is primarily focused towards developers who are looking to implement their own custom metadata agents, however there is nothing preventing anyone interested from taking a look through here if they find the topic interesting. It’s never too late to become a developer!

Many of you know that we removed the old Plug-ins system from Plex Media Server (PMS) many years ago but have kept the legacy metadata agents which use this system around until we had a suitable replacement for those.

Work has been steadily happening in the background on building a system to replace this, which leverages the same API that our official Plex Movie and Plex Series metadata agents use.

Today we are releasing the first implementation of this system for developers to start familiarising themselves with the API and to start building out their own metadata providers and to start replacing any beloved legacy agents with these new ones. We plan to completely remove the legacy agents system from new PMS releases in 2026.

This requires Plex Media Server 1.43.0, which is currently in beta, you may need to restart your server if you have an instance on this beta already running to pick up the new feature.

Metadata Providers and Metadata Agents

The nomenclature is slightly updated with the introduction of “metadata providers,” these are as the name suggests, providers of metadata, and are just an HTTP API that returns metadata for library items in a standardized way which is used across the Plex ecosystem.

The new updated “metadata agents” are just a collection of one or more metadata providers which can be defined in the media server. If you are familiar with how the legacy agents worked, then this will be very similar in the way you can add multiple sources (via metadata providers) and re-order them to define the priority of the data from those sources.

Developers only really need to work on the metadata provider side, as the metadata agents are just a user-defined list of providers.

Documentation

Our documentation portal (https://developer.plex.tv/pms) has been updated to include a few new sections outlining the API and the expected responses.

Your jumping off point will start here: https://developer.plex.tv/pms/#section/API-Info/Metadata-Providers

Developers are not restricted by any one language or technology to write these providers, essentially anything that can serve an HTTP API can be used.

Distribution to users can also happen in any way you see fit, from local Docker containers, to self-contained binaries or publicly hosted on the internet. All the user needs to install a metadata provider is a single URL that their system can access.

Example Provider Project

We’ve also provided an example metadata provider written in Typescript that utilizes the TMDB API for TV Show libraries.

This project should make it easier to reference expected behaviours and shows the usage of a more advanced feature like implementing different episode orders.

You can visit this project here: GitHub - plexinc/tmdb-example-provider

Current limitations and missing features

We are releasing this to developers quite early intentionally with just the basic functionality, as getting early feedback on what is most important to developers will guide what features and functionality get worked on next and how they are implemented

  • Currently only Movie and TV Libraries are supported. Music libraries will come later but require a bit more work to get there.
  • Only unauthenticated requests are currently supported. This is currently fine for development purposes or even when users are only hosting locally. Developers hosting public facing providers will likely want to wait until authentication has been implemented before publishing unauthenticated APIs.
  • Metadata support for “streams” is not yet implemented. This would be used to support providing subtitles. Currently only the “item” metadata is used.
  • Provider-specific preferences are not yet implemented. Some providers may want to define specific settings unique to that provider that users can adjust from inside PMS which then get passed to the provider when making requests. Currently we only pass some fixed standard query parameters with requests like language, country, etc.
  • Expect some bugs early on.

Getting Started

  1. Take a look at the documentation to get a basic understanding.
  2. Clone the example project and get it running locally (be sure to check the SwaggerUI to play around making requests).
  3. Use this to configure the example provider inside PMS
    1. Go to Settings → Metadata Agents → Add Provider → Enter the URL for the locally running provider.
    2. Still in the Metadata Agents section, click “Add Agent”, give it any name you want and make the newly added provider the Primary metadata provider. Add additional providers if needed (generally recommended to also add “Plex Local Media” for local metadata and asset).
    3. Create a new TV Show Library, in the Advanced pane select your new Agent in the agent dropdown.
    4. You will see requests being logged to the console of the example provider, this can be useful to see what is happening when PMS does matching and metadata refreshes.
  4. Be free and write your own metadata providers with the knowledge you’ve gained!

Feedback

Early feedback would be very valuable to us, so anything you think could use improvement or if you’re missing something that doesn’t yet exist please make a post in the dev corner forum section.

Future plans

If you are currently maintaining one of these legacy agents then it would be a great time to hop in and implement your agent using the new metadata provider method, if you wish to continue having a usable metadata agent in future PMS versions, before we drop support for legacy agents.

Please feel free to reach out on the forum if you are one of these people and have any questions to make this process as easy as possible.

10 Likes

Thank you for the implementation and documentation I have few questions that i didn’t see it being addressed.

Currently i assume the match for TV episodes will happen based on the index and parentIndex. This has some side effects for example, i archive some YouTube channels. which look like this

- /path/to/media/youtube/
-- channel/
--- Season 2025/
---- 20250326 file1.mkv
---- 20250326 file2.mkv
---- 20250326 file3.mkv
---- 20251126 file4.mkv

Using the current Plex scanner, it would mark all files file 1,2,3 as duplicate even though they are different.

What i did is, i created a scanner that would do some magic and generate different ids for the files even though the share same broadcast date. it will produce consistent ID for each file with the removal of the metadata/scanners, we will lose the ability to actually support multiple files being released at same date. you can see my implementation here which supports these two metadata agents 1 2

I honestly don’t see how we would be able to maintain this using the new metadata providers. Please consider this use case.

This is probably something a Plex Match file could be used for or we could tweak its logic to fit your needs.

https://support.plex.tv/articles/plexmatch/

It would be much better if it was possible to create scan providers similar to how metadata will be externally handled, The external scanner would receive whatever the current scanners receive and will provide compatible initial metadata in format plex would understand,

What really is limiting, is that providers cant say hey x map to xy unless you actually send the files grandparent/parent/filename to the metadata provider which i think it’s unreasonable.

However, if user opt in this could be consolidated into metadata provider instead of having to create yet another scan providers.

Unfortunately Keeping plexmatch update to date isn’t something easily automated :frowning: I just would like a way to retain the ability to reassign the episode id.

There is no plan currently for hooking into the scanner like the old Python plug-ins did.

I’m quite sure we could get something working with Plex Match for your needs, you wouldn’t really need to update these as Plex Match supports pattern matching.

As a basic example to get the scanner to see the files in your example all you would need is this one line .plexmatch file:

Pattern: * file{ep}.mkv

While this obviously doesn’t do what you specifically want, it is something we could look at expanding on to work with your custom regexes.

Thats unfortunate, I guess we could change the matching. if your giving example could work with the new nfo implementation we could in theory do something like

.plexmatch

pattern: *.mkv

and for each file we could give .nfo file and alter the episode id that way? alongside the metadata and GUIDs?

A .plexmatch file like that wouldn’t do anything as it needs to provide hints for the episode/season indexes (we already scan all .mkv file).

Initial implementation for NFO support will only be metadata (i.e. you will still need to follow supported naming schemes), it will essentially be a separate metadata provider like the one in the example, but it’s just built-in like the other Plex ones.

However there is nothing preventing us from implementing NFOs being used during scanning, it’s just not on the roadmap currently.

Thanks for the clarification.

Sadly, this will have really huge side effects not just to my impl it will also effect afaik the following huge agents

  • plex anime scanner and the related agents.
  • all youtube agents that relies on content id for matching.

I would ask that you consider at least the nfo file during scanning to at least give user some control before you remove support for old agents.

Thank you for your time and sorry for bothering you.

I’m sure we can arrive at some solution that can give us the desired result.

Some additional info about exactly how some of your current workflows are configured would be helpful, e.g. the way the files are laid out and the expected parsed indexes for those files.

@drzoidberg33 FYI… while the desktop plex app Plex for Mac, Windows, and Linux - #139 by drzoidberg33 (well, linux one anyway) is built with web version 4.156.0 this new section Metadata Agents does not appear.

Works fine using a browser, its just the desktop client its not showing on.

Thanks for reminding me, I needed to add those product IDs to the feature.

Can you restart the app and see if it shows up now?

1 Like

Thanks - like magic its now appeared.

Excellent.

I thought you might be interested in this with the TMDB example provider :smile:

Yeap, will definitely be taking a look. My developer skills are limited but I’ll get there slowly as I learn what’s been implemented. Thanks.

BTW… quick question ? I have not looked to deeply yet but will these custom metadata providers support cast metadata ?

I suspect not as cast kinda comes from the online discover cast credits. However, I do hope something can be done as stuff like Sasheer Zamata profile picture requires fixing (looks like a zoomed piece of clothing fabric) just keep happening and while rare is completely out of our control to fix and more often than not is ignored when requests to fix them are created.

1 Like

I am currently playing around with the example project, and there are some oddities that I am not really familiar with or find weird.

When I have the show 8 Out of 10 Cats (which has the ID 4020), I get the following log message

Incoming Request: GET /tv/library/metadata/tmdb-season-4020-1

Just out of curiosity, why is the ratingKey such an assembled string of information? In Comparison, the TMDB API request looks a lot cleaner in that regard, https://api.themoviedb.org/3/tv/4020/season/1 and much easier to understand at a glance. In turn, this would mean that I would have to implement a similar unconventional “parsing” with regex, like in the example, correct? (the parseRatingKey function reads like someone REALLY likes regex) What is the purpose of such a ratingKey, or is that just simply something in the bowels of Plex that was always that way?

Also, what is the first part, tmdb, and where is it coming from? Since this is an incoming request, it looks like that my Server is actually constructing this but where is that information coming from? Is that the GUID for the season?

Not like we have with the Discovery cast information as we don’t currently have a detailed people schema inside PMS.

You can still provide your own cast list, but it won’t navigate to a detailed page for the person. You could also choose not to include cast with a custom provider and then use the Plex provider as a secondary source and it would populate the missing cast details which would give you the discovery pages.

1 Like

You can make this basically what you want as long as it’s valid to be passed inside a URL path and the server receiving the request knows exactly which item your’re referring to.

It’s also a single string (not split by additional forward slashes) because that ratingKey is also used a part of the item guid and the guid needs to retain its structure, i.e. scheme://type/ratingKey - if your ratingKey has slashes it would change the guid structure.

We could probably URL-encode it when it’s part of the guid but this was the simplest solution for the time being.

This is also due to things being based off the Plex provider where everything has a unique id regardless what type it is (as opposed to TMDB for example where ids between movies and TV shows are not unique).

That doesn’t need to be there if you don’t want it to be. I wouldn’t read into the structure of the ratingKey in the example provider too much, it just has to follow simple rules:

  1. Be valid to be passed inside a URL path,
  2. Not contain additional forward slashes (which would change the guid structure),
  3. Be enough information for the provider to know exactly what item it is.