Skip to content

Caveats

Data structures

Type-specific fields in MediaEntry

The main structure MediaEntry contains fields for all media types - movies, shows, seasons, episodes. Some fields are specific for one of the media types and will be None for others - e.g.:

  • total_episode_count is only present for seasons
  • season_number is present for seasons and episodes
  • episode_number is present only for episodes
  • age_certification is present only for movies and shows

For episodes specifically most of the fields will be empty - which is why episodes function returns different structure Episode.

As search function can return only movies and shows, the episode-specific and season-specific fields will always be None. They are included in MediaEntry so they will be present in output from details function and to reuse the structure in seasons.

Optional fields

Some fields in returned data is marked as optional (through | None). Since there is no documentation for the JustWatch GraphQL API I tried to mark as optional fields which I found to actually be optional, rather than mark everything.

However, there is no guarantee what the API will return, so if you need maximum safety you might need to treat all fields as effectively optional (as in - they can be None).

Locale, language, country

Languages and countries are configured via their respecive codes. While the JustWatch API does not give specific standards, it will respond with an error with expected code regex for invalid ones. You can infer the standard from the regex, however it might not be strict.

There is a list of supported locales in JustWatch REST API documentation. Any combination of those languages and countries should work with this API as well, but it doesn't seem to be comprehensive.

Country

Required pattern is two uppercase letters (e.g., US, DE, GB):

^[A-Z]{2}$

It looks like ISO 3166-1 alpha-2 standard.

Country code letter case

API expects only uppercase letters, however this library will automatically convert country codes to uppercase.

If country code doesn't match the regex, or isn't a valid code the API will respond with an internal error and JustWatchApiError will be raised.

Language

Required pattern is 2 lowercase letters with optional alphanumeric suffix after - (e.g., en, en-US, fr, de, de-CH, de-CH1901). The sufix must be uppercase:

^[a-z]{2}(-[0-9A-Z]+)?$

It looks similar to IETF BCP 47 standard, without - characters in the suffix.

Language code letter case

The provided language isn't modified at all by this library, so it must match the regex exactly, including letter case.

If language code doesn't match the expected regex the API will respond with an internal error and JustWatchApiError will be raised.

If the code does match the regex, but isn't a valid code, then the API defaults to English and no exception is raised.

Discrepancy between invalid country and language codes

API handles codes matching expected pattern, but still not valid differently between country and language - for country API will return and error, thus exception will be raised; while for language it will default to English.

Operation complexity

JustWatch API will respond with error on too high operation complexity - essentially when returned graph would be too large. It's the reason for why seasons/episodes data isn't available directly in search, popular, or details functions (mostly the first one).

This issue can still occur for search and popular with too high count value. In my tests the limit is around 100 (in the worst case with best_only = False). It's a lot, but keep it in mind.

Using best_only=True should alleviate the issue somewhat, so for very large requests I recommend using its default True value.

If you need even more entries you can retrieve data in chunks using offset parameter.

Maximum number of entries

The JustWatch API itself won't allow for getting more than 1999 entries, through count and offset, regardless of operation complexity. If you try to get the 2000th entry, the API (and functions in this libary) will return an empty list.

Entries up to 1999th

If you try to access over the 1999th entry you won't get up to 1999 entries, you'll get an empty list.

For example, this will get you entries 1990 - 1999 - a 9 element list of MediaEntry, as expected:

from simplejustwatchapi import search

results = search("title", count=9, offset=1990)
# len(results) == 9, as expected.

But trying to get 1990 - 2000 will result in an empty list:

from simplejustwatchapi import search

results = search("title", count=10, offset=1990)
# len(results) == 0, API responded with empty list.

Overshooting will also result in an empty list:

from simplejustwatchapi import search

results = search("title", count=100, offset=1950)
# len(results) == 0, API responded with empty list.

Interestingly, you'll still hit too high operation complexity for too high values of count, even though you'd get an empty list anyway:

from simplejustwatchapi import search

results = search("title", count=200, offset=1950)
# Errors out due to complexity.

Getting more results and pagination

This library allows for very simple pagination in search and popular commands through count and offset arguments. The first one configures how many entries are returned in one request, the second allows for offsetting which is the "first" result (thus "skipping" first entries).

This lets you get around issues with operation complexity and get more data. For example, to get all available popular titles without running into the issue with complexity you can:

from simplejustwatchapi import popular

i = 0
page = 99
all_results = []
while results := popular(count=page, offset=i):
    i += page
    all_results.extend(results)
# len(all_results) == 1980
While trying to get them all at once will result in an exception:
from simplejustwatchapi import popular

results = popular(count=1980)
# JustWatchApiError is raised due to too high operation complexity.

Unfortunately, I don't know of any way around the issue with maximum number of entries, so it's impossible to get more than 1999 elements.

Stability of results with pagination

All "pagination" is done on the side of the API by offsetting which is the first element. Since this operation isn't keeping any context between requests there's no guarantee of "stability" of results between requests - whether titles will shift order while you're getting pages.

Provider codes

Different countries can have different codes

The codes can be different for different countries. For example, "Amazon Prime Video" in US has code amp, but in France it's prv. At the same time "Netflix" seems to always be nfx.

Invalid codes provide no filtering

If you try to use invalid/unexpected codes for a given country then no filtering will be done at all. There will be no internal errors, or exceptions; functions will return normal values, rather than some kind of empty response.

providers function

The easiest way of getting all provider codes for filtering in search and popular functions is through providers function, for example:

from simplejustwatchapi import popular, providers

codes = [
    package.short_name
    for package
    # Look up all providers in the UK:
    in providers("GB")
    # Only get codes for specific providers:
    if package.name in ("Netflix", "Amazon Prime Video")
]

# codes == ["nfx", "amp"]

# Get popular titles only for selected providers:
popular_netflix_amazon = popular(providers=codes)

Query parameters from JustWatch

You can also get them by going to JustWatch main page and selecting at least 2 of available services. You need 2, for 1 you'll get its full name. Only for multiple you'll get the needed codes as ?providers=<code1>+<code2>+... query parameter. For example on US version the URL when selecting "Netflix" and "Amazon Prime Video" is:

https://www.justwatch.com/us?providers=amp,nfx

So the codes for them are amp and nfx for the US.

Stored output from other functions

The codes are also returned when looking up offers (through pretty much any function aside from providers) through OfferPackage and its short_name field. For example, to get the codes from search:

from simplejustwatchapi import popular, search

search_results = search("The Matrix", "US", "en", 5, True)
name_to_code_dict = {
    # Get name and short_name/code from packages:
    offer.package.name: offer.package.short_name
    for entry in search_results  # Iterate all entries.
    for offer in entry.offers  # Iterate all offers per entry.
}
# Keep country code the same between functions, as different countries might have
# different provider codes.
# Also, "providers" needs to be a list, not a dict.
popular_results = popular("US", providers=list(name_to_code_dict.values()))

When this actually might be useful

This only makes sense if you are already using other functions. To get just the codes use the providers function instead.