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

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.

Updated · by Skilled · 4 min read

Proxy plugins live in an odd spot. They run on fewer machines than server plugins, but each of those machines sits in front of a whole network: a lobby, a few game servers, sometimes hundreds of players at once. A Velocity plugin installed on 40 proxies can reach more players than a Paper plugin on 400 servers.

That changes what's worth measuring, and a few things work differently on a proxy. This guide covers both.

A proxy is not a server

Three differences shape everything else:

  1. One proxy is one network. When you count installs, a proxy should count once, with the players of the whole network behind it, not once per backend server.
  2. There's no main thread. Velocity and BungeeCord handle events on thread pools. There's no tick and no MSPT, so "is my plugin causing lag?" becomes "how long do my handlers take?".
  3. Players move between servers. A player who joins the lobby and then a game server is still one connection on the proxy. Per-player counts on the proxy are network-wide, which is usually what you want.

What's worth measuring

For most proxy plugins, these answer the questions that matter:

  • How many networks run it, and how big they are. Ten networks with 2,000 players each are a very different user base from 300 networks with 5 players each, and they want different features.
  • Which features get used. A party plugin might track party_created, party_invite_sent and party_joined. The ratio between them says whether invites work.
  • Errors, by version. Proxy plugins often deal with network I/O, databases and messaging between servers, where failures depend on the setup. Seeing every exception from every network, grouped, beats waiting for a bug report.
  • How long your handlers take. On a proxy, a slow LoginEvent or ServerPreConnectEvent handler delays every player who joins.
  • Which proxy and version they run. Velocity versions, BungeeCord and Waterfall forks, Java versions: this tells you what you can drop and what you must keep supporting.

bStats on a proxy

bStats has metrics classes for Velocity and BungeeCord. It's free and public, and it counts proxies and players with charts for versions and countries, plus custom charts you define. If a public install count is all you need, it's a good choice.

What it doesn't do is feature usage per player, funnels, error tracking or timing your code. For that you need events, not charts.

PluginAnalytics on Velocity

The PluginAnalytics SDK has an artifact per platform with the same API. On Velocity, start it on ProxyInitializeEvent:

@Plugin(id = "partyplus", name = "PartyPlus", version = "1.0.0")
public final class PartyPlus {
    private final ProxyServer server;
    private final Path dataDirectory;
    private PluginAnalytics analytics;

    @Inject
    public PartyPlus(ProxyServer server, @DataDirectory Path dataDirectory) {
        this.server = server;
        this.dataDirectory = dataDirectory;
    }

    @Subscribe
    public void onInit(ProxyInitializeEvent e) {
        analytics = PluginAnalytics.start(this, server, dataDirectory, "pa_your_key");
    }

    void createParty(Player leader) {
        analytics.track("party_created", leader);
    }
}

It stops by itself when the proxy shuts down. Velocity 3.5 and later (Java 21) are supported. The artifact is pluginanalytics-velocity, shaded and relocated into your jar like any library (installation).

PluginAnalytics on BungeeCord and Waterfall

public final class PartyPlus extends Plugin {
    private PluginAnalytics analytics;

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

    @Override
    public void onDisable() {
        analytics.stop(); // sends the last batch
    }
}

BungeeCord has no "plugin disabled" event the SDK could listen to, so call stop() in onDisable. The artifact is pluginanalytics-bungee.

Tracking on a proxy

Events work the same as on a server. Pass the player when a person did something, leave it out for what the proxy itself does:

analytics.track("party_created", leader);
analytics.track("party_joined", player, "size", String.valueOf(party.size()));
analytics.track("config_reloaded");

Commands aren't counted automatically on proxies (that only works through Bukkit's plugin.yml), so track them in your command handlers:

analytics.track("command:party.invite", player);

Timing instead of sampling

Without a main thread, there's nothing to sample. Measure the code you care about with a span instead:

@Subscribe
public void onPreConnect(ServerPreConnectEvent event) {
    try (PluginAnalytics.Span span = analytics.time("pre_connect")) {
        // your routing logic
    }
}

Performance then shows calls, average, p95 and max for each span, per plugin version, so you see whether a release made your login path slower. Spans are part of the Premium plan; everything else on this page works on every plan.

Config, errors and update notices

A few more things come without code:

  • Errors: exceptions that go through your code are captured, grouped by type and stack trace, with names, IPs and UUIDs removed. Errors
  • Config usage: plain choices from config.yml, .json, .properties or (on Velocity) .toml in your data folder, so you see which options networks change. Config usage
  • Update notices: networks on an older version are told in the console, and players with your notify permission when they join. Update notices

Respect the network owner

Network owners are careful about what runs on their proxy, and they should be. Whatever you use:

  • Say on your resource page that the plugin collects anonymous usage statistics and how to turn them off.
  • Never send player names, UUIDs, IPs or chat.
  • Never block an event handler on network I/O.

The SDK sends in the background, hashes players on the proxy with a salt that never leaves it, and is turned off for every plugin in plugins/PluginAnalytics/config.yml. All platforms are covered 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

Product

How to see how many servers use your Minecraft plugin

Two ways to count the servers running your Spigot or Paper plugin, bStats and PluginAnalytics, why it differs from downloads, and its limits.

4 min read
Product

How to see which commands players actually use in your Minecraft plugin

Count which commands and subcommands of your Spigot or Paper plugin get used, by how many players, and which ones nobody touches, with or without a library.

5 min read

See how your own plugin is found and used

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