July 23, 2026
The Bottom Line Up Front

C4ADS has released followthemoney-neomodel, an open-source tool that automatically converts the Follow the Money data standard into Python classes for Neo4j, letting analysts build and query investigative networks without writing Cypher or custom schema code.

FtM is core to how C4ADS structures data across investigations, but until now, using its vocabulary in a graph database meant hand-writing and maintaining a Python class for every one of FtM’s entity types. followthemoney-neomodel removes that step. It generates FtM’s full vocabulary as ready-to-use Python classes automatically, so analysts and developers can build in ordinary Python, with no Cypher and no manual schema mapping.

As the name suggests, followthemoney-neomodel bridges Follow the Money (FtM) — the anti-corruption field’s shared open data standard, maintained by OpenSanctions — and graph databases, which are designed to store and explore highly interconnected data. Previously, developers wanting to work with FtM data in a graph database had to write custom code or learn Cypher, a graph-specific query language. followthemoney-neomodel removes that barrier, letting them build in ordinary Python with the full FtM vocabulary already built into the toolkit.

We developed followthemoney-neomodel in parallel with OpenSanctions’ own followthemoney-graph, and the two are complementary: theirs loads FtM data into a graph database at scale, while ours gives developers a fast way to put it to use once it’s there.

The Tech: Follow the Money and Neo4j #

Follow the Money (FtM) gives analysts and engineers a shared language for describing investigative data. It defines a rich set of entity types — from people and companies to vessels, bank accounts, and sanctions — along with the relationships among them, including ownership, directorship, and payment. In other words, FtM provides a common framework for anti-corruption investigators that makes data portable, interoperable, and ready for analysis.

As FtM is designed to model networks, describing entities in terms of their connections to one another, it can be neatly paired with graph databases. Neo4j, the graph database used by both C4ADS and OpenSanctions, stores connections as its own type of data with distinct properties rather than leaving connections implied between traditional relational tables. Graphs make questions like “Who is linked to this company, and through what?” fast and natural to ask.

How C4ADS Uses FtM, and Why We Built the Toolkit #

FtM structures data across investigations on our Horizons platform. Data collected from corporate registries, shipping records, and sanctions lists is mapped onto FtM’s schema regardless of source format, which lets us link datasets that would otherwise use incompatible formats.

As part of an ongoing relationship with OpenSanctions, C4ADS has been moving that data out of relational databases and into Neo4j for network analysis. Neo4j speaks its own query language, Cypher, while most data analysis and development happens in Python. neomodel, an open-source library maintained by Neo4j Labs, bridges part of that gap by letting developers define and query graph data in pure Python, translating to Cypher behind the scenes. But neomodel expects developers to hand-write a Python class for every entity type they use, and FtM defines a lot of entity types. That mismatch between neomodel’s design and FtM’s scope is what followthemoney-neomodel closes.

How the Toolkit Works #

At its core, followthemoney-neomodel is a connector library that bridges FtM and neomodel. FtM provides the schemas; neomodel supplies the graph interface.

followthemoney-neomodel reads whatever version of FtM is installed and dynamically generates the corresponding node and edge classes, one for every entity and relationship type FtM defines, respecting its schema hierarchy and property type (string, number, or datetime). followthemoney-neomodel requires no manual schema mapping, coding, or configuration.

In practice, a developer can import a class, use it to create an entity in a Neo4j graph, and immediately start traversing relationships, all the while staying fully aligned with FtM’s schema and in pure Python. The toolkit handles the translation so analysts and developers can focus on the investigation.

A Simple Example #

The following example uses followthemoney-neomodel to create a basic relationship between a Person and a Vehicle, two entity types defined in FtM’s schema:

The result: a few lines of Python produce two entities linked by an ownership relationship in a Neo4j graph, with no Cypher required. Developers can then set properties on the nodes and relationships.

A few aspects of how the followthemoney-neomodel library maps FtM concepts into Neo4j’s graph model are worth noting:

  • Nodes follow FtM’s inheritance hierarchy. In FtM, entity types inherit from one another; i.e., a Person is a type of LegalEntity, which is a type of Thing. The library preserves this by assigning multiple labels to each node. A Person node in Neo4j will carry the labels Thing, LegalEntity, and Person. Thing is the top level of abstraction, and every node in the graph carries it.
  • Edge types become relationships, not nodes. In FtM, some types, like Ownership, describe the connection between two entities rather than a standalone entity. The library recognizes this and creates them as Neo4j relationships rather than nodes. Because Neo4j relationships carry a single type rather than multiple labels, the library maps them to an uppercased relationship type — so Ownership becomes OWNERSHIP in the graph.

Applying the Toolkit: Mapping a PEP Network #

A hypothetical investigation shows how the toolkit works in practice. A common use case at C4ADS  is mapping the corporate and financial networks of Politically Exposed Persons (PEPs). This example builds a network using Person, Asset and Organization entity types  as nodes, and Membership, Ownership, and Payment as edges linking the nodes together.

Consider a suspected money laundering network involving Mr. and Ms. Smith modeled in Neo4j. Payments flow between people and organizations, people  own assets, and memberships tie individuals to organizations. The graph captures all of these connections as a traversable network, shown below (to view the full setup code, see the unittest):

Here, the structure suggests payments are being routed through an intermediary, a pattern that can indicate money laundering. With this data in Neo4j, followthemoney-neomodel makes querying it from Python straightforward.

The output of traverse() depends on how deep the query goes. Developers can fetch one or more relations within the same call and can mix optional and non-optional relations. Because Cypher queries can become complex, the higher layer of abstraction in Python helps. For example, the query above translates roughly to this Cypher:

The results return all five elements in the path traversal: the starting organization, the payment relationship, the intermediary legal entity, the ownership relationship, and the end asset. Because followthemoney-neomodel encodes FtM’s hierarchy, neomodel knows the exact abstract labels (LegalEntity rather than Person) to use when traversing a given relationship. This keeps the terms as broad as possible when finding specific allowable entities along the way. Developers can filter properties at any point along the path, which is a powerful capability when looking for specific terms like number or datetime. In this case, the all() method returns the assets owned by Mr. Smith that are valued above US$4,000 with every node and relationship found along the way.

For more information on neomodel path traversal, read the neomodel docs.

Things to Watch For #

Some limitations are inherent to FtM’s data model and apply no matter what tool you use to work with it. Others are specific to how followthemoney-neomodel maps FtM onto Neo4j.

FtM’s multi-valued properties and statement-level provenance (which source claimed what, with what confidence) get flattened into single Neo4j properties by default; if you need to preserve the claim-level trail, you’ll need to model it explicitly as its own node or edge. Multi-label nodes support hierarchy-aware queries but can surprise you if you filter on a broad label like LegalEntity expecting it to be selective, OpenSanctions explicitly advises against this. Last, there’s currently no way to reconcile old data with a newer FtM version: if the installed FtM version changes, nodes and relationships already in the graph won’t automatically update to match the newly generated classes. We recommend pinning the FtM version you build against.

Try It  #

followthemoney-neomodel is available now on GitHub, along with documentation and the full test suite referenced above. This project continues to develop as part of our ongoing work with OpenSanctions. If you build with it, run into issues, or have feedback on the schema mappings, open an issue on the repo.

References and further reading