Self-hosted service
VisualDataWeb/WebVOWL avatar
VisualDataWeb/WebVOWL

WebVOWL: drawing OWL ontologies as graphs, with a converter service attached

Visualizing ontologies on the Web

1,015 stars280 forksJavaScriptMIT

At a glance

What is it?
WebVOWL renders OWL ontologies in the browser as VOWL visualizations, and the modern deployment path is a Docker stack that pairs the static frontend with the OWL2VOWL converter behind Tomcat. The frontend itself is an older webpack and grunt build on D3 v3, and the SVG export path has a documented trap around inlined CSS.
Who is it for?
Adopt WebVOWL if you need to show an ontology to people who do not read RDF, and you are willing to run the converter service alongside the frontend, since the OWL to VOWL conversion is a separate component. Do not adopt it as a foundation for new interactive work without checking the dependency versions, because the frontend is built on D3 v3 and webpack 1 with a PhantomJS based test runner, and the container images use a Node 12 build stage.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 141 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 21, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The project moved, and the README opens with a warning about it

The first thing in the WebVOWL README is a caution: the URL visualdataweb.org is not owned by VisualDataWeb anymore and is not related to WebVOWL anymore, and the new link to WebVOWL is https://service.tib.eu/webvowl/. The homepage recorded for the repository matches that second address.

That is a useful warning to read twice, because the old domain is still the one that appears in plenty of citations, blog posts and slides about the tool, and a stale link sends people to an unrelated site. The homepage recorded for the repository is service.tib.eu/webvowl.

The repository has a second piece of history in the same paragraph. It was ported from an internal SVN repository to GitHub after the release of WebVOWL 0.4.0, and because the port used `git filter-branch` for cleanups, the commit history might show some strange effects. That is a warning for anyone using the history to date a change: the early commits are not a reliable timeline.

The release list shows a project that moved slowly and then recently moved again. There is v1.1.7 from 2026-06-04, and before that 1.1.6 from 2019-10-08 and 1.1.5 from 2019-06-28. So the most recent release is seven years newer than the one before it, and the last push was on 2026-06-04, the same day as the release.

The visualisation is only half of it, and the other half is a Java service

WebVOWL visualizes ontologies on the web, and the key structural fact is that the picture and the conversion are separate pieces.

The frontend takes VOWL, the Visual Notation for OWL, and draws it. Turning an OWL file into VOWL is the job of a separate project, OWL2VOWL, and the Docker setup brings the two together. The compose file says so in a comment: full stack, WebVOWL UI plus OWL2VOWL, with the converter cloned inside the docker build.

The full stack comes up with:

bash
docker compose build && docker compose up -d

The frontend alone, without the converter endpoint, is a separate compose file and is described as the faster build:

bash
docker compose -f docker-compose.frontend.yml up -d --build

That distinction is the one to understand before you plan a deployment. The frontend is a static application; turning an OWL file into VOWL is the job of the separate converter. Without the converter, you can still load a VOWL document that you already have, and you cannot turn an OWL file into one on the fly.

The README also records a piece of history that explains the shape. The legacy root `Dockerfile` downloaded a WAR from vowl.visualdataweb.org, and that source is broken, with a link to issue 212. The current arrangement fetches OWL2VOWL from GitHub during the image build, so only the WebVOWL repository needs to be cloned locally, with no second local clone.

The converter version is pinned by an environment variable, and the README gives the form:

bash
OWL2VOWL_GIT_REF=v0.3.7 docker compose build

The value is a branch or a tag on the OWL2VOWL repository, and the compose file defaults it to master. Pinning it is the difference between a reproducible deployment and one that changes under you.

The container runs Tomcat as a non-root user with a health check

The frontend image is built in a Node stage and served from Tomcat, and the Dockerfile is a good example of a container that has been hardened deliberately.

The builder stage uses a Node 12 image, copies the build inputs, and runs `npm install --ignore-scripts && npm run release`. The `--ignore-scripts` flag matters, because the package's `postinstall` script runs `grunt release`, and running it inside the image build rather than as a postinstall hook is the explicit choice.

