GraphAware Audit Module

Eric Spiegelberg

by Eric Spiegelberg
· 7 min read

The GraphAware Audit Module seamlessly and transparently captures the full audit history who, when, and how a graph was modified.

A demonstration of the audit module is best viewed during live interactions with Neo4j, which is why GraphAware has published this screencast on the GraphAware YouTube channel. A textual summary of the screencast, this post will quickly introduce modules, discuss the GraphAware Framework, and then dive into the audit module.

What is a module?

Modules are small, custom built software packages, also commonly called plugins, that live inside of Neo4j and enhance it to provide advanced functionality. The type of advanced functionality that can be developed is unlimited, constrained only by the requirements of the business use case.

Among others, examples of modules include GraphAware products, such as:

  • The UUID module, which transparently assigns a universally unique identifier (UUID) to newly created nodes and relationships and ensures that the UUID can not be changed or deleted

  • The Expire module, which automatically deletes nodes and relationships from Neo4j after their expiration date or specified time-to-live has been reached

  • The Neo4j2Elastic module, which transparently and asynchronously replicates data from Neo4j to ElasticSearch

GraphAware Framework

Having covered what a module is, let’s next briefly discuss the GraphAware Framework.

The GraphAware Framework accelerates and simplifies the module development process by providing commonly needed functionality and features. Open source and publicly available on Github, many of GraphAware’s products, including each of the previously mentioned example modules and the audit module, make use of the GraphAware Framework.

Audit Module

GraphAware’s Audit module seamlessly and transparently keeps track of changes made to the data inside your Neo4j database. This is accomplished by capturing audit metadata in a separate graph structure within Neo4j, providing an audit trail of who, when, and how data has changed.

Audit Module: Demo

A demonstration of the audit module is best viewed during live interactions with Neo4j, which is why GraphAware has published this demo screencast on the GraphAware YouTube channel. While there is no substitute for seeing it live, we’ll use screenshots of the screencast here to convey the same information.

Starting with an empty Neo4j instance, let’s use Cypher to create a node:

 CREATE (n:Airplane {engines: 1}) RETURN n

The above Cypher statement creates a node with a label of ‘Airplane’ and a property, the number of engines this airplane has, with a value of 1.

Next, let’s query the database for all available information:


The above query returns the following graph:

Figure 1

Looking at Figure 1, our airplane node is present, as expected, and is shown in blue. We will refer to our airplane node later as our transaction target node; more on this shortly.

In addition to our airplane node there is quite a lot of additional data, all of it created by the audit module, with labels prefixed with _GA_Adudit. This audit module generated information includes:

  1. A _GA_Adudit_User node, displayed in yellow, which captures the user who performed the transaction. Because we executed a Cypher statement in the Neo4j Browser console, the recorded user is the one logged in to the Neo4j Browser (ie: “neo4j”).

  2. Two _GA_Audit_Tx nodes, displayed in purple, which capture metadata about the executed transaction, such as its timestamp.

  3. A _GA_Audit_NodeCreated node, displayed in gray, which captures the action of the transaction, such as if a target node was created, updated, or deleted. This node also contains a mirror of the data and labels assigned to the transaction target node(s), which in this case is our airplane created from the Cypher statement. In other words, the gray node contains exactly the same information as that assigned to our airplane, creating a “snapshot” of our airplane’s state at this particular point in time.

  4. A _GA_Audit_NodeProxy node, displayed in green, which contains a property named uuid and whose value matches the UUID value assigned to our airplane node. This is accomplished by the audit module’s underlying use of GraphAware’s UUID module, which assigns all new nodes and relationships a UUID. The fact that all nodes and relationships possess a unique id allows the audit module to make use this id as a property on the _GA_Audit_NodeProxy, in our case referencing the airplane and specifying it as the target of the audited transaction.

Let’s continue our exploration by using Cypher to modify our newly created node:

 MATCH (n:Airplane) SET n.gps=true

The above Cypher statement adds a “gps” property to our airplane, setting it’s value to true. Once again querying Neo4j for all available data, we are returned the following graph:

Figure 2

Looking at Figure 2, our graph now looks quite different: there are three purple nodes (rather than two), two gray nodes (rather than one), and additional relationships among them.

The fact that there are addition purple and gray nodes reflects the fact that an additional transaction has been performed. As these nodes capture information on each executed transaction, should we execute a third transaction, something we will do shortly, there will be (you guessed it) four purple and three gray nodes.

Looking at the right hand side of the graph, we once again have the blue node, representing our airplane, which now has a gps property. We also see:

  1. A new _GA_Audit_NodeUpdated node, displayed in gray, which captures that the airplane node was updated in the most recent transaction. Looking at this node’s properties, we once again see the snapshot of our airplane node’s data, including the newly added ‘gps’ property.

  2. The LAST_ACTION relationship, which previously existed between the green and the _GA_Audit_NodeCreated node, now exists between the green and the new _GA_Audit_NodeUpdated node and that there is now a relationship between the two gray nodes. These relationships make it easy to query the full audit trail of how the data in your graph has changed over time.

Next, let’s walk through what happens when a node’s property is removed, such as by removing our airplane’s gps property.

 MATCH (n:Airplane) REMOVE n.gps

Once again querying Neo4j for all available data, we are returned the following graph:

Figure 3

Looking at Figure 3, the graph once again looks quite different. Following the pattern from previous exploration, we see an additional set of purple and gray nodes and relationships that correspond to the execution of another transaction. From this graph we see:

  1. An additional _GA_Audit_NodeUpdated node which captures that the airplane node was updated in the previous transaction. Looking at this node, you once again see a mirror of the airplane node’s state; in this case, the gps property has been removed

  2. As with before, the LAST_ACTION relationship has been reassigned to our most recent _GA_Audit_NodeUpdated node, once again make it trivial to query for the most recent transaction.

While we have so far only demonstrated transactions that operate on a single node, the audit module correctly handles complex transactions that operate on numerous nodes and relationships, providing a full audit history of every change.

Accessing the Audit Data

The capture of this audit information is very powerful and can be access in three ways:

  • Querying the database with Cypher

  • Querying the database with Cypher function

  • Making use of a REST API

The first option, querying the database, is a standard exercise in using Cypher. The audit subgraph provides many convenient relationships, such as _GA_AUDIT_LAST_ACTION or _GA_AUDIT_PREVIOUS_TRANSACTION, that make it easy to traverse the full audit history.

The second option, using a Cypher function provided by the module, allows you obtain the audit metadata in JSON format through simple Cypher statements without having to have firsthand knowledge of the audit subgraph structure. A function example, including pagination arguments, is:

 RETURN ga.audit.auditTrail(10, 0) AS auditTrail

The execution of this query returns the following results:

Figure 4

Finally, the audit module also provides a convenient REST API which offers many capabilities, including the retrieval of audit data for a specific node or relationship by its UUID. Using any REST client, such as a web browser, and providing the same credentials used to access the Neo4j Browser, the audit data in JSON format can be seen below.

Figure 5

Getting the Audit Module

The audit module is available from GraphAware under a commercial license, which includes 24x7 email and phone support, a guaranteed SLA, and new feature requests implemented with high priority. Please contact GraphAware for pricing customized to your specific use case.


In conclusion, Modules are plugins that live inside Neo4j, providing advanced functionality.

The GraphAware Framework simplifies the module development process and provides commonly needed functionality and features.

The GraphAware Audit Module seamlessly and transparently captures the full audit history of who, when, and how a graph was modified. This audit information is fully available through traditional Cypher queries, a Cypher function, or through the provided REST API.

Share this blog post: