Skip to content

Protection

Games get copied. A site lifts your build, hosts it themselves, and keeps the ad revenue — while you carry the cost of having made it.

Y8 keeps lists of sites known for doing this, and the SDK checks them for you. When your game is shown on one of those sites, framed by it or as a copy of your build hosted there, the SDK replaces the game with a "Game Embedding Blocked" page. The page tells the site's owner how to ask Y8 for permission and, if your game is released on Y8, links players to it there.

There is nothing to add to your game. The check runs when the SDK initializes, for JavaScript, Unity, Construct 3 and Haxe games alike: they all load the same SDK.

Authentication

Protection does not require the player to be authenticated.


How It Works

  • What is checked: the site showing your game. That means every page above the game that the browser reveals, the page that framed it, and the game's own address.
  • Startup is never delayed: the game starts as usual and the check runs alongside it. If the lists can't be fetched, the game runs.
  • What is never blocked: Y8's own pages (developer-hosted games inside Y8's wrapper included), sites Y8 has approved, and local addresses (localhost, 127.0.0.1, file:). Testing on your own machine is unaffected.
  • What is counted: Y8 counts the loads it blocks. It also counts loads where the browser hides the site showing the game, but doesn't block those. Neither shows up in your analytics.

Limits

  • Firefox shows a game only the page directly above it. There, a listed site that frames your game through another page in between is not caught.
  • A site can hide itself from the browser. In Firefox, an iframe with referrerpolicy="no-referrer" does it. Such loads are counted, not blocked.
  • A copy of your build with the SDK stripped out is beyond the reach of anything that runs in the game.

Check It Yourself (Optional)

You don't need this, since the game's frame is replaced either way. isBlacklisted gives the same answer the automatic check acts on. It is there for games that already call it, or that want to react first: pause, mute, or show their own message.

y8Sdk.isBlacklisted()
    .then((blacklisted) => {

        if (blacklisted) {
            // Show a message directing the player
            // to the official game page.
        }

    })
    .catch((error) => {
        console.error(error.message);
    });

The list is fetched on the first check and reused for the rest of the session, so calling this more than once costs nothing after the first.

The returned value is:

  • true — The site showing the game is blocked.
  • false — It is not.

Unlike the automatic check, this rejects when the lists can't be fetched.

JsResponse<bool> response =
    await Y8.Instance.IsBlacklistedAsync();

if (response.IsSuccess && response.Data)
{
    // Show a message directing the player
    // to the official game page.
}

The blacklist is cached by the SDK after the first request.

If the check itself fails, the response is IsSuccess == true with Data == false — the same as a domain that is not blacklisted. IsSuccess is never false here.

checkBlacklist → On clicked
            → Call checkBlacklist
On function checkBlacklist
    → checkBlacklist()

SaveData

If the site showing the game is blocked, the C3 integration triggers the WebsiteBlacklisted function.

On function WebsiteBlacklisted
    → Show a message directing the player
      to the official game page.

SaveData

If the site is not blocked, or if the check fails, WebsiteBlacklisted is not triggered.

Y8.checkBlacklist(function(blacklisted:Bool) {
    trace("Blacklisted: " + blacklisted);

    if (blacklisted) {
        trace("Website is blacklisted");

        // Show a message directing the player
        // to the official game page.
    }
});

The callback receives a Bool:

  • true — The site showing the game is blocked.
  • false — It is not, the check failed, or the SDK was not ready yet.

Pages That Host a Game

The check above runs inside the game. A page that shows a game rather than being one can run the same check with y8.checkEmbedding, without calling init(). Y8's own /embed/<slug> page does this, so games that don't use the SDK are protected there too. A game that calls init() doesn't need it.

<script>
  window.addEventListener('y8sdk.ready', function () {
    if (window.y8 && window.y8.checkEmbedding) {
      window.y8.checkEmbedding({ appId: '<app id>' });
    }
  }, { once: true });
</script>
<script src="https://cdn.y8.com/minimal-sdk/2-0/y8.min.js" async></script>

It resolves with 'blocked' (the page's own frame is then replaced), 'hidden' (the browser hides the embedding site; counted, not blocked) or 'ok', including when the lists can't be fetched. It never rejects.