diff --git a/Makefile b/Makefile
index 69d57839..2624f9a7 100644
--- a/Makefile
+++ b/Makefile
@@ -163,6 +163,17 @@ graphiql:
 	make graphiql
 
 
+# Download and prepare actual version of GraphQL Playground static files, used
+# for integrating it.
+#
+# Usage:
+#	make graphql-playground
+
+graphql-playground:
+	@cd juniper/ && \
+	make graphql-playground
+
+
 
 
 ##################
@@ -172,5 +183,5 @@ graphiql:
 .PHONY: book fmt lint release test \
         book.build book.serve \
         cargo.fmt cargo.lint cargo.release cargo.test \
-        graphiql \
+        graphiql graphql-playground \
         test.book test.cargo
diff --git a/juniper/CHANGELOG.md b/juniper/CHANGELOG.md
index e0e6975c..02932f69 100644
--- a/juniper/CHANGELOG.md
+++ b/juniper/CHANGELOG.md
@@ -70,6 +70,7 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
 
 - Made `GraphQLRequest` fields public. ([#750])
 - Relaxed [object safety] requirement for `GraphQLValue` and `GraphQLValueAsync` traits. ([ba1ed85b])
+- Updated [GraphQL Playground] to 1.7.28 version. ([#1190])
 
 ## Fixed
 
@@ -123,6 +124,7 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
 [#1147]: /../../pull/1147
 [#1176]: /../../pull/1176
 [#1188]: /../../pull/1188
+[#1190]: /../../pull/1190
 [ba1ed85b]: /../../commit/ba1ed85b3c3dd77fbae7baf6bc4e693321a94083
 [CVE-2022-31173]: /../../security/advisories/GHSA-4rx6-g5vg-5f3j
 
@@ -144,6 +146,7 @@ See [old CHANGELOG](/../../blob/juniper-v0.15.9/juniper/CHANGELOG.md).
 [Cargo feature]: https://doc.rust-lang.org/cargo/reference/features.html
 [`graphql-ws` GraphQL over WebSocket Protocol]: https://github.com/graphql/graphiql
 [GraphiQL]: https://github.com/enisdenjo/graphql-ws/master/PROTOCOL.md
+[GraphQL Playground]: https://github.com/prisma/graphql-playground
 [graphql-scalars.dev]: https://graphql-scalars.dev
 [October 2021]: https://spec.graphql.org/October2021
 [object safety]: https://doc.rust-lang.org/reference/items/traits.html#object-safety
diff --git a/juniper/Makefile b/juniper/Makefile
index fb43bc27..d04febe0 100644
--- a/juniper/Makefile
+++ b/juniper/Makefile
@@ -18,6 +18,8 @@ sed-i = sed -i$(if $(call eq,$(shell uname -s),Darwin), '',)
 
 GRAPHIQL_VER ?= $(strip \
 	$(shell grep -m1 '"graphiql": "' package.json | cut -d '"' -f4))
+GRAPHQL_PLAYGROUND_VER ?= $(strip \
+	$(shell grep -m1 '"graphql-playground-react": "' package.json | cut -d '"' -f4))
 
 
 
@@ -35,11 +37,11 @@ GRAPHIQL_VER ?= $(strip \
 graphiql:
 	curl -fL -o src/http/graphiql.html \
 		https://raw.githubusercontent.com/graphql/graphiql/graphiql%40$(GRAPHIQL_VER)/examples/graphiql-cdn/index.html
-	$(sed-i) 's|https://unpkg.com/graphiql/|https://unpkg.com/graphiql@$(GRAPHIQL_VER)/|g' \
+	$(sed-i) 's|unpkg.com/graphiql/|unpkg.com/graphiql@$(GRAPHIQL_VER)/|g' \
 		src/http/graphiql.html
-	$(sed-i) "s|'https://swapi-graphql.netlify.app/.netlify/functions/index'|GRAPHQL_URL|g" \
+	$(sed-i) "s|'https://swapi-graphql.netlify.app/.netlify/functions/index'|JUNIPER_URL|g" \
 		src/http/graphiql.html
-	$(sed-i) "s|url: GRAPHQL_URL,|url: GRAPHQL_URL,\n        subscriptionUrl: normalizeSubscriptionEndpoint(GRAPHQL_URL, GRAPHQL_SUBSCRIPTIONS_URL)|" \
+	$(sed-i) "s|url: JUNIPER_URL,|url: JUNIPER_URL,\n        subscriptionUrl: normalizeSubscriptionEndpoint(JUNIPER_URL, JUNIPER_SUBSCRIPTIONS_URL)|" \
 		src/http/graphiql.html
 	$(sed-i) 's|<script>|<script>\n<!-- inject -->|' \
 		src/http/graphiql.html
@@ -47,10 +49,25 @@ graphiql:
 		src/http/graphiql.html
 
 
+# Download and prepare actual version of GraphQL Playground static files, used
+# for integrating it.
+#
+# Usage:
+#	make graphql-playground
+
+graphql-playground:
+	curl -fL -o src/http/playground.html \
+		https://raw.githubusercontent.com/graphql/graphql-playground/graphql-playground-react%40$(GRAPHQL_PLAYGROUND_VER)/packages/graphql-playground-html/withAnimation.html
+	$(sed-i) 's|cdn.jsdelivr.net/npm/graphql-playground-react/|cdn.jsdelivr.net/npm/graphql-playground-react@$(GRAPHQL_PLAYGROUND_VER)/|g' \
+		src/http/playground.html
+	$(sed-i) "s|// you can add more options here|endpoint: 'JUNIPER_URL', subscriptionEndpoint: 'JUNIPER_SUBSCRIPTIONS_URL'|" \
+		src/http/playground.html
+
+
 
 
 ##################
 # .PHONY section #
 ##################
 
-.PHONY: graphiql
+.PHONY: graphiql graphql-playground
diff --git a/juniper/package.json b/juniper/package.json
index 68a4cdb1..05a7d57c 100644
--- a/juniper/package.json
+++ b/juniper/package.json
@@ -1,9 +1,10 @@
 {
   "private": true,
   "scripts": {
-    "postinstall": "make graphiql"
+    "postinstall": "make graphiql graphql-playground"
   },
   "dependencies": {
-    "graphiql": "3.0.5"
+    "graphiql": "3.0.5",
+    "graphql-playground-react": "1.7.28"
   }
 }
diff --git a/juniper/src/http/graphiql.html b/juniper/src/http/graphiql.html
index 7b209dcb..37d266a2 100644
--- a/juniper/src/http/graphiql.html
+++ b/juniper/src/http/graphiql.html
@@ -59,8 +59,8 @@
 <!-- inject -->
       const root = ReactDOM.createRoot(document.getElementById('graphiql'));
       const fetcher = GraphiQL.createFetcher({
-        url: GRAPHQL_URL,
-        subscriptionUrl: normalizeSubscriptionEndpoint(GRAPHQL_URL, GRAPHQL_SUBSCRIPTIONS_URL)
+        url: JUNIPER_URL,
+        subscriptionUrl: normalizeSubscriptionEndpoint(JUNIPER_URL, JUNIPER_SUBSCRIPTIONS_URL)
       });
       const explorerPlugin = GraphiQLPluginExplorer.explorerPlugin();
       root.render(
diff --git a/juniper/src/http/graphiql.rs b/juniper/src/http/graphiql.rs
index 588bc90e..803cf83a 100644
--- a/juniper/src/http/graphiql.rs
+++ b/juniper/src/http/graphiql.rs
@@ -20,11 +20,11 @@ pub fn graphiql_source(
 
     include_str!("graphiql.html").replace(
         "<!-- inject -->",
-        // Language: JavaScript
         &format!(
+            // language=JavaScript
             "
-      var GRAPHQL_URL = '{graphql_url}';
-      var GRAPHQL_SUBSCRIPTIONS_URL = '{graphql_subscriptions_url}';
+      var JUNIPER_URL = '{graphql_url}';
+      var JUNIPER_SUBSCRIPTIONS_URL = '{graphql_subscriptions_url}';
 
 {grahiql_js}
 
diff --git a/juniper/src/http/playground.html b/juniper/src/http/playground.html
new file mode 100644
index 00000000..9f24869f
--- /dev/null
+++ b/juniper/src/http/playground.html
@@ -0,0 +1,540 @@
+<!DOCTYPE html>
+
+<html>
+
+<head>
+  <meta charset=utf-8 />
+  <meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
+  <title>GraphQL Playground</title>
+  <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/graphql-playground-react@1.7.28/build/static/css/index.css" />
+  <link rel="shortcut icon" href="//cdn.jsdelivr.net/npm/graphql-playground-react@1.7.28/build/favicon.png" />
+  <script src="//cdn.jsdelivr.net/npm/graphql-playground-react@1.7.28/build/static/js/middleware.js"></script>
+
+</head>
+
+<body>
+  <style type="text/css">
+    html {
+      font-family: "Open Sans", sans-serif;
+      overflow: hidden;
+    }
+
+    body {
+      margin: 0;
+      background: #172a3a;
+    }
+
+    .playgroundIn {
+      -webkit-animation: playgroundIn 0.5s ease-out forwards;
+      animation: playgroundIn 0.5s ease-out forwards;
+    }
+
+    @-webkit-keyframes playgroundIn {
+      from {
+        opacity: 0;
+        -webkit-transform: translateY(10px);
+        -ms-transform: translateY(10px);
+        transform: translateY(10px);
+      }
+      to {
+        opacity: 1;
+        -webkit-transform: translateY(0);
+        -ms-transform: translateY(0);
+        transform: translateY(0);
+      }
+    }
+
+    @keyframes playgroundIn {
+      from {
+        opacity: 0;
+        -webkit-transform: translateY(10px);
+        -ms-transform: translateY(10px);
+        transform: translateY(10px);
+      }
+      to {
+        opacity: 1;
+        -webkit-transform: translateY(0);
+        -ms-transform: translateY(0);
+        transform: translateY(0);
+      }
+    }
+  </style>
+
+  <style type="text/css">
+    .fadeOut {
+      -webkit-animation: fadeOut 0.5s ease-out forwards;
+      animation: fadeOut 0.5s ease-out forwards;
+    }
+
+    @-webkit-keyframes fadeIn {
+      from {
+        opacity: 0;
+        -webkit-transform: translateY(-10px);
+        -ms-transform: translateY(-10px);
+        transform: translateY(-10px);
+      }
+      to {
+        opacity: 1;
+        -webkit-transform: translateY(0);
+        -ms-transform: translateY(0);
+        transform: translateY(0);
+      }
+    }
+
+    @keyframes fadeIn {
+      from {
+        opacity: 0;
+        -webkit-transform: translateY(-10px);
+        -ms-transform: translateY(-10px);
+        transform: translateY(-10px);
+      }
+      to {
+        opacity: 1;
+        -webkit-transform: translateY(0);
+        -ms-transform: translateY(0);
+        transform: translateY(0);
+      }
+    }
+
+    @-webkit-keyframes fadeOut {
+      from {
+        opacity: 1;
+        -webkit-transform: translateY(0);
+        -ms-transform: translateY(0);
+        transform: translateY(0);
+      }
+      to {
+        opacity: 0;
+        -webkit-transform: translateY(-10px);
+        -ms-transform: translateY(-10px);
+        transform: translateY(-10px);
+      }
+    }
+
+    @keyframes fadeOut {
+      from {
+        opacity: 1;
+        -webkit-transform: translateY(0);
+        -ms-transform: translateY(0);
+        transform: translateY(0);
+      }
+      to {
+        opacity: 0;
+        -webkit-transform: translateY(-10px);
+        -ms-transform: translateY(-10px);
+        transform: translateY(-10px);
+      }
+    }
+
+    @-webkit-keyframes appearIn {
+      from {
+        opacity: 0;
+        -webkit-transform: translateY(0px);
+        -ms-transform: translateY(0px);
+        transform: translateY(0px);
+      }
+      to {
+        opacity: 1;
+        -webkit-transform: translateY(0);
+        -ms-transform: translateY(0);
+        transform: translateY(0);
+      }
+    }
+
+    @keyframes appearIn {
+      from {
+        opacity: 0;
+        -webkit-transform: translateY(0px);
+        -ms-transform: translateY(0px);
+        transform: translateY(0px);
+      }
+      to {
+        opacity: 1;
+        -webkit-transform: translateY(0);
+        -ms-transform: translateY(0);
+        transform: translateY(0);
+      }
+    }
+
+    @-webkit-keyframes scaleIn {
+      from {
+        -webkit-transform: scale(0);
+        -ms-transform: scale(0);
+        transform: scale(0);
+      }
+      to {
+        -webkit-transform: scale(1);
+        -ms-transform: scale(1);
+        transform: scale(1);
+      }
+    }
+
+    @keyframes scaleIn {
+      from {
+        -webkit-transform: scale(0);
+        -ms-transform: scale(0);
+        transform: scale(0);
+      }
+      to {
+        -webkit-transform: scale(1);
+        -ms-transform: scale(1);
+        transform: scale(1);
+      }
+    }
+
+    @-webkit-keyframes innerDrawIn {
+      0% {
+        stroke-dashoffset: 70;
+      }
+      50% {
+        stroke-dashoffset: 140;
+      }
+      100% {
+        stroke-dashoffset: 210;
+      }
+    }
+
+    @keyframes innerDrawIn {
+      0% {
+        stroke-dashoffset: 70;
+      }
+      50% {
+        stroke-dashoffset: 140;
+      }
+      100% {
+        stroke-dashoffset: 210;
+      }
+    }
+
+    @-webkit-keyframes outerDrawIn {
+      0% {
+        stroke-dashoffset: 76;
+      }
+      100% {
+        stroke-dashoffset: 152;
+      }
+    }
+
+    @keyframes outerDrawIn {
+      0% {
+        stroke-dashoffset: 76;
+      }
+      100% {
+        stroke-dashoffset: 152;
+      }
+    }
+
+    .hHWjkv {
+      -webkit-transform-origin: 0px 0px;
+      -ms-transform-origin: 0px 0px;
+      transform-origin: 0px 0px;
+      -webkit-transform: scale(0);
+      -ms-transform: scale(0);
+      transform: scale(0);
+      -webkit-animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
+      animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
+    }
+
+    .gCDOzd {
+      -webkit-transform-origin: 0px 0px;
+      -ms-transform-origin: 0px 0px;
+      transform-origin: 0px 0px;
+      -webkit-transform: scale(0);
+      -ms-transform: scale(0);
+      transform: scale(0);
+      -webkit-animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
+      animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
+    }
+
+    .hmCcxi {
+      -webkit-transform-origin: 0px 0px;
+      -ms-transform-origin: 0px 0px;
+      transform-origin: 0px 0px;
+      -webkit-transform: scale(0);
+      -ms-transform: scale(0);
+      transform: scale(0);
+      -webkit-animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
+      animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
+    }
+
+    .eHamQi {
+      -webkit-transform-origin: 0px 0px;
+      -ms-transform-origin: 0px 0px;
+      transform-origin: 0px 0px;
+      -webkit-transform: scale(0);
+      -ms-transform: scale(0);
+      transform: scale(0);
+      -webkit-animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
+      animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
+    }
+
+    .byhgGu {
+      -webkit-transform-origin: 0px 0px;
+      -ms-transform-origin: 0px 0px;
+      transform-origin: 0px 0px;
+      -webkit-transform: scale(0);
+      -ms-transform: scale(0);
+      transform: scale(0);
+      -webkit-animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
+      animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
+    }
+
+    .llAKP {
+      -webkit-transform-origin: 0px 0px;
+      -ms-transform-origin: 0px 0px;
+      transform-origin: 0px 0px;
+      -webkit-transform: scale(0);
+      -ms-transform: scale(0);
+      transform: scale(0);
+      -webkit-animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
+      animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
+    }
+
+    .bglIGM {
+      -webkit-transform-origin: 64px 28px;
+      -ms-transform-origin: 64px 28px;
+      transform-origin: 64px 28px;
+      -webkit-transform: scale(0);
+      -ms-transform: scale(0);
+      transform: scale(0);
+      -webkit-animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
+      animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
+    }
+
+    .ksxRII {
+      -webkit-transform-origin: 95.98500061035156px 46.510000228881836px;
+      -ms-transform-origin: 95.98500061035156px 46.510000228881836px;
+      transform-origin: 95.98500061035156px 46.510000228881836px;
+      -webkit-transform: scale(0);
+      -ms-transform: scale(0);
+      transform: scale(0);
+      -webkit-animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
+      animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
+    }
+
+    .cWrBmb {
+      -webkit-transform-origin: 95.97162628173828px 83.4900016784668px;
+      -ms-transform-origin: 95.97162628173828px 83.4900016784668px;
+      transform-origin: 95.97162628173828px 83.4900016784668px;
+      -webkit-transform: scale(0);
+      -ms-transform: scale(0);
+      transform: scale(0);
+      -webkit-animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
+      animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
+    }
+
+    .Wnusb {
+      -webkit-transform-origin: 64px 101.97999572753906px;
+      -ms-transform-origin: 64px 101.97999572753906px;
+      transform-origin: 64px 101.97999572753906px;
+      -webkit-transform: scale(0);
+      -ms-transform: scale(0);
+      transform: scale(0);
+      -webkit-animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
+      animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
+    }
+
+    .bfPqf {
+      -webkit-transform-origin: 32.03982162475586px 83.4900016784668px;
+      -ms-transform-origin: 32.03982162475586px 83.4900016784668px;
+      transform-origin: 32.03982162475586px 83.4900016784668px;
+      -webkit-transform: scale(0);
+      -ms-transform: scale(0);
+      transform: scale(0);
+      -webkit-animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
+      animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
+    }
+
+    .edRCTN {
+      -webkit-transform-origin: 32.033552169799805px 46.510000228881836px;
+      -ms-transform-origin: 32.033552169799805px 46.510000228881836px;
+      transform-origin: 32.033552169799805px 46.510000228881836px;
+      -webkit-transform: scale(0);
+      -ms-transform: scale(0);
+      transform: scale(0);
+      -webkit-animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
+      animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
+    }
+
+    .iEGVWn {
+      opacity: 0;
+      stroke-dasharray: 76;
+      -webkit-animation: outerDrawIn 0.5s ease-out forwards 0.3333333333333333s, appearIn 0.1s ease-out forwards 0.3333333333333333s;
+      animation: outerDrawIn 0.5s ease-out forwards 0.3333333333333333s, appearIn 0.1s ease-out forwards 0.3333333333333333s;
+      -webkit-animation-iteration-count: 1, 1;
+      animation-iteration-count: 1, 1;
+    }
+
+    .bsocdx {
+      opacity: 0;
+      stroke-dasharray: 76;
+      -webkit-animation: outerDrawIn 0.5s ease-out forwards 0.5333333333333333s, appearIn 0.1s ease-out forwards 0.5333333333333333s;
+      animation: outerDrawIn 0.5s ease-out forwards 0.5333333333333333s, appearIn 0.1s ease-out forwards 0.5333333333333333s;
+      -webkit-animation-iteration-count: 1, 1;
+      animation-iteration-count: 1, 1;
+    }
+
+    .jAZXmP {
+      opacity: 0;
+      stroke-dasharray: 76;
+      -webkit-animation: outerDrawIn 0.5s ease-out forwards 0.7333333333333334s, appearIn 0.1s ease-out forwards 0.7333333333333334s;
+      animation: outerDrawIn 0.5s ease-out forwards 0.7333333333333334s, appearIn 0.1s ease-out forwards 0.7333333333333334s;
+      -webkit-animation-iteration-count: 1, 1;
+      animation-iteration-count: 1, 1;
+    }
+
+    .hSeArx {
+      opacity: 0;
+      stroke-dasharray: 76;
+      -webkit-animation: outerDrawIn 0.5s ease-out forwards 0.9333333333333333s, appearIn 0.1s ease-out forwards 0.9333333333333333s;
+      animation: outerDrawIn 0.5s ease-out forwards 0.9333333333333333s, appearIn 0.1s ease-out forwards 0.9333333333333333s;
+      -webkit-animation-iteration-count: 1, 1;
+      animation-iteration-count: 1, 1;
+    }
+
+    .bVgqGk {
+      opacity: 0;
+      stroke-dasharray: 76;
+      -webkit-animation: outerDrawIn 0.5s ease-out forwards 1.1333333333333333s, appearIn 0.1s ease-out forwards 1.1333333333333333s;
+      animation: outerDrawIn 0.5s ease-out forwards 1.1333333333333333s, appearIn 0.1s ease-out forwards 1.1333333333333333s;
+      -webkit-animation-iteration-count: 1, 1;
+      animation-iteration-count: 1, 1;
+    }
+
+    .hEFqBt {
+      opacity: 0;
+      stroke-dasharray: 76;
+      -webkit-animation: outerDrawIn 0.5s ease-out forwards 1.3333333333333333s, appearIn 0.1s ease-out forwards 1.3333333333333333s;
+      animation: outerDrawIn 0.5s ease-out forwards 1.3333333333333333s, appearIn 0.1s ease-out forwards 1.3333333333333333s;
+      -webkit-animation-iteration-count: 1, 1;
+      animation-iteration-count: 1, 1;
+    }
+
+    .dzEKCM {
+      opacity: 0;
+      stroke-dasharray: 70;
+      -webkit-animation: innerDrawIn 1s ease-in-out forwards 1.3666666666666667s, appearIn 0.1s linear forwards 1.3666666666666667s;
+      animation: innerDrawIn 1s ease-in-out forwards 1.3666666666666667s, appearIn 0.1s linear forwards 1.3666666666666667s;
+      -webkit-animation-iteration-count: infinite, 1;
+      animation-iteration-count: infinite, 1;
+    }
+
+    .DYnPx {
+      opacity: 0;
+      stroke-dasharray: 70;
+      -webkit-animation: innerDrawIn 1s ease-in-out forwards 1.5333333333333332s, appearIn 0.1s linear forwards 1.5333333333333332s;
+      animation: innerDrawIn 1s ease-in-out forwards 1.5333333333333332s, appearIn 0.1s linear forwards 1.5333333333333332s;
+      -webkit-animation-iteration-count: infinite, 1;
+      animation-iteration-count: infinite, 1;
+    }
+
+    .hjPEAQ {
+      opacity: 0;
+      stroke-dasharray: 70;
+      -webkit-animation: innerDrawIn 1s ease-in-out forwards 1.7000000000000002s, appearIn 0.1s linear forwards 1.7000000000000002s;
+      animation: innerDrawIn 1s ease-in-out forwards 1.7000000000000002s, appearIn 0.1s linear forwards 1.7000000000000002s;
+      -webkit-animation-iteration-count: infinite, 1;
+      animation-iteration-count: infinite, 1;
+    }
+
+    #loading-wrapper {
+      position: absolute;
+      width: 100vw;
+      height: 100vh;
+      display: -webkit-box;
+      display: -webkit-flex;
+      display: -ms-flexbox;
+      display: flex;
+      -webkit-align-items: center;
+      -webkit-box-align: center;
+      -ms-flex-align: center;
+      align-items: center;
+      -webkit-box-pack: center;
+      -webkit-justify-content: center;
+      -ms-flex-pack: center;
+      justify-content: center;
+      -webkit-flex-direction: column;
+      -ms-flex-direction: column;
+      flex-direction: column;
+    }
+
+    .logo {
+      width: 75px;
+      height: 75px;
+      margin-bottom: 20px;
+      opacity: 0;
+      -webkit-animation: fadeIn 0.5s ease-out forwards;
+      animation: fadeIn 0.5s ease-out forwards;
+    }
+
+    .text {
+      font-size: 32px;
+      font-weight: 200;
+      text-align: center;
+      color: rgba(255, 255, 255, 0.6);
+      opacity: 0;
+      -webkit-animation: fadeIn 0.5s ease-out forwards;
+      animation: fadeIn 0.5s ease-out forwards;
+    }
+
+    .dGfHfc {
+      font-weight: 400;
+    }
+  </style>
+  <div id="loading-wrapper">
+    <svg class="logo" viewBox="0 0 128 128" xmlns:xlink="http://www.w3.org/1999/xlink">
+      <title>GraphQL Playground Logo</title>
+      <defs>
+        <linearGradient id="linearGradient-1" x1="4.86%" x2="96.21%" y1="0%" y2="99.66%">
+          <stop stop-color="#E00082" stop-opacity=".8" offset="0%"></stop>
+          <stop stop-color="#E00082" offset="100%"></stop>
+        </linearGradient>
+      </defs>
+      <g>
+        <rect id="Gradient" width="127.96" height="127.96" y="1" fill="url(#linearGradient-1)" rx="4"></rect>
+        <path id="Border" fill="#E00082" fill-rule="nonzero" d="M4.7 2.84c-1.58 0-2.86 1.28-2.86 2.85v116.57c0 1.57 1.28 2.84 2.85 2.84h116.57c1.57 0 2.84-1.26 2.84-2.83V5.67c0-1.55-1.26-2.83-2.83-2.83H4.67zM4.7 0h116.58c3.14 0 5.68 2.55 5.68 5.7v116.58c0 3.14-2.54 5.68-5.68 5.68H4.68c-3.13 0-5.68-2.54-5.68-5.68V5.68C-1 2.56 1.55 0 4.7 0z"></path>
+        <path class="bglIGM" x="64" y="28" fill="#fff" d="M64 36c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8" style="transform: translate(100px, 100px);"></path>
+        <path class="ksxRII" x="95.98500061035156" y="46.510000228881836" fill="#fff" d="M89.04 50.52c-2.2-3.84-.9-8.73 2.94-10.96 3.83-2.2 8.72-.9 10.95 2.94 2.2 3.84.9 8.73-2.94 10.96-3.85 2.2-8.76.9-10.97-2.94"
+          style="transform: translate(100px, 100px);"></path>
+        <path class="cWrBmb" x="95.97162628173828" y="83.4900016784668" fill="#fff" d="M102.9 87.5c-2.2 3.84-7.1 5.15-10.94 2.94-3.84-2.2-5.14-7.12-2.94-10.96 2.2-3.84 7.12-5.15 10.95-2.94 3.86 2.23 5.16 7.12 2.94 10.96"
+          style="transform: translate(100px, 100px);"></path>
+        <path class="Wnusb" x="64" y="101.97999572753906" fill="#fff" d="M64 110c-4.43 0-8-3.6-8-8.02 0-4.44 3.57-8.02 8-8.02s8 3.58 8 8.02c0 4.4-3.57 8.02-8 8.02"
+          style="transform: translate(100px, 100px);"></path>
+        <path class="bfPqf" x="32.03982162475586" y="83.4900016784668" fill="#fff" d="M25.1 87.5c-2.2-3.84-.9-8.73 2.93-10.96 3.83-2.2 8.72-.9 10.95 2.94 2.2 3.84.9 8.73-2.94 10.96-3.85 2.2-8.74.9-10.95-2.94"
+          style="transform: translate(100px, 100px);"></path>
+        <path class="edRCTN" x="32.033552169799805" y="46.510000228881836" fill="#fff" d="M38.96 50.52c-2.2 3.84-7.12 5.15-10.95 2.94-3.82-2.2-5.12-7.12-2.92-10.96 2.2-3.84 7.12-5.15 10.95-2.94 3.83 2.23 5.14 7.12 2.94 10.96"
+          style="transform: translate(100px, 100px);"></path>
+        <path class="iEGVWn" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M63.55 27.5l32.9 19-32.9-19z"></path>
+        <path class="bsocdx" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M96 46v38-38z"></path>
+        <path class="jAZXmP" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M96.45 84.5l-32.9 19 32.9-19z"></path>
+        <path class="hSeArx" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M64.45 103.5l-32.9-19 32.9 19z"></path>
+        <path class="bVgqGk" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M32 84V46v38z"></path>
+        <path class="hEFqBt" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M31.55 46.5l32.9-19-32.9 19z"></path>
+        <path class="dzEKCM" id="Triangle-Bottom" stroke="#fff" stroke-width="4" d="M30 84h70" stroke-linecap="round"></path>
+        <path class="DYnPx" id="Triangle-Left" stroke="#fff" stroke-width="4" d="M65 26L30 87" stroke-linecap="round"></path>
+        <path class="hjPEAQ" id="Triangle-Right" stroke="#fff" stroke-width="4" d="M98 87L63 26" stroke-linecap="round"></path>
+      </g>
+    </svg>
+    <div class="text">Loading
+      <span class="dGfHfc">GraphQL Playground</span>
+    </div>
+  </div>
+
+  <div id="root" />
+  <script type="text/javascript">
+    window.addEventListener('load', function (event) {
+
+      const loadingWrapper = document.getElementById('loading-wrapper');
+      loadingWrapper.classList.add('fadeOut');
+
+
+      const root = document.getElementById('root');
+      root.classList.add('playgroundIn');
+
+      GraphQLPlayground.init(root, {
+        endpoint: 'JUNIPER_URL', subscriptionEndpoint: 'JUNIPER_SUBSCRIPTIONS_URL'
+      })
+    })
+  </script>
+</body>
+</html>
diff --git a/juniper/src/http/playground.rs b/juniper/src/http/playground.rs
index 09cfc53f..de61bf94 100644
--- a/juniper/src/http/playground.rs
+++ b/juniper/src/http/playground.rs
@@ -1,7 +1,6 @@
-//! Utility module to generate a GraphQL Playground interface
+//! Utility module to generate a GraphQL Playground interface.
 
-/// Generate the HTML source to show a GraphQL Playground interface
-// source: https://github.com/prisma/graphql-playground/blob/master/packages/graphql-playground-html/withAnimation.html
+/// Generate the HTML source to show a GraphQL Playground interface.
 pub fn playground_source(
     graphql_endpoint_url: &str,
     subscriptions_endpoint_url: Option<&str>,
@@ -12,545 +11,7 @@ pub fn playground_source(
         graphql_endpoint_url
     };
 
-    r##"
-<!DOCTYPE html>
-
-<html>
-
-<head>
-  <meta charset=utf-8 />
-  <meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
-  <title>GraphQL Playground</title>
-  <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/graphql-playground-react@1.7.26/build/static/css/index.css" />
-  <link rel="shortcut icon" href="//cdn.jsdelivr.net/npm/graphql-playground-react@1.7.26/build/favicon.png" />
-  <script src="//cdn.jsdelivr.net/npm/graphql-playground-react@1.7.26/build/static/js/middleware.js"></script>
-
-</head>
-
-<body>
-  <style type="text/css">
-    html {
-      font-family: "Open Sans", sans-serif;
-      overflow: hidden;
-    }
-
-    body {
-      margin: 0;
-      background: #172a3a;
-    }
-
-    .playgroundIn {
-      -webkit-animation: playgroundIn 0.5s ease-out forwards;
-      animation: playgroundIn 0.5s ease-out forwards;
-    }
-
-    @-webkit-keyframes playgroundIn {
-      from {
-        opacity: 0;
-        -webkit-transform: translateY(10px);
-        -ms-transform: translateY(10px);
-        transform: translateY(10px);
-      }
-      to {
-        opacity: 1;
-        -webkit-transform: translateY(0);
-        -ms-transform: translateY(0);
-        transform: translateY(0);
-      }
-    }
-
-    @keyframes playgroundIn {
-      from {
-        opacity: 0;
-        -webkit-transform: translateY(10px);
-        -ms-transform: translateY(10px);
-        transform: translateY(10px);
-      }
-      to {
-        opacity: 1;
-        -webkit-transform: translateY(0);
-        -ms-transform: translateY(0);
-        transform: translateY(0);
-      }
-    }
-  </style>
-
-  <style type="text/css">
-    .fadeOut {
-      -webkit-animation: fadeOut 0.5s ease-out forwards;
-      animation: fadeOut 0.5s ease-out forwards;
-    }
-
-    @-webkit-keyframes fadeIn {
-      from {
-        opacity: 0;
-        -webkit-transform: translateY(-10px);
-        -ms-transform: translateY(-10px);
-        transform: translateY(-10px);
-      }
-      to {
-        opacity: 1;
-        -webkit-transform: translateY(0);
-        -ms-transform: translateY(0);
-        transform: translateY(0);
-      }
-    }
-
-    @keyframes fadeIn {
-      from {
-        opacity: 0;
-        -webkit-transform: translateY(-10px);
-        -ms-transform: translateY(-10px);
-        transform: translateY(-10px);
-      }
-      to {
-        opacity: 1;
-        -webkit-transform: translateY(0);
-        -ms-transform: translateY(0);
-        transform: translateY(0);
-      }
-    }
-
-    @-webkit-keyframes fadeOut {
-      from {
-        opacity: 1;
-        -webkit-transform: translateY(0);
-        -ms-transform: translateY(0);
-        transform: translateY(0);
-      }
-      to {
-        opacity: 0;
-        -webkit-transform: translateY(-10px);
-        -ms-transform: translateY(-10px);
-        transform: translateY(-10px);
-      }
-    }
-
-    @keyframes fadeOut {
-      from {
-        opacity: 1;
-        -webkit-transform: translateY(0);
-        -ms-transform: translateY(0);
-        transform: translateY(0);
-      }
-      to {
-        opacity: 0;
-        -webkit-transform: translateY(-10px);
-        -ms-transform: translateY(-10px);
-        transform: translateY(-10px);
-      }
-    }
-
-    @-webkit-keyframes appearIn {
-      from {
-        opacity: 0;
-        -webkit-transform: translateY(0px);
-        -ms-transform: translateY(0px);
-        transform: translateY(0px);
-      }
-      to {
-        opacity: 1;
-        -webkit-transform: translateY(0);
-        -ms-transform: translateY(0);
-        transform: translateY(0);
-      }
-    }
-
-    @keyframes appearIn {
-      from {
-        opacity: 0;
-        -webkit-transform: translateY(0px);
-        -ms-transform: translateY(0px);
-        transform: translateY(0px);
-      }
-      to {
-        opacity: 1;
-        -webkit-transform: translateY(0);
-        -ms-transform: translateY(0);
-        transform: translateY(0);
-      }
-    }
-
-    @-webkit-keyframes scaleIn {
-      from {
-        -webkit-transform: scale(0);
-        -ms-transform: scale(0);
-        transform: scale(0);
-      }
-      to {
-        -webkit-transform: scale(1);
-        -ms-transform: scale(1);
-        transform: scale(1);
-      }
-    }
-
-    @keyframes scaleIn {
-      from {
-        -webkit-transform: scale(0);
-        -ms-transform: scale(0);
-        transform: scale(0);
-      }
-      to {
-        -webkit-transform: scale(1);
-        -ms-transform: scale(1);
-        transform: scale(1);
-      }
-    }
-
-    @-webkit-keyframes innerDrawIn {
-      0% {
-        stroke-dashoffset: 70;
-      }
-      50% {
-        stroke-dashoffset: 140;
-      }
-      100% {
-        stroke-dashoffset: 210;
-      }
-    }
-
-    @keyframes innerDrawIn {
-      0% {
-        stroke-dashoffset: 70;
-      }
-      50% {
-        stroke-dashoffset: 140;
-      }
-      100% {
-        stroke-dashoffset: 210;
-      }
-    }
-
-    @-webkit-keyframes outerDrawIn {
-      0% {
-        stroke-dashoffset: 76;
-      }
-      100% {
-        stroke-dashoffset: 152;
-      }
-    }
-
-    @keyframes outerDrawIn {
-      0% {
-        stroke-dashoffset: 76;
-      }
-      100% {
-        stroke-dashoffset: 152;
-      }
-    }
-
-    .hHWjkv {
-      -webkit-transform-origin: 0px 0px;
-      -ms-transform-origin: 0px 0px;
-      transform-origin: 0px 0px;
-      -webkit-transform: scale(0);
-      -ms-transform: scale(0);
-      transform: scale(0);
-      -webkit-animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
-      animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
-    }
-
-    .gCDOzd {
-      -webkit-transform-origin: 0px 0px;
-      -ms-transform-origin: 0px 0px;
-      transform-origin: 0px 0px;
-      -webkit-transform: scale(0);
-      -ms-transform: scale(0);
-      transform: scale(0);
-      -webkit-animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
-      animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
-    }
-
-    .hmCcxi {
-      -webkit-transform-origin: 0px 0px;
-      -ms-transform-origin: 0px 0px;
-      transform-origin: 0px 0px;
-      -webkit-transform: scale(0);
-      -ms-transform: scale(0);
-      transform: scale(0);
-      -webkit-animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
-      animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
-    }
-
-    .eHamQi {
-      -webkit-transform-origin: 0px 0px;
-      -ms-transform-origin: 0px 0px;
-      transform-origin: 0px 0px;
-      -webkit-transform: scale(0);
-      -ms-transform: scale(0);
-      transform: scale(0);
-      -webkit-animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
-      animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
-    }
-
-    .byhgGu {
-      -webkit-transform-origin: 0px 0px;
-      -ms-transform-origin: 0px 0px;
-      transform-origin: 0px 0px;
-      -webkit-transform: scale(0);
-      -ms-transform: scale(0);
-      transform: scale(0);
-      -webkit-animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
-      animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
-    }
-
-    .llAKP {
-      -webkit-transform-origin: 0px 0px;
-      -ms-transform-origin: 0px 0px;
-      transform-origin: 0px 0px;
-      -webkit-transform: scale(0);
-      -ms-transform: scale(0);
-      transform: scale(0);
-      -webkit-animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
-      animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
-    }
-
-    .bglIGM {
-      -webkit-transform-origin: 64px 28px;
-      -ms-transform-origin: 64px 28px;
-      transform-origin: 64px 28px;
-      -webkit-transform: scale(0);
-      -ms-transform: scale(0);
-      transform: scale(0);
-      -webkit-animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
-      animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
-    }
-
-    .ksxRII {
-      -webkit-transform-origin: 95.98500061035156px 46.510000228881836px;
-      -ms-transform-origin: 95.98500061035156px 46.510000228881836px;
-      transform-origin: 95.98500061035156px 46.510000228881836px;
-      -webkit-transform: scale(0);
-      -ms-transform: scale(0);
-      transform: scale(0);
-      -webkit-animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
-      animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
-    }
-
-    .cWrBmb {
-      -webkit-transform-origin: 95.97162628173828px 83.4900016784668px;
-      -ms-transform-origin: 95.97162628173828px 83.4900016784668px;
-      transform-origin: 95.97162628173828px 83.4900016784668px;
-      -webkit-transform: scale(0);
-      -ms-transform: scale(0);
-      transform: scale(0);
-      -webkit-animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
-      animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
-    }
-
-    .Wnusb {
-      -webkit-transform-origin: 64px 101.97999572753906px;
-      -ms-transform-origin: 64px 101.97999572753906px;
-      transform-origin: 64px 101.97999572753906px;
-      -webkit-transform: scale(0);
-      -ms-transform: scale(0);
-      transform: scale(0);
-      -webkit-animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
-      animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
-    }
-
-    .bfPqf {
-      -webkit-transform-origin: 32.03982162475586px 83.4900016784668px;
-      -ms-transform-origin: 32.03982162475586px 83.4900016784668px;
-      transform-origin: 32.03982162475586px 83.4900016784668px;
-      -webkit-transform: scale(0);
-      -ms-transform: scale(0);
-      transform: scale(0);
-      -webkit-animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
-      animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
-    }
-
-    .edRCTN {
-      -webkit-transform-origin: 32.033552169799805px 46.510000228881836px;
-      -ms-transform-origin: 32.033552169799805px 46.510000228881836px;
-      transform-origin: 32.033552169799805px 46.510000228881836px;
-      -webkit-transform: scale(0);
-      -ms-transform: scale(0);
-      transform: scale(0);
-      -webkit-animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
-      animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
-    }
-
-    .iEGVWn {
-      opacity: 0;
-      stroke-dasharray: 76;
-      -webkit-animation: outerDrawIn 0.5s ease-out forwards 0.3333333333333333s, appearIn 0.1s ease-out forwards 0.3333333333333333s;
-      animation: outerDrawIn 0.5s ease-out forwards 0.3333333333333333s, appearIn 0.1s ease-out forwards 0.3333333333333333s;
-      -webkit-animation-iteration-count: 1, 1;
-      animation-iteration-count: 1, 1;
-    }
-
-    .bsocdx {
-      opacity: 0;
-      stroke-dasharray: 76;
-      -webkit-animation: outerDrawIn 0.5s ease-out forwards 0.5333333333333333s, appearIn 0.1s ease-out forwards 0.5333333333333333s;
-      animation: outerDrawIn 0.5s ease-out forwards 0.5333333333333333s, appearIn 0.1s ease-out forwards 0.5333333333333333s;
-      -webkit-animation-iteration-count: 1, 1;
-      animation-iteration-count: 1, 1;
-    }
-
-    .jAZXmP {
-      opacity: 0;
-      stroke-dasharray: 76;
-      -webkit-animation: outerDrawIn 0.5s ease-out forwards 0.7333333333333334s, appearIn 0.1s ease-out forwards 0.7333333333333334s;
-      animation: outerDrawIn 0.5s ease-out forwards 0.7333333333333334s, appearIn 0.1s ease-out forwards 0.7333333333333334s;
-      -webkit-animation-iteration-count: 1, 1;
-      animation-iteration-count: 1, 1;
-    }
-
-    .hSeArx {
-      opacity: 0;
-      stroke-dasharray: 76;
-      -webkit-animation: outerDrawIn 0.5s ease-out forwards 0.9333333333333333s, appearIn 0.1s ease-out forwards 0.9333333333333333s;
-      animation: outerDrawIn 0.5s ease-out forwards 0.9333333333333333s, appearIn 0.1s ease-out forwards 0.9333333333333333s;
-      -webkit-animation-iteration-count: 1, 1;
-      animation-iteration-count: 1, 1;
-    }
-
-    .bVgqGk {
-      opacity: 0;
-      stroke-dasharray: 76;
-      -webkit-animation: outerDrawIn 0.5s ease-out forwards 1.1333333333333333s, appearIn 0.1s ease-out forwards 1.1333333333333333s;
-      animation: outerDrawIn 0.5s ease-out forwards 1.1333333333333333s, appearIn 0.1s ease-out forwards 1.1333333333333333s;
-      -webkit-animation-iteration-count: 1, 1;
-      animation-iteration-count: 1, 1;
-    }
-
-    .hEFqBt {
-      opacity: 0;
-      stroke-dasharray: 76;
-      -webkit-animation: outerDrawIn 0.5s ease-out forwards 1.3333333333333333s, appearIn 0.1s ease-out forwards 1.3333333333333333s;
-      animation: outerDrawIn 0.5s ease-out forwards 1.3333333333333333s, appearIn 0.1s ease-out forwards 1.3333333333333333s;
-      -webkit-animation-iteration-count: 1, 1;
-      animation-iteration-count: 1, 1;
-    }
-
-    .dzEKCM {
-      opacity: 0;
-      stroke-dasharray: 70;
-      -webkit-animation: innerDrawIn 1s ease-in-out forwards 1.3666666666666667s, appearIn 0.1s linear forwards 1.3666666666666667s;
-      animation: innerDrawIn 1s ease-in-out forwards 1.3666666666666667s, appearIn 0.1s linear forwards 1.3666666666666667s;
-      -webkit-animation-iteration-count: infinite, 1;
-      animation-iteration-count: infinite, 1;
-    }
-
-    .DYnPx {
-      opacity: 0;
-      stroke-dasharray: 70;
-      -webkit-animation: innerDrawIn 1s ease-in-out forwards 1.5333333333333332s, appearIn 0.1s linear forwards 1.5333333333333332s;
-      animation: innerDrawIn 1s ease-in-out forwards 1.5333333333333332s, appearIn 0.1s linear forwards 1.5333333333333332s;
-      -webkit-animation-iteration-count: infinite, 1;
-      animation-iteration-count: infinite, 1;
-    }
-
-    .hjPEAQ {
-      opacity: 0;
-      stroke-dasharray: 70;
-      -webkit-animation: innerDrawIn 1s ease-in-out forwards 1.7000000000000002s, appearIn 0.1s linear forwards 1.7000000000000002s;
-      animation: innerDrawIn 1s ease-in-out forwards 1.7000000000000002s, appearIn 0.1s linear forwards 1.7000000000000002s;
-      -webkit-animation-iteration-count: infinite, 1;
-      animation-iteration-count: infinite, 1;
-    }
-
-    #loading-wrapper {
-      position: absolute;
-      width: 100vw;
-      height: 100vh;
-      display: -webkit-box;
-      display: -webkit-flex;
-      display: -ms-flexbox;
-      display: flex;
-      -webkit-align-items: center;
-      -webkit-box-align: center;
-      -ms-flex-align: center;
-      align-items: center;
-      -webkit-box-pack: center;
-      -webkit-justify-content: center;
-      -ms-flex-pack: center;
-      justify-content: center;
-      -webkit-flex-direction: column;
-      -ms-flex-direction: column;
-      flex-direction: column;
-    }
-
-    .logo {
-      width: 75px;
-      height: 75px;
-      margin-bottom: 20px;
-      opacity: 0;
-      -webkit-animation: fadeIn 0.5s ease-out forwards;
-      animation: fadeIn 0.5s ease-out forwards;
-    }
-
-    .text {
-      font-size: 32px;
-      font-weight: 200;
-      text-align: center;
-      color: rgba(255, 255, 255, 0.6);
-      opacity: 0;
-      -webkit-animation: fadeIn 0.5s ease-out forwards;
-      animation: fadeIn 0.5s ease-out forwards;
-    }
-
-    .dGfHfc {
-      font-weight: 400;
-    }
-  </style>
-  <div id="loading-wrapper">
-    <svg class="logo" viewBox="0 0 128 128" xmlns:xlink="http://www.w3.org/1999/xlink">
-      <title>GraphQL Playground Logo</title>
-      <defs>
-        <linearGradient id="linearGradient-1" x1="4.86%" x2="96.21%" y1="0%" y2="99.66%">
-          <stop stop-color="#E00082" stop-opacity=".8" offset="0%"></stop>
-          <stop stop-color="#E00082" offset="100%"></stop>
-        </linearGradient>
-      </defs>
-      <g>
-        <rect id="Gradient" width="127.96" height="127.96" y="1" fill="url(#linearGradient-1)" rx="4"></rect>
-        <path id="Border" fill="#E00082" fill-rule="nonzero" d="M4.7 2.84c-1.58 0-2.86 1.28-2.86 2.85v116.57c0 1.57 1.28 2.84 2.85 2.84h116.57c1.57 0 2.84-1.26 2.84-2.83V5.67c0-1.55-1.26-2.83-2.83-2.83H4.67zM4.7 0h116.58c3.14 0 5.68 2.55 5.68 5.7v116.58c0 3.14-2.54 5.68-5.68 5.68H4.68c-3.13 0-5.68-2.54-5.68-5.68V5.68C-1 2.56 1.55 0 4.7 0z"></path>
-        <path class="bglIGM" x="64" y="28" fill="#fff" d="M64 36c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8" style="transform: translate(100px, 100px);"></path>
-        <path class="ksxRII" x="95.98500061035156" y="46.510000228881836" fill="#fff" d="M89.04 50.52c-2.2-3.84-.9-8.73 2.94-10.96 3.83-2.2 8.72-.9 10.95 2.94 2.2 3.84.9 8.73-2.94 10.96-3.85 2.2-8.76.9-10.97-2.94"
-          style="transform: translate(100px, 100px);"></path>
-        <path class="cWrBmb" x="95.97162628173828" y="83.4900016784668" fill="#fff" d="M102.9 87.5c-2.2 3.84-7.1 5.15-10.94 2.94-3.84-2.2-5.14-7.12-2.94-10.96 2.2-3.84 7.12-5.15 10.95-2.94 3.86 2.23 5.16 7.12 2.94 10.96"
-          style="transform: translate(100px, 100px);"></path>
-        <path class="Wnusb" x="64" y="101.97999572753906" fill="#fff" d="M64 110c-4.43 0-8-3.6-8-8.02 0-4.44 3.57-8.02 8-8.02s8 3.58 8 8.02c0 4.4-3.57 8.02-8 8.02"
-          style="transform: translate(100px, 100px);"></path>
-        <path class="bfPqf" x="32.03982162475586" y="83.4900016784668" fill="#fff" d="M25.1 87.5c-2.2-3.84-.9-8.73 2.93-10.96 3.83-2.2 8.72-.9 10.95 2.94 2.2 3.84.9 8.73-2.94 10.96-3.85 2.2-8.74.9-10.95-2.94"
-          style="transform: translate(100px, 100px);"></path>
-        <path class="edRCTN" x="32.033552169799805" y="46.510000228881836" fill="#fff" d="M38.96 50.52c-2.2 3.84-7.12 5.15-10.95 2.94-3.82-2.2-5.12-7.12-2.92-10.96 2.2-3.84 7.12-5.15 10.95-2.94 3.83 2.23 5.14 7.12 2.94 10.96"
-          style="transform: translate(100px, 100px);"></path>
-        <path class="iEGVWn" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M63.55 27.5l32.9 19-32.9-19z"></path>
-        <path class="bsocdx" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M96 46v38-38z"></path>
-        <path class="jAZXmP" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M96.45 84.5l-32.9 19 32.9-19z"></path>
-        <path class="hSeArx" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M64.45 103.5l-32.9-19 32.9 19z"></path>
-        <path class="bVgqGk" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M32 84V46v38z"></path>
-        <path class="hEFqBt" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M31.55 46.5l32.9-19-32.9 19z"></path>
-        <path class="dzEKCM" id="Triangle-Bottom" stroke="#fff" stroke-width="4" d="M30 84h70" stroke-linecap="round"></path>
-        <path class="DYnPx" id="Triangle-Left" stroke="#fff" stroke-width="4" d="M65 26L30 87" stroke-linecap="round"></path>
-        <path class="hjPEAQ" id="Triangle-Right" stroke="#fff" stroke-width="4" d="M98 87L63 26" stroke-linecap="round"></path>
-      </g>
-    </svg>
-    <div class="text">Loading
-      <span class="dGfHfc">GraphQL Playground</span>
-    </div>
-  </div>
-
-  <div id="root" />
-  <script type="text/javascript">
-    window.addEventListener('load', function (event) {
-
-      const loadingWrapper = document.getElementById('loading-wrapper');
-      loadingWrapper.classList.add('fadeOut');
-
-
-      const root = document.getElementById('root');
-      root.classList.add('playgroundIn');
-
-      GraphQLPlayground.init(root, { endpoint: 'JUNIPER_GRAPHQL_URL', subscriptionEndpoint: 'JUNIPER_SUBSCRIPTIONS_URL' })
-    })
-  </script>
-</body>
-</html>
-  "##.replace("JUNIPER_GRAPHQL_URL", graphql_endpoint_url)
-     .replace("JUNIPER_SUBSCRIPTIONS_URL", subscriptions_endpoint)
+    include_str!("playground.html")
+        .replace("JUNIPER_URL", graphql_endpoint_url)
+        .replace("JUNIPER_SUBSCRIPTIONS_URL", subscriptions_endpoint)
 }
diff --git a/juniper_actix/src/lib.rs b/juniper_actix/src/lib.rs
index c18eeee1..baf0476f 100644
--- a/juniper_actix/src/lib.rs
+++ b/juniper_actix/src/lib.rs
@@ -515,8 +515,8 @@ mod tests {
             "text/html; charset=utf-8"
         );
         let body = take_response_body_string(resp).await;
-        assert!(body.contains("var GRAPHQL_URL = '/dogs-api/graphql';"));
-        assert!(body.contains("var GRAPHQL_SUBSCRIPTIONS_URL = '/dogs-api/subscriptions';"))
+        assert!(body.contains("var JUNIPER_URL = '/dogs-api/graphql';"));
+        assert!(body.contains("var JUNIPER_SUBSCRIPTIONS_URL = '/dogs-api/subscriptions';"))
     }
 
     #[actix_web::rt::test]
@@ -554,7 +554,9 @@ mod tests {
             "text/html; charset=utf-8"
         );
         let body = take_response_body_string(resp).await;
-        assert!(body.contains("GraphQLPlayground.init(root, { endpoint: '/dogs-api/graphql', subscriptionEndpoint: '/dogs-api/subscriptions' })"));
+        assert!(body.contains(
+            "endpoint: '/dogs-api/graphql', subscriptionEndpoint: '/dogs-api/subscriptions'",
+        ));
     }
 
     #[actix_web::rt::test]
diff --git a/juniper_warp/src/lib.rs b/juniper_warp/src/lib.rs
index d6ccc2c6..48adecc1 100644
--- a/juniper_warp/src/lib.rs
+++ b/juniper_warp/src/lib.rs
@@ -556,7 +556,7 @@ mod tests {
         );
         let body = String::from_utf8(response.body().to_vec()).unwrap();
 
-        assert!(body.contains("var GRAPHQL_URL = '/dogs-api/graphql';"));
+        assert!(body.contains("var JUNIPER_URL = '/dogs-api/graphql';"));
     }
 
     #[tokio::test]
@@ -614,7 +614,9 @@ mod tests {
         );
         let body = String::from_utf8(response.body().to_vec()).unwrap();
 
-        assert!(body.contains("GraphQLPlayground.init(root, { endpoint: '/dogs-api/graphql', subscriptionEndpoint: '/dogs-api/subscriptions' })"));
+        assert!(body.contains(
+            "endpoint: '/dogs-api/graphql', subscriptionEndpoint: '/dogs-api/subscriptions'",
+        ));
     }
 
     #[tokio::test]