TVmaze API alternative

TVmaze is TV only, free to use, rate limited per IP address, and its data is under an attribution license. Check their docs for the details. amodb is a paid API for TV, movies and people, with limits counted per key and TMDB v3 paths. Choose by scope and budget.

Choose by scope and budget

TVmaze is TV only. It is free to use as a public API with rate limits per IP address, and its data comes under an attribution license, so check their docs for the details. amodb is paid and covers TV, movies and people. If your app is a TV tracker and a free source meets your needs, TVmaze is a sensible start. If you also show films, cast pages or posters in several languages, one amodb key replaces several sources.

What each scope means for your app

Your app showsTVmazeamodb
A TV show pageYesGET /3/tv/{series_id}
An episode listYesGET /3/tv/{series_id}/season/{season_number}
A movie pageNo moviesGET /3/movie/{movie_id}
An actor pageCheck their docsGET /3/person/{person_id} and combined credits
Shows airing todayCheck their docsGET /3/tv/airing_today
A translated overviewCheck their docslanguage parameter, 14 languages
Scores from several sitesCheck their docs/ratings extension

The movie row decides most cases. If you have no film pages, the extra scope has no value to you.

Gaps to check before you move

The season and episode endpoints follow the TMDB shape, and a few parts of them come back empty. Test the screens that use them.

  • Episode cast. On an episode, cast is an empty array. guest_stars and crew are filled, and the series /credits call has the main cast.
  • Season extras. Season images, videos and translations are empty, so a season poster comes from the season record and not from an image list.
  • External ids. Season and episode external_ids are all null. Map episodes to your own records by season_number and episode_number.
  • Creators. created_by on a series is empty for most shows.
  • No changes feed. amodb has no endpoint that lists the shows changed since a date.

Feature comparison

FeatureTVmazeamodb
Pricing modelFree to use public APIPrepaid, 1 to 24 months per purchase
Free tierYes, the whole public APINone, and no trial
AuthenticationCheck their docsapi_key or Bearer header
Response formatJSON, check their docsJSON in TMDB v3 shape
LanguagesCheck their docs14 interface languages
MoviesNoYes
TVYes, its only focusYes
PeopleCheck their docsYes
ImagesCheck their docsimg.amodb.dev, ten size tokens
RatingsCheck their docsFive sources where known
Rate limitPer IP address, check their docs for numbers20, 40 or 120 per minute per key
Commercial useData under an attribution license, check their docsPaid plans, see pricing
CompatibilityIts own APITMDB v3 reads and OMDb

Where amodb differs

  • The limit follows the key. All your servers share one counter in a sliding 60 second window, and replies carry X-RateLimit-Remaining. Nothing depends on which address a request leaves from.
  • Movies, TV and people in one place. One client, one error format and one set of headers cover the whole app.
  • Languages. Titles and overviews come back in any of 14 languages, and original_name keeps the native title.
  • Established protocol. Libraries written for TMDB v3 reads work with a new base URL. See the TV show API page for the series endpoints.

Where TVmaze is a better fit

  • No budget. It is free to use, so a student project or a weekend tracker needs no payment. amodb has no free tier and no trial.
  • TV only, kept simple. If your data model has shows and episodes and nothing else, a TV focused API matches it.
  • Its own conventions. Apps already built around the TVmaze model save work by staying.

If you stay, follow its attribution license. Check their docs for the wording.

Migrate to amodb

Start with a mapping job. Read the external ids that your stored TVmaze records list (check their docs for the field names) and resolve them through /3/find. The program below maps one IMDb id to a series and prints the next episode date.

Go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"time"
)

type findResult struct {
	TVResults []struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	} `json:"tv_results"`
}

type episode struct {
	AirDate       string `json:"air_date"`
	SeasonNumber  int    `json:"season_number"`
	EpisodeNumber int    `json:"episode_number"`
}

type series struct {
	Name        string   `json:"name"`
	Status      string   `json:"status"`
	NextEpisode *episode `json:"next_episode_to_air"`
}

var client = &http.Client{Timeout: 10 * time.Second}

func get(path string, out any) error {
	req, err := http.NewRequest(http.MethodGet, "https://api.amodb.dev/3"+path, nil)
	if err != nil {
		return err
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("AMODB_KEY"))
	res, err := client.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode != http.StatusOK {
		return fmt.Errorf("amodb returned %s", res.Status)
	}
	return json.NewDecoder(res.Body).Decode(out)
}

func main() {
	var found findResult
	if err := get("/find/tt0903747?external_source=imdb_id", &found); err != nil {
		fmt.Println(err)
		return
	}
	if len(found.TVResults) == 0 {
		fmt.Println("no match")
		return
	}
	var s series
	if err := get(fmt.Sprintf("/tv/%d", found.TVResults[0].ID), &s); err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(s.Name, s.Status)
	if s.NextEpisode != nil {
		fmt.Println("next episode:", s.NextEpisode.AirDate)
	}
}

The pointer type for NextEpisode handles the null that ended shows return. Run the mapping once, save the amodb id with each of your records, and call /3/tv/{id} from then on. A 429 is answered with Retry-After, and the find by external id page lists the other id sources.

Sizing a nightly sync

Suppose you refresh 300 shows each night. That is 300 requests, since one series call returns one show. At 20 requests per minute the job takes 15 minutes, at 40 it takes 7.5 minutes, and at 120 it takes 2.5 minutes. Add append_to_response=credits,ratings to each call so cast and scores arrive in the same request instead of costing two more per show. Read X-RateLimit-Remaining and pause when it reaches zero, then continue after the X-RateLimit-Reset seconds.

Pricing

amodb is prepaid and never renews on its own. Choose 1, 3, 6, 12 or 24 months and a plan of 20, 40 or 120 requests per minute. Longer periods are 10, 20, 30 or 40 percent cheaper, and each plan includes all data. Amounts are on pricing.

Questions and answers

Is the TVmaze API free?

TVmaze offers a free public API with rate limits per IP address, and its data is under an attribution license. Check their docs for current limits and the licence text. amodb is paid and has no free tier.

Does amodb cover movies as well as TV?

Yes. Movies, TV series, seasons, episodes and people are on the same key and base URL. TVmaze is TV only, so a movie page in your app needs a second source there.

How do I map TVmaze shows to amodb ids?

TVmaze show records list ids for other databases such as IMDb (check their docs for the exact fields). Call the find endpoint with the IMDb id and external_source=imdb_id, then store the id from tv_results.

Why does a per-IP limit matter?

A limit tied to an IP address is shared by everything behind it, such as a server pool or an office network. amodb counts requests per key in a sliding 60 second window, wherever the calls come from.

Can I show the next episode date for a show?

Yes. Series details return next_episode_to_air with air_date, season_number and episode_number, or null when nothing is scheduled. The edge caches details for 6 hours, so refresh a few times a day.