diff --git a/Documentation/release/9.2.md b/Documentation/release/9.2.md
index 68eb8c66088d9b00d2d9700e1f33cb565d8628b9..58de2b358e5bcc9efdb62b4f2af102379ce9056b 100644
--- a/Documentation/release/9.2.md
+++ b/Documentation/release/9.2.md
@@ -174,6 +174,10 @@ o = vtkPoints() # o is actually an instance of foo
 ### Web
 
 - Fix a memory leak in `vtkWebApplication`.
+- The render window serializers were updated to better map VTK options to VTK.js options. This includes font coloring for scalar bars and color transfer function discretization.
+- `vtkDataSetSurfaceFilter` is used in place of `vtkGeometryFilter`
+- The generic mapper serializer now uses `vtkDataSetSurfaceFilter` to always extract a surface from the input dataset.
+- Python `print` statements were changed to DEBUG logging statements.
 
 [](#changes-third-party)
 ### Third Party
diff --git a/Web/Python/vtkmodules/web/protocols.py b/Web/Python/vtkmodules/web/protocols.py
index 01e045d9f645e78bd4481f6b820553a474d64b67..598a8645d8383d315bfa0dd2a18d6e37bc3dab2d 100644
--- a/Web/Python/vtkmodules/web/protocols.py
+++ b/Web/Python/vtkmodules/web/protocols.py
@@ -742,7 +742,7 @@ class vtkWebLocalRendering(vtkWebProtocol):
     def __init__(self, **kwargs):
         super(vtkWebLocalRendering, self).__init__()
         initializeSerializers()
-        self.context = SynchronizationContext(True)
+        self.context = SynchronizationContext()
         self.trackingViews = {}
         self.mtime = 0
 
diff --git a/Web/Python/vtkmodules/web/render_window_serializer.py b/Web/Python/vtkmodules/web/render_window_serializer.py
index 223550005e6662167deaccbfcbdc20adbe97dab2..54318676ae2c8c2bdd1f2d1884577a66f7621925 100644
--- a/Web/Python/vtkmodules/web/render_window_serializer.py
+++ b/Web/Python/vtkmodules/web/render_window_serializer.py
@@ -1,4 +1,5 @@
 import io
+import logging
 import struct
 import time
 import zipfile
@@ -16,6 +17,9 @@ from vtkmodules.vtkFiltersGeometry import vtkCompositeDataGeometryFilter
 from vtkmodules.vtkFiltersGeometry import vtkDataSetSurfaceFilter
 from vtkmodules.vtkRenderingCore import vtkColorTransferFunction
 
+logger = logging.getLogger(__name__)
+# Always DEBUG level for this logger. Users can change this
+logger.setLevel(logging.DEBUG)
 
 # -----------------------------------------------------------------------------
 # Array helpers
@@ -61,12 +65,10 @@ def linspace(start, stop, num):
 
 
 class SynchronizationContext:
-    def __init__(self, debug=False):
+    def __init__(self):
         self.dataArrayCache = {}
         self.lastDependenciesMapping = {}
         self.ingoreLastDependencies = False
-        self.debugSerializers = debug
-        self.debugAll = debug
 
     def setIgnoreLastDependencies(self, force):
         self.ingoreLastDependencies = force
@@ -80,8 +82,7 @@ class SynchronizationContext:
         cacheTime = cacheObj["mTime"]
 
         if cacheTime != array.GetMTime():
-            if context.debugAll:
-                print(" ***** ERROR: you asked for an old cache key! ***** ")
+            logger.debug(" ***** ERROR: you asked for an old cache key! ***** ")
 
         if array.GetDataType() == 12:
             # IdType need to be converted to Uint32
@@ -180,11 +181,7 @@ def serializeInstance(parent, instance, instanceId, context, depth):
     if serializer:
         return serializer(parent, instance, instanceId, context, depth)
 
-    if context.debugSerializers:
-        print(
-            "%s!!!No serializer for %s with id %s"
-            % (pad(depth), instanceType, instanceId)
-        )
+    logger.error(f"!!!No serializer for {instanceType} with id {instanceId}")
 
     return None
 
@@ -369,7 +366,7 @@ def extractRequiredFields(
     extractedFields, parent, dataset, context, requestedFields=["Normals", "TCoords"]
 ):
     arrays_to_export = set()
-    export_all = '*' in requestedFields
+    export_all = "*" in requestedFields
     # Identify arrays to export
     if not export_all:
         # FIXME should evolve and support funky mapper which leverage many arrays
@@ -380,7 +377,7 @@ def extractRequiredFields(
             colorArrayName = (
                 mapper.GetArrayName() if arrayAccessMode == 1 else mapper.GetArrayId()
             )
-            colorMode = mapper.GetColorMode()
+            # colorMode = mapper.GetColorMode()
             scalarMode = mapper.GetScalarMode()
             if scalarVisibility and scalarMode in (1, 3):
                 array_to_export = dataset.GetPointData().GetArray(colorArrayName)
@@ -393,20 +390,26 @@ def extractRequiredFields(
                     array_to_export = dataset.GetCellData().GetScalars()
                 arrays_to_export.add(array_to_export)
             if scalarVisibility and scalarMode == 0:
-              array_to_export = dataset.GetPointData().GetScalars()
-              if array_to_export is None:
+                array_to_export = dataset.GetPointData().GetScalars()
+                if array_to_export is None:
                     array_to_export = dataset.GetCellData().GetScalars()
-              arrays_to_export.add(array_to_export)
+                arrays_to_export.add(array_to_export)
 
         if parent and parent.IsA("vtkTexture") and dataset.GetPointData().GetScalars():
             arrays_to_export.add(dataset.GetPointData().GetScalars())
 
         arrays_to_export.update(
-            [getattr(dataset.GetPointData(), "Get" + requestedField, lambda : None)() for requestedField in requestedFields]
+            [
+                getattr(dataset.GetPointData(), "Get" + requestedField, lambda: None)()
+                for requestedField in requestedFields
+            ]
         )
 
     # Browse all arrays
-    for location, field_data in [('pointData', dataset.GetPointData()), ('cellData', dataset.GetCellData())]:
+    for location, field_data in [
+        ("pointData", dataset.GetPointData()),
+        ("cellData", dataset.GetCellData()),
+    ]:
         for array_index in range(field_data.GetNumberOfArrays()):
             array = field_data.GetArray(array_index)
             if export_all or array in arrays_to_export:
@@ -414,7 +417,11 @@ def extractRequiredFields(
                 if arrayMeta:
                     arrayMeta["location"] = location
                     attribute = field_data.IsArrayAnAttribute(array_index)
-                    arrayMeta["registration"] = "set" + field_data.GetAttributeTypeAsString(attribute) if attribute >= 0 else 'addArray'
+                    arrayMeta["registration"] = (
+                        "set" + field_data.GetAttributeTypeAsString(attribute)
+                        if attribute >= 0
+                        else "addArray"
+                    )
                     extractedFields.append(arrayMeta)
 
 # -----------------------------------------------------------------------------
@@ -434,8 +441,7 @@ def genericActorSerializer(parent, actor, actorId, context, depth):
     if actorVisibility:
         mapper = None
         if not hasattr(actor, "GetMapper"):
-            if context.debugAll:
-                print("This actor does not have a GetMapper method")
+            logger.debug("This actor does not have a GetMapper method")
         else:
             mapper = actor.GetMapper()
 
@@ -452,8 +458,7 @@ def genericActorSerializer(parent, actor, actorId, context, depth):
         if hasattr(actor, "GetProperty"):
             prop = actor.GetProperty()
         else:
-            if context.debugAll:
-                print("This actor does not have a GetProperty method")
+            logger.debug("This actor does not have a GetProperty method")
 
         if prop:
             propId = getReferenceId(prop)
@@ -469,8 +474,7 @@ def genericActorSerializer(parent, actor, actorId, context, depth):
         if hasattr(actor, "GetTexture"):
             texture = actor.GetTexture()
         else:
-            if context.debugAll:
-                print("This actor does not have a GetTexture method")
+            logger.debug("This actor does not have a GetTexture method")
 
         if texture:
             textureId = getReferenceId(texture)
@@ -522,8 +526,7 @@ def genericVolumeSerializer(parent, actor, actorId, context, depth):
     if actorVisibility:
         mapper = None
         if not hasattr(actor, "GetMapper"):
-            if context.debugAll:
-                print("This actor does not have a GetMapper method")
+            logger.debug("This actor does not have a GetMapper method")
         else:
             mapper = actor.GetMapper()
 
@@ -540,8 +543,7 @@ def genericVolumeSerializer(parent, actor, actorId, context, depth):
         if hasattr(actor, "GetProperty"):
             prop = actor.GetProperty()
         else:
-            if context.debugAll:
-                print("This actor does not have a GetProperty method")
+            logger.debug("This actor does not have a GetProperty method")
 
         if prop:
             propId = getReferenceId(prop)
@@ -588,8 +590,7 @@ def textureSerializer(parent, texture, textureId, context, depth):
     if hasattr(texture, "GetInput"):
         dataObject = texture.GetInput()
     else:
-        if context.debugAll:
-            print("This texture does not have GetInput method")
+        logger.debug("This texture does not have GetInput method")
 
     if dataObject:
         dataObjectId = "%s-texture" % textureId
@@ -633,10 +634,15 @@ def genericMapperSerializer(parent, mapper, mapperId, context, depth):
         mapper.GetInputAlgorithm().Update()
         dataObject = mapper.GetInputDataObject(0, 0)
     else:
-        if context.debugAll:
-            print("This mapper does not have GetInputDataObject method")
+        logger.debug("This mapper does not have GetInputDataObject method")
 
     if dataObject:
+        if dataObject.IsA("vtkDataSet"):
+            alg = vtkDataSetSurfaceFilter()
+            alg.SetInputData(dataObject)
+            alg.Update()
+            dataObject = alg.GetOutput()
+
         dataObjectId = "%s-dataset" % mapperId
         dataObjectInstance = serializeInstance(
             mapper, dataObject, dataObjectId, context, depth + 1
@@ -651,8 +657,7 @@ def genericMapperSerializer(parent, mapper, mapperId, context, depth):
     if hasattr(mapper, "GetLookupTable"):
         lookupTable = mapper.GetLookupTable()
     else:
-        if context.debugAll:
-            print("This mapper does not have GetLookupTable method")
+        logger.debug("This mapper does not have GetLookupTable method")
 
     if lookupTable:
         lookupTableId = getReferenceId(lookupTable)
@@ -661,7 +666,9 @@ def genericMapperSerializer(parent, mapper, mapperId, context, depth):
         )
         if lookupTableInstance:
             dependencies.append(lookupTableInstance)
-            calls.append(["setLookupTable", [wrapId(lookupTableId)]])
+            calls.append(
+                ["setLookupTable", [wrapId(lookupTableId)]]
+            )
 
     if dataObjectInstance:
         colorArrayName = (
@@ -712,8 +719,7 @@ def genericVolumeMapperSerializer(parent, mapper, mapperId, context, depth):
         mapper.GetInputAlgorithm().Update()
         dataObject = mapper.GetInputDataObject(0, 0)
     else:
-        if context.debugAll:
-            print("This mapper does not have GetInputDataObject method")
+        logger.debug("This mapper does not have GetInputDataObject method")
 
     if dataObject:
         dataObjectId = "%s-dataset" % mapperId
@@ -985,8 +991,7 @@ def polydataSerializer(parent, dataset, datasetId, context, depth, requested_fie
             "properties": properties,
         }
 
-    if context.debugAll:
-        print("This dataset has no points!")
+    logger.debug("This dataset has no points!")
     return None
 
 
@@ -1168,8 +1173,7 @@ def scalarBarActorSerializer(parent, actor, actorId, context, depth):
     if hasattr(actor, "GetProperty"):
         prop = actor.GetProperty()
     else:
-        if context.debugAll:
-            print("This scalarBarActor does not have a GetProperty method")
+        logger.debug("This scalarBarActor does not have a GetProperty method")
 
         if prop:
             propId = getReferenceId(prop)
@@ -1184,16 +1188,6 @@ def scalarBarActorSerializer(parent, actor, actorId, context, depth):
     width = actor.GetWidth()
     height = actor.GetHeight()
 
-    # axisTitlePixelOffset = actor.GetTextPad()
-    # position = actor.GetPosition()
-    # position2 = actor.GetPosition2()
-    # print(f'axisTitlePixelOffset: {axisTitlePixelOffset}')
-    # print(f'axisLabel: {axisLabel}')
-    # print(f'width: {width}')
-    # print(f'height: {height}')
-    # print(f'position: {position}')
-    # print(f'position2: {position2}')
-
     return {
         "parent": getReferenceId(parent),
         "id": actorId,
@@ -1218,18 +1212,21 @@ def scalarBarActorSerializer(parent, actor, actorId, context, depth):
             "boxSize": [width, height],
             "axisTitlePixelOffset": 36.0,
             "axisTextStyle": {
-                "fontColor": "white",
+                "fontColor": actor.GetTitleTextProperty().GetColor(),
                 "fontStyle": "normal",
                 "fontSize": 18,
                 "fontFamily": "serif",
             },
             "tickLabelPixelOffset": 14.0,
             "tickTextStyle": {
-                "fontColor": "white",
+                "fontColor": actor.GetTitleTextProperty().GetColor(),
                 "fontStyle": "normal",
                 "fontSize": 14,
                 "fontFamily": "serif",
             },
+            "drawNanAnnotation": actor.GetDrawNanAnnotation(),
+            "drawBelowRangeSwatch": actor.GetDrawBelowRangeSwatch(),
+            "drawAboveRangeSwatch": actor.GetDrawAboveRangeSwatch(),
         },
         "calls": calls,
         "dependencies": dependencies,