The runtime stage is Tomcat 9 on a JRE 8 Temurin base. It installs curl for the health check, creates a `tomcat` group and user with the uid and gid 999, clears the default web applications, creates a fresh `ROOT` directory, and changes the ownership of the Tomcat home to that user. The built files are copied in with the ownership set, the container switches to the `tomcat` user, and the image exposes port 8080.

The health check is declared in the image itself and mirrors the compose file:

dockerfile
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
    CMD curl -f http://127.0.0.1:8080/ || exit 1

And the compose service adds the container hardening:

yaml
security_opt:
  - no-new-privileges:true
healthcheck:
  test: ["CMD", "curl", "-f", "http://127.0.0.1:8080/serverTimeStamp"]
  interval: 30s
  timeout: 5s
  start_period: 90s
  retries: 3

The health check endpoint differs between the two, with the compose file probing a `serverTimeStamp` path and the image probing the root, which is a small inconsistency worth knowing if you are reading container logs. The compose file also mounts a `./data` directory into the container, and a commented-out line shows a volume for the deploy directory into the Tomcat webapps root.

The legacy build path still works, with grunt and a local server

Before the Docker setup, the README documents a plain development path, and it is the one most contributors will follow.

The simple setup is six steps: install Node.js, open a terminal in the root directory, run `npm install` to install the dependencies and build the project, edit the code, run `npm run-script release` to rebuild all necessary files into the deploy directory, and then run `serve deploy/` to serve it locally, installing serve with `npm install serve -g`. The result is at http://localhost:3000.

The advanced setup adds the `grunt-cli` package installed globally with `npm install grunt-cli -g`, which unlocks a set of tasks: `grunt` or `grunt release` builds the release files into the deploy directory, `grunt package` builds the development version, `grunt webserver` starts a local live-updating webserver with the current development version, `grunt test` starts the test runner, and `grunt zip` builds the project and puts it into a zip file.

The `package.json` maps the same commands onto npm scripts, so `npm test` runs `grunt test-ci`, `npm run webserver` runs `grunt webserver`, and `npm run release` runs `grunt release`. The postinstall hook runs `grunt release`, which is why a plain `npm install` produces a built project.

The rest of the tooling is a webpack 1 build with the html build plugin, the karma test runner with jasmine, and a plugin list that includes `grunt-gitinfo`, which is how the build gets the commit information. The project is MIT licensed, with the licence file at `license.txt`, and the repository holds `src/`, `test/`, `util/`, `data/`, `doc/`, `docs/` and `docker/` directories.

The dependency versions tell you how old this frontend is

The dependency list in `package.json` is worth reading as a status report.

The runtime dependencies are D3 at 3.5.6, lodash at 4.1.0, and grunt-cli. D3 v3 is the important one. D3 v3 and v4 are not compatible in their APIs, and v3 is long past its support window, so any code you write against the current D3 documentation will not apply to this code. The visualisation code in `src/` is written against a decade-old rendering library.

The build tooling is the same vintage. Webpack is at 1.12.0, webpack-dev-server at 1.12.0, karma at 1.3.0, and the test launcher is `karma-phantomjs-launcher` with `phantomjs-prebuilt` as a dependency. PhantomJS was discontinued years ago, and a test suite that depends on it will not run in a modern CI environment without workarounds.

That is not a criticism so much as a fact about the maintenance model. The recent release is v1.1.7, and the work in the changelog for that line has been the Docker setup, the converter integration and the deployment packaging, not a modernisation of the front end. The visualisation engine is stable, and nobody has needed it to change.

The consequence for an adopter is specific. If you want to run WebVOWL as published, or in the container, the age of the stack is invisible. If you want to extend the visualisation, to add a layout, to change the interaction model, to write a plugin, then you are working with D3 v3, webpack 1 and a JavaScript toolchain that predates the current one, and that is the real cost of adopting this code rather than this service.

SVG export needs the CSS inlined, and there is a converter for that

One extra piece of the README covers a problem that anyone exporting a graph will hit, and it has a dedicated tool in the repository.

