★ Founding developer program: Pro free for 90 days for the first 50 developers →

Guides · Engineering

Analytics for Fabric and NeoForge mods, on servers and in players' games

Count the servers and games running your Fabric or NeoForge mod, see which features get used and which errors happen, with anonymous, disclosed telemetry.

Updated · by Skilled · 4 min read

Mod developers have it harder than plugin developers when it comes to knowing who uses their work. Download counts on Modrinth and CurseForge include modpack installs, launcher updates and people who tried a pack once. And a mod can run in two very different places: on a dedicated server, and inside a player's own game.

This guide covers what you can measure in a Fabric or NeoForge mod, how to do it without upsetting players, and how to set it up.

Two places a mod runs

  • Dedicated servers. Like a plugin: one install serves many players. You want the number of servers, their players, and what happens on them.
  • Players' games. Every install is one person. You want to know how many active installs there are, which features they use, and what crashes, without ever knowing who they are.

Most analytics tools for Minecraft were built for the first case. Client mods are where downloads say the least, because modpacks bundle mods that many players never touch.

What's worth measuring

  • Active installs, on servers and in games, and their trend. A rising count after a modpack picks you up looks very different from organic growth.
  • Minecraft and loader versions. Which versions to keep supporting is the most expensive decision a mod developer makes every update. Data beats guessing.
  • Feature usage. Which blocks get placed, which screens get opened, which items get crafted. The feature nobody uses is the one you can stop porting.
  • Errors, grouped. Crashes and logged exceptions from every install, with the mod version, instead of a crash log pasted into an issue every few weeks.

Telemetry in mods: do it in the open

Players are rightly wary of mods that phone home. If you collect anything, these aren't optional:

  • Disclose it. Say in your description that the mod collects anonymous usage statistics. Modrinth asks for a "Contains telemetry" disclosure, and its rules require clear disclosure of anything uploaded to a remote server.
  • Collect nothing that identifies a person. No name, account, UUID or IP.
  • Give players an off switch that works for every mod at once.
  • Stay out of the way. No network calls on the render or server thread, no held-open connections from a player's game, nothing that delays startup.

Setting it up with PluginAnalytics

The PluginAnalytics SDK has artifacts for Fabric and NeoForge with the same API as the plugin SDKs. It doesn't depend on Minecraft classes, so one version works on every Minecraft version the loader runs.

Fabric

public final class SkyIslands implements ModInitializer {
    public static PluginAnalytics analytics;

    @Override
    public void onInitialize() {
        analytics = PluginAnalytics.start("skyislands", "pa_your_key");
    }
}

With Loom, the SDK has to be shaded into the jar Loom remaps and relocated into your package. Use the Shadow plugin and point remapJar at the shaded jar. Don't use Loom's include() (jar-in-jar): it can't relocate the SDK, so the SDK turns itself off. The full build script is in proxies and mods.

NeoForge

@Mod("skyislands")
public final class SkyIslands {
    public static PluginAnalytics analytics;

    public SkyIslands() {
        analytics = PluginAnalytics.start("skyislands", "pa_your_key");
    }
}

With ModDevGradle, ship the shaded jar and keep the plain one as a "slim" classifier. As with Fabric, don't use jarJar for the SDK. Build script.

Tracking what players do

A player is their UUID in your code. The SDK turns it into an anonymous hash before anything is sent:

SkyIslands.analytics.track("island_created", player.getUuid());
SkyIslands.analytics.track("island_upgraded", player.getUuid(), "level", String.valueOf(level));

Event names are lowercase words like island_created. Keep property values low-cardinality (a level, a type, a result), never a name or free text.

What happens in a player's game

When the mod runs on the client, each install of the game is one anonymous "server" in your dashboard, shown as Fabric (client) or NeoForge (client), and every event belongs to that install:

  • The install is a random id with its own salt. Nothing ties it to the player's account.
  • The first batch goes out 60 to 90 seconds after the game starts, then every 30 minutes and when the game closes, over plain HTTPS. No connection is held open from a player's game.
  • Players turn it off for every mod that uses the SDK in config/pluginanalytics.yml with enabled: false.

On dedicated servers, player joins, player counts and the server thread (for performance sampling) come from Fabric API when it's installed; NeoForge has them built in.

Errors from every install

Exceptions that go through your mod's code are captured automatically, grouped by type and stack trace, with names, IPs and UUIDs removed. Each issue shows the versions it was first and last seen in, and how many installs it hit, counting each install once however often it repeats. That last part matters for mods: one broken setup can throw the same exception thousands of times, and it shouldn't look like a disaster. Errors

Config usage

The SDK reads plain choices from your config file (config/<modid>-server.toml or -common.toml on NeoForge, or config/<modid>.json, .json5, .toml, .properties or .yml), so you see which options people change and which defaults everyone keeps. Private-looking keys are always skipped. Config usage

Before you ship

  • Add the telemetry disclosure on Modrinth and a line in your description.
  • Mention the off switch (config/pluginanalytics.yml).
  • Check that the SDK is relocated: if it isn't, it turns itself off rather than clash with another mod's copy.

Everything each platform supports is in proxies and mods.

Skilled

Makes Minecraft plugins (including The Sift on SpigotMC) and PluginAnalytics, so other plugin developers can see how their plugins are found, installed and used.

More guides

Engineering

Analytics for Velocity and BungeeCord plugins

What you can measure in a Velocity or BungeeCord proxy plugin, why a proxy is not a server, and how to count networks, players, features and errors.

4 min read
Engineering

Error tracking for Minecraft plugins: find the bug before the 1-star review

How Spigot and Paper plugin exceptions reach the console, why waiting for reports fails, and how to collect, group and fix errors from every server.

4 min read

See how your own plugin is found and used

Free for your first plugin or mod. One line of code.