diff --git a/src/dto.rs b/src/dto.rs
index aa69ad7a692b405e525a2879d8cd70ab03eba338..fbdc64f546ba542fe08363a4b200c1f615d8d4d7 100644
--- a/src/dto.rs
+++ b/src/dto.rs
@@ -2,6 +2,7 @@ use serde::{Deserialize, Serialize};
 
 use crate::config::Config;
 use crate::models::*;
+use crate::dto_helpers::absolute_url;
 
 #[derive(Serialize, Deserialize, PartialEq, Debug)]
 #[serde(rename_all = "camelCase")]
@@ -19,6 +20,7 @@ pub struct TitleDto {
     pub images: Vec<ImageDto>,
     pub media: Vec<MediaDto>,
     pub subtitles: Vec<SubtitleDto>,
+    pub preview: Option<String>,
     pub created_at: chrono::DateTime<chrono::Utc>,
     pub updated_at: chrono::DateTime<chrono::Utc>,
 }
@@ -34,6 +36,7 @@ impl TitleDto {
         images: Vec<ImageDto>,
         media: Vec<MediaDto>,
         subtitles: Vec<SubtitleDto>,
+        preview: Option<String>
     ) -> Self {
         TitleDto {
             ids: TitleIdDto {
@@ -54,6 +57,7 @@ impl TitleDto {
             images,
             media,
             subtitles,
+            preview,
             created_at: src.created_at,
             updated_at: src.updated_at,
         }
@@ -200,7 +204,7 @@ impl ImageDto {
         Ok(ImageDto {
             kind: src.kind,
             mime: src.mime,
-            src: config.static_url.join(src.src.as_str())?.into_string(),
+            src: absolute_url(config, src.src)?,
         })
     }
 }
@@ -220,7 +224,7 @@ impl MediaDto {
             mime: src.mime,
             codecs: src.codecs,
             languages: src.languages,
-            src: config.static_url.join(src.src.as_str())?.into_string(),
+            src: absolute_url(config, src.src)?,
         })
     }
 }
@@ -258,7 +262,7 @@ impl SubtitleDto {
             language: src.language,
             region: src.region,
             specifier: src.specifier,
-            src: config.static_url.join(src.src.as_str())?.into_string(),
+            src: absolute_url(config, src.src)?,
         })
     }
 }
diff --git a/src/dto_helpers.rs b/src/dto_helpers.rs
index c23cdd923119fcbf621fc735c6cb7d82fa5133ae..ca55297c38e666f08cdd3b601b8c594cc6fca115 100644
--- a/src/dto_helpers.rs
+++ b/src/dto_helpers.rs
@@ -4,6 +4,7 @@ use crate::config::Config;
 use crate::dto::*;
 use crate::models::*;
 use crate::schema::*;
+use url::ParseError;
 
 pub fn load_title(db: &PgConnection, config: &Config, title: Title) -> QueryResult<TitleDto> {
     let title_names: Vec<TitleName> = TitleName::belonging_to(&title)
@@ -24,11 +25,14 @@ pub fn load_title(db: &PgConnection, config: &Config, title: Title) -> QueryResu
         .load::<TitleMedium>(db)?;
     let title_subtitles: Vec<TitleSubtitle> = TitleSubtitle::belonging_to(&title)
         .load::<TitleSubtitle>(db)?;
+    let title_preview: TitlePreview = TitlePreview::belonging_to(&title)
+        .first::<TitlePreview>(db)?;
     Ok(process_title(
         config,
         title, title_names, title_descriptions,
         title_cast, title_genres, title_ratings,
         title_images, title_media, title_subtitles,
+        title_preview,
     ))
 }
 
@@ -59,6 +63,8 @@ pub fn load_titles(db: &PgConnection, config: &Config, titles: Vec<Title>) -> Qu
     let title_subtitles: Vec<Vec<TitleSubtitle>> = TitleSubtitle::belonging_to(&titles)
         .load::<TitleSubtitle>(db)?
         .grouped_by(&titles);
