Unity WebGL Upload Guide

Learn how to prepare and upload your Unity WebGL games

Back to guides

Preparing Your Unity WebGL Game

Unity WebGL games need specific build settings to work properly on our platform. Follow these steps to ensure your game is compatible:

Configure Build Settings

In Unity, go to File > Build Settings and select WebGL as the platform. If it's not installed, you may need to add it through the Unity Hub.

Unity Build Settings

Configure Player Settings

Click on Player Settings and configure the following:

  • Resolution and Presentation: Set default screen width and height
  • WebGL Template: Use the "Default" or "Minimal" template
  • Publishing Settings: Enable "Compression Format: Gzip"
  • Other Settings: Set "Color Space" to "Linear" for better visuals

Note: Enabling Gzip compression will make your build smaller and load faster.

Build Your Game

Click Build and select a destination folder. Unity will generate a WebGL build with the following structure:

Build/ ├── Build.data.gz ├── Build.framework.js.gz ├── Build.loader.js ├── Build.wasm.gz └── ... index.html TemplateData/ └── (various template files)

Important: Do not modify the file structure or rename files after building.

Test Your Build Locally

Unity WebGL builds must be served from a web server to work properly. You can use:

  • Unity's built-in preview server (click "Build and Run")
  • A local web server like http-server (npm install -g http-server)
  • Python's SimpleHTTPServer (python -m http.server)

Test your game thoroughly to ensure it works as expected before uploading.

Zip Your Build

Compress the entire build folder (including index.html, Build/ folder, and TemplateData/ folder) into a ZIP file.

# On macOS/Linux zip -r my-game.zip index.html Build/ TemplateData/ # On Windows # Right-click the folder > Send to > Compressed (zipped) folder

Common Issues and Solutions

Game Doesn't Load

If your game shows a black screen or doesn't load:

Performance Issues

If your game runs slowly:

Content Encoding Errors

If you see "ERR_CONTENT_DECODING_FAILED" errors:

Note: Our platform has special handling for Unity WebGL files to ensure proper content encoding headers are set for .gz and .unityweb files.

Implementing Game Session Tracking

All games uploaded to our platform must implement session tracking functionality. This allows us to track player sessions and maintain leaderboards for your game.

Important: Your game bundle must include API calls to our session tracking endpoints. Our validation system will check for these calls during the upload process. Games without proper session tracking implementation will be rejected.

Option 1: Use Our JavaScript SDK (Recommended)

For Unity WebGL games, you can use our JavaScript SDK by adding it to your game via the Unity WebGL template. You can download the SDK here or view an example implementation.

Step 1: Create a custom WebGL template

In your Unity project, create a custom WebGL template by copying the default template:

  1. Go to Project Settings > Player > WebGL > Publishing Settings
  2. Click on Custom WebGL Template and select Create

Step 2: Add our SDK to the template

In your custom template's index.html file, add our SDK script before the closing </body> tag:

<!-- Game Session Tracker SDK -->
<script src="/sdk/game-session-tracker.js"></script>
<script>
  // Initialize the tracker when the game is loaded
  var tracker = null;
  
  function initializeSessionTracker() {
    tracker = new GameSessionTracker();
    console.log("Game session tracker initialized");
  }
  
  // Call this when the game is fully loaded
  document.addEventListener("gameLoaded", initializeSessionTracker);
</script>

Step 3: Create a JavaScript plugin for Unity

Create a JavaScript plugin that your Unity game can call:

// Add this to a .jslib file in your Unity project's Plugins folder
mergeInto(LibraryManager.library, {
  // Function to end the session and submit score
  EndGameSession: function(score) {
    if (tracker) {
      tracker.endSession(score)
        .then(function(response) {
          console.log("Session recorded successfully", response);
        })
        .catch(function(error) {
          console.error("Failed to record session", error);
        });
    } else {
      console.error("Game session tracker not initialized");
    }
  },
  
  // Function to get leaderboard
  GetGameLeaderboard: function(limit) {
    if (tracker) {
      tracker.getLeaderboard(limit)
        .then(function(response) {
          // Convert the response to a string to pass back to Unity
          var jsonResponse = JSON.stringify(response);
          // Call a Unity function to handle the response
          unityInstance.SendMessage('LeaderboardManager', 'OnLeaderboardReceived', jsonResponse);
        })
        .catch(function(error) {
          console.error("Failed to fetch leaderboard", error);
        });
    } else {
      console.error("Game session tracker not initialized");
    }
  }
});

Step 4: Create C# scripts to call the JavaScript functions

In your Unity project, create C# scripts to interface with the JavaScript plugin:

using UnityEngine;
using System.Runtime.InteropServices;

public class GameSessionManager : MonoBehaviour
{
    // Import the JavaScript functions
    [DllImport("__Internal")]
    private static extern void EndGameSession(int score);
    
    [DllImport("__Internal")]
    private static extern void GetGameLeaderboard(int limit);
    
    // Call this when the game ends
    public void EndGame(int score)
    {
        #if UNITY_WEBGL && !UNITY_EDITOR
            EndGameSession(score);
        #else
            Debug.Log("Session tracking only works in WebGL builds");
        #endif
    }
    
