You can use AfterProperties, at least in ItemUpdated events. You'll need to sniff the contents of these dictionaries out using the debugger because they're totally not intuitive and as you likely know not documented anywhere.
In my example, I'm using ItemUpdated to update an Item (triggering another ItemUpdated), and you can infer by inspecting the dictionary whether the item was updated by your event receiver or via the UI.
If an item (this is a slightly modified Task) has been updated via the UI, I'll see 17 items in the AfterProperties:
Now in my trivial example I'l just updating the title of the task:
In the subsequent run of the RER, there are only two items in AfterProperties, the Title, and a system value:
so with this in mind I've just written a method WasUpdatedByEventReceiver, which checks the AfterProperties to see if the update was a valid update or a false one triggered by the RER:
private bool WasUpdatedByEventReceiver(SPRemoteEventProperties properties)
return (properties.ItemEventProperties.AfterProperties.Count == 2 && properties.ItemEventProperties.AfterProperties.ContainsKey("Title"));
Is it perfect? No. Does it work? Yes.
See also(mine): https://derekgusoff.wordpress.com/2017/11/08/remote-event-receivers-youre-all-doing-it-wrong/