+    let title_preview: Vec<TitlePreview> = TitlePreview::belonging_to(&titles)
+        .load::<TitlePreview>(db)?;
     Ok(titles.into_iter()
         .zip(title_names)
         .zip(title_descriptions)
@@ -68,15 +74,17 @@ pub fn load_titles(db: &PgConnection, config: &Config, titles: Vec<Title>) -> Qu
         .zip(title_images)
         .zip(title_media)
         .zip(title_subtitles)
+        .zip(title_preview)
         .map(|tuple| {
-            let ((((((((title, akas), descriptions),
+            let (((((((((title, akas), descriptions),
                 cast), genres), ratings),
-                images), media), subtitles) = tuple;
+                images), media), subtitles), preview) = tuple;
             process_title(
                 config,
                 title, akas, descriptions,
                 cast, genres, ratings,
                 images, media, subtitles,
+                preview,
             )
         }).collect::<Vec<TitleDto>>())
 }
@@ -86,6 +94,7 @@ fn process_title(
     title: Title, names: Vec<TitleName>, descriptions: Vec<TitleDescription>,
     cast: Vec<(TitleCast, Person)>, genres: Vec<(TitleGenre, Genre)>, ratings: Vec<TitleRating>,
     images: Vec<TitleImage>, media: Vec<TitleMedium>, subtitles: Vec<TitleSubtitle>,
+    preview: TitlePreview,
 ) -> TitleDto {
     TitleDto::of(
         title,
@@ -114,5 +123,10 @@ fn process_title(
         subtitles.into_iter().filter_map(|src| {
             SubtitleDto::of(src, &config).ok()
         }).collect::<Vec<_>>(),
+        preview.src.and_then(|preview| absolute_url(config, preview).ok())
     )
+}
+
+pub fn absolute_url(config: &Config, url: impl Into<String>) -> Result<String, ParseError> {
+    config.static_url.join(url.into().as_str()).map(url::Url::into_string)
 }
\ No newline at end of file
diff --git a/src/models.rs b/src/models.rs
index 3573ad982022932b9e57aa9cbfd0dceb451566c0..c4e00933ba13b789ef0bde5352aa75d5bdc0fa0e 100644
--- a/src/models.rs
+++ b/src/models.rs
@@ -148,6 +148,17 @@ pub struct TitleSubtitle {
     pub title_id: uuid::Uuid,
 }
 
+#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
+#[belongs_to(Title, foreign_key = "title_id")]
+#[table_name = "title_previews"]
+pub struct TitlePreview {
+    pub id: uuid::Uuid,
+    pub src: Option<String>,
+    pub created_at: chrono::DateTime<chrono::Utc>,
+    pub updated_at: chrono::DateTime<chrono::Utc>,
+    pub title_id: uuid::Uuid,
+}
+
 #[derive(Identifiable, Queryable, PartialEq, Debug)]
 #[table_name = "titles"]
 pub struct Title {
diff --git a/src/schema.rs b/src/schema.rs
index f20a6d78c4fbf53a513d1cff0a5fd1faf151a293..8a53a071ffc0d31b4a7fb75a2ebd47b627776187 100644
--- a/src/schema.rs
+++ b/src/schema.rs
@@ -131,6 +131,16 @@ table! {
     }
 }
 
+table! {
+    title_previews (id) {
+        id -> Uuid,
+        src -> Nullable<Text>,
+        created_at -> Timestamptz,
+        updated_at -> Timestamptz,
+        title_id -> Uuid,
+    }
+}
+
 table! {
     titles (id) {
         id -> Uuid,
@@ -156,6 +166,7 @@ joinable!(title_media -> titles (title_id));
 joinable!(title_names -> titles (title_id));
 joinable!(title_ratings -> titles (title_id));
 joinable!(title_subtitles -> titles (title_id));
+joinable!(title_previews -> titles (title_id));
 
 allow_tables_to_appear_in_same_query!(
     genres,