diff --git a/NEWS.md b/NEWS.md
index 212fcd7444..160d219974 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -16,6 +16,8 @@
 * `ggplotly()` now respects `guide(aes = "none")` (e.g., `guide(fill = "none")`) when constructing legend entries. (#2067)
 * Fixed an issue with translating `GGally::ggcorr()` via `ggplotly()`. (#2012)
 * Fixed an issue where clearing a crosstalk filter would raise an error in the JS console (#2087)
+* Fixed an issue with `{crosstalk}` where running `selectionHandle.clear()` from another visual causes plotly to throw an error. (#2098)
+
 
 ## Improvements
 
diff --git a/inst/htmlwidgets/plotly.js b/inst/htmlwidgets/plotly.js
index 1155269d37..063da3ffd0 100644
--- a/inst/htmlwidgets/plotly.js
+++ b/inst/htmlwidgets/plotly.js
@@ -628,15 +628,15 @@ TraceManager.prototype.updateFilter = function(group, keys) {
 };
 
 TraceManager.prototype.updateSelection = function(group, keys) {
-  
-  if (keys !== null && !Array.isArray(keys)) {
+ 
+  if (keys !== null && keys !== undefined  && !Array.isArray(keys)) {
     throw new Error("Invalid keys argument; null or array expected");
   }
   
   // if selection has been cleared, or if this is transient
   // selection, delete the "selection traces"
   var nNewTraces = this.gd.data.length - this.origData.length;
-  if (keys === null || !this.highlight.persistent && nNewTraces > 0) {
+  if (keys === null || keys === undefined || !this.highlight.persistent && nNewTraces > 0) {
     var tracesToRemove = [];
     for (var i = 0; i < this.gd.data.length; i++) {
       if (this.gd.data[i]._isCrosstalkTrace) tracesToRemove.push(i);
@@ -655,7 +655,7 @@ TraceManager.prototype.updateSelection = function(group, keys) {
     }
   }
   
-  if (keys === null) {
+  if (keys === null || keys === undefined) {
     
     Plotly.restyle(this.gd, {"opacity": this.origOpacity});