    // Call this to fetch the leaderboard
    public void FetchLeaderboard(int limit = 10)
    {
        #if UNITY_WEBGL && !UNITY_EDITOR
            GetGameLeaderboard(limit);
        #else
            Debug.Log("Leaderboard only works in WebGL builds");
        #endif
    }
}

Step 5: Create a LeaderboardManager to handle responses

Create a LeaderboardManager script to handle the leaderboard data:

using UnityEngine;
using System;
using System.Collections.Generic;

[Serializable]
public class LeaderboardEntry
{
    public string token;
    public int high_score;
    public int play_count;
    public string last_played;
}

[Serializable]
public class LeaderboardData
{
    public List leaderboard;
}

[Serializable]
public class LeaderboardResponse
{
    public bool success;
    public string message;
    public LeaderboardData data;
}

public class LeaderboardManager : MonoBehaviour
{
    // This function will be called from JavaScript
    public void OnLeaderboardReceived(string jsonData)
    {
        LeaderboardResponse response = JsonUtility.FromJson(jsonData);
        if (response.success)
        {
            // Process and display the leaderboard
            DisplayLeaderboard(response.data.leaderboard);
        }
        else
        {
            Debug.LogError("Failed to get leaderboard: " + response.message);
        }
    }
    
    private void DisplayLeaderboard(List entries)
    {
        // Implement your UI logic to display the leaderboard
        foreach (var entry in entries)
        {
            Debug.Log($"Player: {entry.token}, Score: {entry.high_score}, Plays: {entry.play_count}");
        }
    }
}

Option 2: Custom Implementation

If you prefer not to use our SDK, you can implement session tracking directly in JavaScript and call it from Unity:

Step 1: Add this JavaScript code to your WebGL template

<script>
// Add this to your index.html file
function getSubdomain() {
  const hostname = window.location.hostname;
  const parts = hostname.split('.');
  return parts.length > 2 ? parts[0] : '';
}

function endGameSession(score) {
  const sessionStartTime = new Date(sessionStorage.getItem('sessionStartTime') || new Date());
  const sessionEndTime = new Date();
  const subdomain = getSubdomain();
  
  // Generate a random token if not already stored
  let token = sessionStorage.getItem('playerToken');
  if (!token) {
    token = Math.random().toString(36).substring(2, 15);
    sessionStorage.setItem('playerToken', token);
  }
  
  const sessionData = {
    token: token,
    session_start_time: sessionStartTime.toISOString(),
    session_end_time: sessionEndTime.toISOString(),
    score: score,
    app_version: '1.0.0',
    language: navigator.language.split('-')[0] || 'en'
  };
  
  // REQUIRED: This exact endpoint must be called when a game session ends
  fetch(`https://jiran-games-api.lezzoodevs.com/api/v1/games/${subdomain}/session-ended`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(sessionData)
  })
  .then(response => response.json())
  .then(data => {
    console.log("Session recorded successfully", data);
    // Call a Unity function to notify of success if needed
    if (window.unityInstance) {
      window.unityInstance.SendMessage('GameSessionManager', 'OnSessionRecorded', 'success');
    }
  })
  .catch(error => {
    console.error("Failed to record session", error);
    // Call a Unity function to notify of failure if needed
    if (window.unityInstance) {
      window.unityInstance.SendMessage('GameSessionManager', 'OnSessionRecorded', 'error');
    }
  });
}

// Store session start time when page loads
document.addEventListener('DOMContentLoaded', function() {
  sessionStorage.setItem('sessionStartTime', new Date().toISOString());
});
</script>

Step 2: Create a C# script to call the JavaScript function

using UnityEngine;
using System.Runtime.InteropServices;

public class GameSessionManager : MonoBehaviour
{
    // Import the JavaScript function
    [DllImport("__Internal")]
    private static extern void endGameSession(int score);
    
    // Call this when the game ends
    public void EndGame(int score)
    {
        #if UNITY_WEBGL && !UNITY_EDITOR
            endGameSession(score);
        #else
            Debug.Log("Session tracking only works in WebGL builds");
        #endif
    }
    
    // This function will be called from JavaScript when session recording completes
    public void OnSessionRecorded(string result)
    {
        if (result == "success")
        {
            Debug.Log("Session recorded successfully");
        }
        else
        {
            Debug.LogError("Failed to record session");
        }
    }
}

Testing Your Implementation

Before uploading, test your session tracking implementation:

  1. Build your game for WebGL and run it locally
  2. Use browser developer tools to verify network requests are being made correctly
  3. Check that the POST request to /api/v1/games/:subdomain/session-ended is being made with all required parameters

Uploading to Jiran Games

Log in to Your Account

Sign in to your Jiran Games developer account.

Create a New Game

Click on "Add New Game" and fill in the required information:

  • Game Name
  • Description
  • Game Logo (recommended size: 512x512px)
  • Tags (to help users find your game)
  • Subdomain (this will be your game's URL: yourgame.jiran.games)

Upload Your Game Bundle

Select the ZIP file containing your Unity WebGL build and upload it.

Important: The maximum file size is 500MB. If your game is larger, consider optimizing your assets or splitting it into multiple levels.

Submit for Review

After uploading, your game will be marked as "pending_review". Our team will review it to ensure it meets our guidelines.

The review process typically takes 1-2 business days.