diff --git a/pkg/drawing_crdt.d.ts b/pkg/drawing_crdt.d.ts
index 80516b57ed2f6061c94b73a6e95d6dc5928ee3f8..edb0f3f95c4aa79b8b9941373582f56d45ffe952 100644
--- a/pkg/drawing_crdt.d.ts
+++ b/pkg/drawing_crdt.d.ts
@@ -78,8 +78,9 @@ export class WasmCRDT {
   fetch_deltas(): void;
 /**
 * @param {Uint8Array} deltas 
+* @returns {bool} 
 */
-  apply_deltas(deltas: Uint8Array): void;
+  apply_deltas(deltas: Uint8Array): bool;
 /**
 * @returns {Uint8Array} 
 */
diff --git a/pkg/drawing_crdt.js b/pkg/drawing_crdt.js
index 206552175b5444d2dcf82e0fac2bfe48e55b9cb6..c5370fd61758dc4750df87ba0b98c95e7ead6bce 100644
--- a/pkg/drawing_crdt.js
+++ b/pkg/drawing_crdt.js
@@ -22,6 +22,15 @@ function takeObject(idx) {
     return ret;
 }
 
+function addHeapObject(obj) {
+    if (heap_next === heap.length) heap.push(heap.length + 1);
+    const idx = heap_next;
+    heap_next = heap[idx];
+
+    heap[idx] = obj;
+    return idx;
+}
+
 let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
 
 cachedTextDecoder.decode();
@@ -38,15 +47,6 @@ function getStringFromWasm0(ptr, len) {
     return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
 }
 
-function addHeapObject(obj) {
-    if (heap_next === heap.length) heap.push(heap.length + 1);
-    const idx = heap_next;
-    heap_next = heap[idx];
-
-    heap[idx] = obj;
-    return idx;
-}
-
 function debugString(val) {
     // primitive types
     const type = typeof val;
@@ -378,11 +378,13 @@ export class WasmCRDT {
     }
     /**
     * @param {Uint8Array} deltas
+    * @returns {bool}
     */
     apply_deltas(deltas) {
         var ptr0 = passArray8ToWasm0(deltas, wasm.__wbindgen_malloc);
         var len0 = WASM_VECTOR_LEN;
-        wasm.wasmcrdt_apply_deltas(this.ptr, ptr0, len0);
+        var ret = wasm.wasmcrdt_apply_deltas(this.ptr, ptr0, len0);
+        return ret !== 0;
     }
     /**
     * @returns {Uint8Array}
@@ -412,11 +414,6 @@ export const __wbindgen_object_drop_ref = function(arg0) {
     takeObject(arg0);
 };
 
-export const __wbindgen_string_new = function(arg0, arg1) {
-    var ret = getStringFromWasm0(arg0, arg1);
-    return addHeapObject(ret);
-};
-
 export const __wbg_onstroke_a7ff14dcafc1fe51 = function(arg0, arg1, arg2, arg3) {
     try {
         getObject(arg0).on_stroke(getStringFromWasm0(arg1, arg2), takeObject(arg3));
@@ -454,15 +451,16 @@ export const __wbindgen_object_clone_ref = function(arg0) {
     return addHeapObject(ret);
 };
 
-export const __widl_f_log_1_ = function(arg0) {
-    console.log(getObject(arg0));
-};
-
 export const __wbindgen_number_new = function(arg0) {
     var ret = arg0;
     return addHeapObject(ret);
 };
 
+export const __wbindgen_string_new = function(arg0, arg1) {
+    var ret = getStringFromWasm0(arg0, arg1);
+    return addHeapObject(ret);
+};
+
 export const __wbg_new_4fee7e2900033464 = function() {
     var ret = new Array();
     return addHeapObject(ret);
diff --git a/pkg/drawing_crdt_bg.d.ts b/pkg/drawing_crdt_bg.d.ts
index 035620f69cd89bf3d77da6bcd2c30a5f19714db3..c17ef37b3172675f42686c5d6ffb8acf535df355 100644
--- a/pkg/drawing_crdt_bg.d.ts
+++ b/pkg/drawing_crdt_bg.d.ts
@@ -16,7 +16,7 @@ export function wasmcrdt_get_stroke_points(a: number, b: number, c: number): num
 export function wasmcrdt_get_stroke_intervals(a: number, b: number, c: number): number;
 export function wasmcrdt_fetch_events(a: number): void;
 export function wasmcrdt_fetch_deltas(a: number): void;
-export function wasmcrdt_apply_deltas(a: number, b: number, c: number): void;
+export function wasmcrdt_apply_deltas(a: number, b: number, c: number): number;
 export function wasmcrdt_get_state_vector(a: number, b: number): void;
 export function wasmcrdt_fetch_deltas_from_state_vector(a: number, b: number, c: number, d: number, e: number): void;
 export function __wbindgen_malloc(a: number): number;
diff --git a/pkg/drawing_crdt_bg.wasm b/pkg/drawing_crdt_bg.wasm
index 4612d38758c6d8098454e1226855791e71dc2b27..8ffddf20a889254f8b02cdbe299878e0eb936785 100644
Binary files a/pkg/drawing_crdt_bg.wasm and b/pkg/drawing_crdt_bg.wasm differ
diff --git a/src/crdt.rs b/src/crdt.rs
index ea56ba1c1fd8007fbc00561cb0b680347f03eeaa..d4baeb29d2ff657f0a96d40b21f6dfbf817a121b 100644
--- a/src/crdt.rs
+++ b/src/crdt.rs
@@ -1708,20 +1708,22 @@ impl CRDT {
         let mut deltas = HashMap::new();
         std::mem::swap(&mut self.deltas, &mut deltas);
 
-        web_sys::console::log_1(&format!("temporal deltas: {:?}", deltas).into());
+        //web_sys::console::log_1(&format!("temporal deltas: {:?}", deltas).into());
 
         self.event_listener.on_deltas(DeltaVec(deltas));
     }
 
-    pub fn apply_deltas(&mut self, deltas: DeltaVec) {
+    pub fn apply_deltas(&mut self, deltas: DeltaVec) -> bool {
         let deltas = deltas.0;
 
         if deltas.is_empty() {
-            return;
+            return false;
         };
 
         let mut crdt = self.crdt.borrow_mut();
 
+        let mut changed = false;
+
         crdt.dirty();
 
         for (stroke_id, stroke_delta) in deltas {
@@ -1743,15 +1745,23 @@ impl CRDT {
             };
 
             if !stroke_delta.points.is_empty() {
-                stroke.points.dirty();
+                let old_len = stroke.points.len();
 
                 stroke.points.extend(stroke_delta.points.into_iter());
+
+                if stroke.points.len() != old_len {
+                    stroke.points.dirty();
+                    changed = true;
+                }
             }
 
             if stroke.intervals.union(&stroke_delta.intervals) {
-                stroke.intervals.dirty()
-            };
+                stroke.intervals.dirty();
+                changed = true;
+            }
         }
+
+        changed
     }
 
     pub fn get_state_vector(&mut self) -> &StateVec {
@@ -1825,8 +1835,8 @@ impl CRDT {
 
         let mut deltas = HashMap::new();
 
-        web_sys::console::log_1(&format!("local state: {:?}", self.state).into());
-        web_sys::console::log_1(&format!("remote state: {:?}", remote_state).into());
+        //web_sys::console::log_1(&format!("local state: {:?}", self.state).into());
+        //web_sys::console::log_1(&format!("remote state: {:?}", remote_state).into());
 
         for (user, strokes_state) in &self.state.strokes {
             let strokes = &crdt.get(user).unwrap().strokes;
@@ -1924,7 +1934,7 @@ impl CRDT {
             }
         }
 
-        web_sys::console::log_1(&format!("deltas from state: {:?}", deltas).into());
+        //web_sys::console::log_1(&format!("deltas from state: {:?}", deltas).into());
 
         self.event_listener
             .on_deltas_from_state(user, DeltaVec(deltas))
diff --git a/src/lib.rs b/src/lib.rs
index a81c130e809e37af7f982c711ac68e3432e23789..c9f10b11d446d92b5fedc0702c655763c7d0537a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -148,7 +148,7 @@ impl WasmCRDT {
         self.0.fetch_deltas()
     }
 
-    pub fn apply_deltas(&mut self, deltas: Box<[u8]>) -> Result<(), JsValue> {
+    pub fn apply_deltas(&mut self, deltas: Box<[u8]>) -> Result<bool, JsValue> {
         let deltas = match bincode::deserialize(&packing::unpack(&deltas)) {
             Ok(deltas) => deltas,
             Err(error) => return Err(Error::new(&format!("{:?}", error)).into()),