Anti-botting

Botting is the act of using an automated script or computer program to connect to and interact with a game. This guide will show three ways to prevent botting using Rivet.

  1. Captcha
  2. Custom external verification

Captcha

One popular method of bot prevention used across the entire internet is the CAPTCHA.

Configuration changes

To configure captcha for the Rivet matchmaker, add the following to your version config file:

matchmaker:
  captcha:
    # How many requests a connection can make before captcha reverification is required
    requests_before_reverify: 10
    # How much time before captcha reverification is required
    verification_ttl: 240000 # milliseconds
    # Chosen captcha provider here ...

The Rivet matchmaker currently supports two captcha providers:

Client-side changes

After setting up captcha in your version config, future calls to lobbies.find, lobbies.join, and lobbies.create will fail if captcha is not provided when requested.

The response body will look something like this:

{
  "code": "CAPTCHA_CAPTCHA_REQUIRED",
  "message": "Captcha is required.",
  "documentation": "https://rivet.gg/docs/general/errors/captcha/captcha-required",
  "metadata": {
    "hcaptcha": {
      "site_id": "MY_HCAPTCHA_SITE_ID"
    }
  }
}

Use the metadata provided (or in the case of Turnstile, just your own site key) to have the user verify a captcha. After a successful captcha completion, retry the lobbies.find, lobbies.join, or lobbies.create request with the captcha response:

Request

POST
https://matchmaker.api.rivet.gg/v1/lobbies/find
curl
  -X POST \
  -H "Content-Type: application/json" \
  -d "{ \"captcha\": { \"turnstile\": { \"client_response\": \"CAPTCHA_RESPONSE\" } } }" \
  'https://matchmaker.api.rivet.gg/v1/lobbies/find'

Custom external verification

The Rivet matchmaker allows for external verification requests to enable developers to arbitrarily allow/reject matchmaker requests by their own logic. This is useful for games that have their own account system or custom anti-botting mechanism that want to restrict API calls to the matchmaker.

This is done via a webhook-like system that sends a POST request to a custom API endpoint after every lobbies.find, lobbies.join, or lobbies.create request.

Configuration changes

In this example, Rivet will send https://my.app/verify an HTTP POST request after every lobbies.join request it receives.

matchmaker:
  game_modes:
    default:
      actions:
        join:
          enabled: true
          verification_config:
            url: https://my.app/verify
            headers:
              my_header: SECRET_CODE

The request payload will look something like this:

{
  // This is arbitrary JSON data provided by the user to the /find or /join
  // endpoints. Can be null.
  "verification_data": {
    // ...
  },
  "game": {
    "namespace_id": "NAMESPACE_ID",
    "game_mode_id": "GAME_MODE_ID",
    "game_mode_name_id": "default",

    // Info about the lobby only if it is already running. Null otherwise.
    // When this value is null and `kind` is "find", that implies this lobby
    // is being auto-created.
    "lobby": {
      "lobby_id": "LOBBY_ID",
      "region_id": "REGION_ID",
      "region_name_id": "atl",
      "create_ts": "Tue, 15 Nov 1994 12:45:26 GMT",
      "is_closed": false
    },
    // This is arbitrary JSON data. Can be null. †
    "state": {
      // ...
    },
    // This is arbitrary JSON data provided by the user to the /create
    // endpoint when creating a custom lobby. Can be null. It will be
    // passed to the `RIVET_LOBBY_CONFIG` environment variable upon
    // lobby creation. ††
    "config": {
      // ...
    },
    // This is an arbitrary string hashmap provided by /find or /create by
    // the user
    "tags": {
      // ...
    },
    // Set by the user in /find and /create requests. Null if unset.
    "dynamic_max_players": 4
  },
  // IP info about all connecting players in this request.
  "clients": {
    "1.2.3.4": {
      // Null if `User-Agent` header was not set.
      "user_agent": "...",
      // Coordinates can be null if IP fetching failed.
      "latitude": 0.0,
      "longitude": 0.0
    }
  },
  "join_kind": "normal", // Either "normal", or "party"
  "kind": "join" // Either "find", "join", or "create"
}

† See lobbies.setState.

†† See Lobby environment variables for more info.

Server reply

Your server should reply to Rivet's request according to these rules:

  • A success status code (200 - 299) tells the matchmaker it should accept the request
  • Any other status code tells the matchmaker it should reject the request with the MATCHMAKER_VERIFICATION_FAILED error

Client-side changes

This code shows how to provide user data to your external verification server through Rivet:

Request

POST
https://matchmaker.api.rivet.gg/v1/lobbies/find
curl
  -X POST \
  -H "Content-Type: application/json" \
  -d "{ \"verification_data\": { \"foo\": \"bar\" } }" \
  'https://matchmaker.api.rivet.gg/v1/lobbies/find'

If your server returns a response that ends up rejecting the matchmaker request, the user's request will fail with the MATCHMAKER_VERIFICATION_FAILED error code. If Rivet's request to your server times out or fails for any reason, the matchmaker request will fail with the MATCHMAKER_VERIFICATION_REQUEST_FAILED error code.

Use case: Custom account verification

If you plan on using an external account system instead of Rivet's identities, you can leverage the external verification system discussed above.

For example, passing a user's account token into this request will allow you to verify that the user is who they say they are:

Request

POST
https://matchmaker.api.rivet.gg/v1/lobbies/find
curl
  -X POST \
  -H "Content-Type: application/json" \
  -d "{ \"verification_data\": { \"my_secret_account_token\": \"my-external-account-token-here" } }" \
  'https://matchmaker.api.rivet.gg/v1/lobbies/find'

Rivet

Open-source multiplayer infrastructure. Easy, flexible, and affordable.

This website is not sponsored by or affiliated with Unity Technologies or its affiliates. Unity Trademark(s) are trademark(s) or registered trademark(s) of Unity Technologies or its affiliates in the U.S. and elsewhere. | This website is not sponsored by, affiliated with, or endorsed by Epic Games, Inc. or its affiliates. 'Unreal Engine' is a trademark or registered trademark of Epic Games, Inc. in the U.S. and elsewhere. | The HTML5 Logo by the World Wide Web Consortium (W3C), used under a Creative Commons Attribution 3.0 License. Source | The Godot Engine Logo by the Andrea Calabró, used under a Creative Commons Attribution 4.0 International License. Source | Docker and the Docker logo are trademarks or registered trademarks of Docker, Inc. in the United States and/or other countries. Docker, Inc. and other parties may also have trademark rights in other terms used herein.

© 2024 Rivet Gaming, Inc. All rights reserved.