diff --git a/src/components/gltf-model-plus.js b/src/components/gltf-model-plus.js
index fad11f667fb6c879fbc1505e056d9b7f39130684..b449ea9ae2c0248c380eae5c3027b07f4fafc3b7 100644
--- a/src/components/gltf-model-plus.js
+++ b/src/components/gltf-model-plus.js
@@ -1,4 +1,3 @@
-import { isFarsparkUrl, decodeFarsparkUrl } from "../utils/media-utils";
 const GLTFCache = {};
 
 AFRAME.GLTFModelPlus = {
@@ -182,15 +181,12 @@ function nextTick() {
   });
 }
 
-function cachedLoadGLTF(src, preferredTechnique, onProgress) {
+function cachedLoadGLTF(src, basePath, preferredTechnique, onProgress) {
   // Load the gltf model from the cache if it exists.
   if (!GLTFCache[src]) {
     GLTFCache[src] = new Promise((resolve, reject) => {
       const gltfLoader = new THREE.GLTFLoader();
-      // Farspark urls can't handle relative paths. Use the original url as the base path.
-      if (isFarsparkUrl(src)) {
-        gltfLoader.path = THREE.LoaderUtils.extractUrlBase(decodeFarsparkUrl(src));
-      }
+      gltfLoader.path = basePath;
       gltfLoader.preferredTechnique = preferredTechnique;
       gltfLoader.load(src, resolve, onProgress, reject);
     });
@@ -207,6 +203,7 @@ function cachedLoadGLTF(src, preferredTechnique, onProgress) {
 AFRAME.registerComponent("gltf-model-plus", {
   schema: {
     src: { type: "string" },
+    basePath: { type: "string", default: undefined },
     inflate: { default: false }
   },
 
@@ -247,7 +244,7 @@ AFRAME.registerComponent("gltf-model-plus", {
       }
 
       const gltfPath = THREE.LoaderUtils.extractUrlBase(src);
-      const model = await cachedLoadGLTF(src, this.preferredTechnique);
+      const model = await cachedLoadGLTF(src, this.data.basePath, this.preferredTechnique);
 
       // If we started loading something else already
       // TODO: there should be a way to cancel loading instead
diff --git a/src/utils/media-utils.js b/src/utils/media-utils.js
index 1c72a0fb18fa59bb87cb3763797f6c09377e8af7..e22efc18fbad8d9948fc80130fda291409bd8a53 100644
--- a/src/utils/media-utils.js
+++ b/src/utils/media-utils.js
@@ -8,31 +8,20 @@ if (process.env.NODE_ENV === "development") {
 export const resolveFarsparkUrl = async url => {
   const parsedUrl = new URL(url);
   if ((parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") || isHostWhitelisted(parsedUrl.hostname))
-    return url;
+    return [url, url];
 
-  return (await fetch(resolveMediaUrl, {
+  const mediaResponse = await fetch(resolveMediaUrl, {
     method: "POST",
     headers: { "Content-Type": "application/json" },
     body: JSON.stringify({ media: { url } })
-  }).then(r => r.json())).raw;
-};
-
-const farsparkRegex = /^farspark.*\.reticulum\.io$/;
-export const isFarsparkUrl = url => farsparkRegex.test(new URL(url).hostname);
-export const decodeFarsparkUrl = url => {
-  const parts = url.split("/");
-  return atob(parts[parts.length - 1]);
+  }).then(r => r.json());
+  return [mediaResponse.raw, mediaResponse.origin];
 };
 
 const staticContentMappings = {
   "poly.googleapis.com": "model/gltf"
 };
-const fetchContentType = async url => {
-  const staticContentType = staticContentMappings[new URL(isFarsparkUrl(url) ? decodeFarsparkUrl(url) : url).hostname];
-  return staticContentType
-    ? Promise.resolve(staticContentType)
-    : fetch(url, { method: "HEAD" }).then(r => r.headers.get("content-type"));
-};
+const fetchContentType = async url => fetch(url, { method: "HEAD" }).then(r => r.headers.get("content-type"));
 
 let interactableId = 0;
 const offset = { x: 0, y: 0, z: -1.5 };
@@ -51,7 +40,7 @@ export const spawnNetworkedImage = (src, contentType) => {
   return image;
 };
 
-export const spawnNetworkedInteractable = src => {
+export const spawnNetworkedInteractable = (src, basePath) => {
   const scene = AFRAME.scenes[0];
   const model = document.createElement("a-entity");
   model.id = "interactable-model-" + interactableId++;
@@ -62,7 +51,7 @@ export const spawnNetworkedInteractable = src => {
     offset: offset,
     selfDestruct: true
   });
-  model.setAttribute("gltf-model-plus", "src", src);
+  model.setAttribute("gltf-model-plus", { src, basePath });
   model.setAttribute("auto-box-collider", { resize: true });
   scene.appendChild(model);
   return model;
@@ -70,15 +59,14 @@ export const spawnNetworkedInteractable = src => {
 
 export const addMedia = async url => {
   try {
-    const farsparkUrl = await resolveFarsparkUrl(url);
-    console.log("resolved", url, farsparkUrl);
-
-    const contentType = await fetchContentType(farsparkUrl);
+    const [farsparkUrl, originUrl] = await resolveFarsparkUrl(url);
+    console.log("resolved", url, farsparkUrl, originUrl);
 
+    const contentType = staticContentMappings[new URL(originUrl).hostname] || (await fetchContentType(farsparkUrl));
     if (contentType.startsWith("image/") || contentType.startsWith("video/")) {
       return spawnNetworkedImage(farsparkUrl, contentType);
     } else if (contentType.startsWith("model/gltf") || url.endsWith(".gltf") || url.endsWith(".glb")) {
-      return spawnNetworkedInteractable(farsparkUrl);
+      return spawnNetworkedInteractable(farsparkUrl, THREE.LoaderUtils.extractUrlBase(originUrl));
     } else {
       throw new Error(`Unsupported content type: ${contentType}`);
     }
diff --git a/src/vendor/GLTFLoader.js b/src/vendor/GLTFLoader.js
index 754ae5d9460e80e176a928cc53ea75ab7a6f5212..52887bc9d43ccb377d20a2597bac8a1156c979f9 100644
--- a/src/vendor/GLTFLoader.js
+++ b/src/vendor/GLTFLoader.js
@@ -40,7 +40,7 @@ THREE.GLTFLoader = ( function () {
 
 			loader.setResponseType( 'arraybuffer' );
 
-			var farsparkURL = await resolveFarsparkUrl(url);
+			var [farsparkURL] = await resolveFarsparkUrl(url);
 
 			loader.load( farsparkURL, function ( data ) {
 
@@ -1623,7 +1623,7 @@ THREE.GLTFLoader = ( function () {
 
 		var options = this.options;
 
-		var farsparkURL = await resolveFarsparkUrl(resolveURL(bufferDef.uri, options.path));
+		var [farsparkURL] = await resolveFarsparkUrl(resolveURL(bufferDef.uri, options.path));
 
 		return new Promise( function ( resolve, reject ) {
 
@@ -1823,7 +1823,7 @@ THREE.GLTFLoader = ( function () {
 
     var urlToLoad = resolveURL(sourceURI, options.path);
     if (!hasBufferView){
-      urlToLoad = await resolveFarsparkUrl(urlToLoad);
+      [urlToLoad] = await resolveFarsparkUrl(urlToLoad);
     }
 
 		return Promise.resolve( sourceURI ).then( function ( sourceURI ) {