diff --git a/IO/Import/vtkGLTFImporter.cxx b/IO/Import/vtkGLTFImporter.cxx
index f5197e6ba6988e94f49b7a6057e012143f331f99..43cd4fb94280fa0cf13d3bea871b8c32d3a57c44 100644
--- a/IO/Import/vtkGLTFImporter.cxx
+++ b/IO/Import/vtkGLTFImporter.cxx
@@ -403,9 +403,9 @@ void vtkGLTFImporter::InitializeLoader()
 int vtkGLTFImporter::ImportBegin()
 {
   // Make sure we have a file to read.
-  if (!this->FileName)
+  if (!this->Stream && !this->FileName)
   {
-    vtkErrorMacro("A FileName must be specified.");
+    vtkErrorMacro("Neither FileName nor Stream has been specified.");
     return 0;
   }
 
@@ -422,21 +422,44 @@ int vtkGLTFImporter::ImportBegin()
 
   // Check extension
   std::vector<char> glbBuffer;
-  std::string extension = vtksys::SystemTools::GetFilenameLastExtension(this->FileName);
-  if (extension == ".glb")
+  if (this->Stream != nullptr)
   {
-    if (!this->Loader->LoadFileBuffer(this->FileName, glbBuffer))
+    // this->Stream is defined.
+    if (this->StreamIsBinary)
     {
-      vtkErrorMacro("Error loading binary data");
+      if (!this->Loader->LoadStreamBuffer(this->Stream, glbBuffer))
+      {
+        vtkErrorMacro("Error loading binary data");
+        return 0;
+      }
+    }
+
+    if (!this->Loader->LoadModelMetaDataFromStream(this->Stream, this->StreamURILoader))
+    {
+      vtkErrorMacro("Error loading model metadata");
       return 0;
     }
   }
-
-  if (!this->Loader->LoadModelMetaDataFromFile(this->FileName))
+  else
   {
-    vtkErrorMacro("Error loading model metadata");
-    return 0;
+    // this->FileName is defined.
+    std::string extension = vtksys::SystemTools::GetFilenameLastExtension(this->FileName);
+    if (extension == ".glb")
+    {
+      if (!this->Loader->LoadFileBuffer(this->FileName, glbBuffer))
+      {
+        vtkErrorMacro("Error loading binary data");
+        return 0;
+      }
+    }
+
+    if (!this->Loader->LoadModelMetaDataFromFile(this->FileName))
+    {
+      vtkErrorMacro("Error loading model metadata");
+      return 0;
+    }
   }
+
   if (!this->Loader->LoadModelData(glbBuffer))
   {
     vtkErrorMacro("Error loading model data");
@@ -1037,7 +1060,16 @@ bool vtkGLTFImporter::GetTemporalInformation(vtkIdType animationIndex, double fr
 void vtkGLTFImporter::PrintSelf(ostream& os, vtkIndent indent)
 {
   this->Superclass::PrintSelf(os, indent);
-  os << indent << "File Name: " << (this->FileName ? this->FileName : "(none)") << "\n";
+  os << indent;
+  if (this->Stream != nullptr)
+  {
+    os << "Stream (" << (this->StreamIsBinary ? "binary" : "ascii") << ")";
+  }
+  else
+  {
+    os << "File Name: " << (this->FileName ? this->FileName : "(none)");
+  }
+  os << "\n";
 }
 
 //------------------------------------------------------------------------------
diff --git a/IO/Import/vtkGLTFImporter.h b/IO/Import/vtkGLTFImporter.h
index 239d1d7fb75aa01a2a609d2144dbb2e387543cc4..c242f2a6f6a4facc8ebbb7fcb439994b8318fddd 100644
--- a/IO/Import/vtkGLTFImporter.h
+++ b/IO/Import/vtkGLTFImporter.h
@@ -51,16 +51,22 @@
 
 #include "vtkIOImportModule.h" // For export macro
 #include "vtkImporter.h"
-#include "vtkSmartPointer.h" // For SmartPointer
+#include "vtkResourceStream.h" // For Stream
+#include "vtkSmartPointer.h"   // For SmartPointer
+#include "vtkURILoader.h"      // For URILoader
 
 #include <map>    // For map
 #include <vector> // For vector
 
 VTK_ABI_NAMESPACE_BEGIN
+
+// Forward declarations
 class vtkActor;
 class vtkCamera;
 class vtkGLTFDocumentLoader;
+class vtkResourceStream;
 class vtkTexture;
+class vtkURILoader;
 
 class VTKIOIMPORT_EXPORT vtkGLTFImporter : public vtkImporter
 {
@@ -78,6 +84,40 @@ public:
   vtkGetFilePathMacro(FileName);
   ///@}
 
+  ///@{
+  /**
+   * Specify the glTF source stream to read from. When selecting the input method, `Stream` has a
+   * higher priority than `FileName` i.e. if a stream is provided, the filename is ignored.
+   *
+   * \note If the stream contains non-data URIs, specifying a custom uri loader is crucial.
+   * \sa SetStreamURILoader()
+   *
+   * \sa SetStreamIsBinary()
+   */
+  vtkSetSmartPointerMacro(Stream, vtkResourceStream);
+  vtkGetSmartPointerMacro(Stream, vtkResourceStream);
+  ///@}
+
+  ///@{
+  /**
+   * Specify a custom URI loader for non-data URIs in the input stream.
+   * \sa SetStream(), SetStreamIsBinary()
+   */
+  vtkSetSmartPointerMacro(StreamURILoader, vtkURILoader);
+  vtkGetSmartPointerMacro(StreamURILoader, vtkURILoader);
+  ///@}
+
+  ///@{
+  /**
+   * Set/Get whether the input stream is binary
+   *
+   * \sa SetStream()
+   */
+  vtkSetMacro(StreamIsBinary, bool);
+  vtkGetMacro(StreamIsBinary, bool);
+  vtkBooleanMacro(StreamIsBinary, bool);
+  ///@}
+
   /**
    * glTF defines multiple camera objects, but no default behavior for which camera should be
    * used. The importer will by default apply the asset's first camera. This accessor lets you use
@@ -167,6 +207,9 @@ protected:
   virtual void ApplyArmatureProperties(vtkActor* actor);
 
   char* FileName = nullptr;
+  vtkSmartPointer<vtkResourceStream> Stream;
+  vtkSmartPointer<vtkURILoader> StreamURILoader;
+  bool StreamIsBinary = false;
 
   std::map<int, vtkSmartPointer<vtkCamera>> Cameras;
   std::map<int, vtkSmartPointer<vtkTexture>> Textures;