rrweb icon indicating copy to clipboard operation
rrweb copied to clipboard

Retrieving event metadata from node id

Open jay-khatri opened this issue 5 years ago • 13 comments

Hi there. As discussed in another issue, I'm using the event-cast to get a stream of events as the replay is happening. I'd like to be able to get more metadata about each event, however. For example, for a click event, how can I get the name/id of the div that was clicked?

Is there a way to search the node map in some way? It looks like the replayer doesn't have any exported methods for this.

jay-khatri avatar Aug 22 '20 22:08 jay-khatri

Seems like mirror.getNode(id) would to the trick? It looks like mirror.map is being populated here on the rebuild: https://sourcegraph.com/github.com/rrweb-io/rrweb/-/blob/src/replay/index.ts#L412

Could mirror (or the map) be exported in the Replayer? Or alternatively, some more metadata on each event would work as well.

jay-khatri avatar Aug 22 '20 22:08 jay-khatri

I believe mirror is already exported: https://github.com/rrweb-io/rrweb/blob/master/src/index.ts#L15

Yuyz0112 avatar Aug 24 '20 04:08 Yuyz0112

Hi @Yuyz0112 , sorry to bother here. I'm using mirror.getNode to retrieve node metadat (tagName, attributes, etc.) for each event, however, it seems like the data in mirror.map is dynamically changing as the replay is happening.

Is this observation correct? And if so, do you mind directing me to the right place to see how this works?

And beyond that, is there any way that I can arbitrarily request the data for any node id at any time? I'd like to make a nice UI that shows all the events/elements as the player is happening.

jay-khatri avatar Sep 23 '20 04:09 jay-khatri

Friendly reminder here @Yuyz0112 .

jay-khatri avatar Sep 29 '20 23:09 jay-khatri

@jay-khatri

Sorry for the late.

I'd like to make a nice UI that shows all the events/elements as the player is happening.

This is a good feature-request I'd love to work on. And you are right, the DOM map is a map from id to element object, which is dynamically changed during the replay since elements are adding and removing from the document.

I think we can provide a feature which can build a static map from id to some element attributes, like CSS path and tag name, by replaying all the events in a background mode. It may not be a good idea to keep all the element object all the time, since it may cause some complex memory problem.

So could tell me the info your need to store in this static map?

Yuyz0112 avatar Oct 01 '20 14:10 Yuyz0112

Hi @Yuyz0112 , no worries!

My use case for this feature is:

  1. being able to show a nice UI of events (as discussed)
  2. indexing each session based on these attributes.

Therefore, it would be nice to have access to this map via record((e) => ...), so that indexing can be done asynchronously on the server. Now that I think of it, I could filter the event that's emitted in record to create the map myself 🤔 , but I might still have some trouble with looking up the attributes I want.

Some things I'd like to have in the static map:

  • css selectors/path
  • event id / timestamp
  • node.attributes, node.tagName

jay-khatri avatar Oct 01 '20 16:10 jay-khatri

@Yuyz0112 I've taken a closer look at the implementation of this, and it seems there could be an event emitter that outputs a serializedNodeWithId whenever this method is called. Then, in the client code, I can add a custom method that writes to my backend, for example.

On the replay side, your approach of replaying all the events in a background mode makes a lot of sense.

Overall, I'm thinking its probably best to decouple the replay/record implementations of this feature, but any thoughts here? I'd also be happy to help; maybe I can work on the record part?

jay-khatri avatar Oct 01 '20 23:10 jay-khatri

Yep, you can try the record part!

Yuyz0112 avatar Oct 03 '20 15:10 Yuyz0112

Hi @Yuyz0112 , I've been thinking about how this should be implemented and here's my thoughts.

In rrweb-snapshot here, the idNodeMap is being populated for every serialized node (and its respective children). Ideally, whenever a node is added to this map, I'd like a method to get called so that it can be picked up by the client code via record.

What I'm thinking is to extend the mirror type so that it looks like:

export type Mirror = {
  getId: (n: INode) => number;
  getNode: (id: number) => INode \| null;
  removeNodeFromMap: (n: INode) => void;
  has: (id: number) => boolean;
  // new
  setNode: (n: INode, id: number)
  _map: idNodeMap;
  onNewEntry: ()...
};

And rather than explicitly setting the new member of the map via map[], we call setNode so that we can pick up changes and run onNewEntry() as an option to record. Further down the line, we use setNode to prepopulate the _map when replay happens as well.

Thoughts?

jay-khatri avatar Oct 07 '20 21:10 jay-khatri

@Yuyz0112 thought more about this, and I don't actually need the record feature in the short term. I would, however, like to have the replay part. Do you mind directing me to the right place to start looking at:

build[ing] a static map from id to some element attributes, like CSS path and tag name, by replaying all the events in a background mode

jay-khatri avatar Oct 09 '20 18:10 jay-khatri

Ping here! @Yuyz0112 (sorry to bother)

jay-khatri avatar Oct 17 '20 20:10 jay-khatri

@jay-khatri I've sent you a draft implementation via slack.

Yuyz0112 avatar Oct 19 '20 14:10 Yuyz0112

I am very interested in this. How is it going? @Yuyz0112 @jay-khatri

OPY-bbt avatar Jun 30 '22 02:06 OPY-bbt