To export the VOWL visualization to an SVG image, all CSS styles have to be included into the SVG code. The consequence of getting this wrong is stated precisely: if you change the CSS code in the `vowl.css` file, you also have to update the code that inlines the styles, otherwise the exported SVG will not look the same as the displayed graph.

The reason is that an SVG file that is loaded on its own has no access to the stylesheet of the page it came from, so a graph that looks right on screen can export as an unstyled collection of shapes.

The tool that generates the inlining code lives in the util directory, in a project named VowlCssToD3RuleConverter, and the README points to its own README file for the instructions. The name says what it does: it converts the CSS rules into something the D3 rendering code can apply, so the styles survive the export.

The structural lesson is the one from the rest of the project. The CSS is not only CSS, it is also data for the SVG export path, and the two have to be kept in step by hand. That is the sort of coupling that a build step or a test would usually remove, and here it is documented instead.

Where WebVOWL is the wrong tool

The first wrong case is a workflow that needs a general graph library. WebVOWL draws a specific kind of graph, an ontology rendered in the VOWL notation, with its own visual language for classes, properties and the relationships between them. If you want to draw an arbitrary network, this is a framework with a very specific purpose and a very old dependency base.

The second is a deployment that cannot run a Java service. The converter is a JVM component, and the container is Tomcat. If your constraint is a static site or a serverless function, the frontend alone will render VOWL documents you already have, but the OWL to VOWL step has to happen somewhere else.

The third is a project that intends to extend the visualisation code. As above, that means D3 v3, webpack 1 and a PhantomJS test runner. The published service is a good deal; the codebase is an old one.

The fourth is expecting a maintained upstream community. The gap between 1.1.6 in 2019 and 1.1.7 in 2026 is the honest signal here. The project has clearly been worked on, because the Docker setup, the converter integration and the health checks are recent work, but that work is in the deployment layer rather than in the library of the visualisation itself, and there is no indication of a roadmap.

The fifth is assuming the old domain still resolves. The README says in its first line that visualdataweb.org is no longer owned by VisualDataWeb and is unrelated to WebVOWL, so any deployment script, internal wiki or training document that still points there is pointing at the wrong thing.

Editorial conclusion

Adopt WebVOWL if you need to show an ontology to people who do not read RDF, and you are willing to run the converter service alongside the frontend, since the OWL to VOWL conversion is a separate component. Do not adopt it as a foundation for new interactive work without checking the dependency versions, because the frontend is built on D3 v3 and webpack 1 with a PhantomJS based test runner, and the container images use a Node 12 build stage. Before you deploy, read the Docker README and the architecture decision record it points to, pin the converter with `OWL2VOWL_GIT_REF` instead of tracking master, and remember that the current service lives at service.tib.eu/webvowl rather than at the old visualdataweb.org address.

Frequently asked questions

How do I run WebVOWL with Docker?

Clone the repository and run `docker compose build && docker compose up -d`, then open http://localhost:8080. The full stack builds the OWL2VOWL converter inside the image; for the frontend alone use `docker compose -f docker-compose.frontend.yml up -d --build`.

How do I pin the OWL2VOWL converter version?

The build argument `OWL2VOWL_GIT_REF` takes a branch or a tag on the OWL2VOWL repository, so `OWL2VOWL_GIT_REF=v0.3.7 docker compose build` pins it. The compose file otherwise defaults to master.

How do I build and run WebVOWL locally without Docker?

Install Node.js, run `npm install` to install dependencies and build, edit the code, run `npm run-script release` to rebuild into the deploy directory, and then serve it with `serve deploy/` after installing serve globally. The app is then at http://localhost:3000.

Why does my exported SVG look different from the graph on screen?

All CSS styles have to be inlined into the SVG code for the export to look the same. If you change the CSS in the vowl.css file you also have to update the code that inlines the styles, and the tool that generates that code is documented in the util directory.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. VisualDataWeb/WebVOWL on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/visualdataweb-webvowl.svg)](https://hysenlabs.com/projects/visualdataweb-webvowl)

Was this useful?