Decentralized JavaScript Games with Internet Identity
Learn how to build pure JavaScript games with Internet Identity authentication and deploy them on the Internet Computer Protocol for decentralized gaming experiences

Introduction
Learn how to create simple, pure JavaScript games with Internet Identity authentication and host them on the Internet Computer Protocol (ICP) for truly decentralized gaming experiences.
Why Decentralized Games?
Traditional web games rely on centralized servers, leaving users vulnerable to data loss, privacy concerns, and platform shutdowns. By hosting games on ICP with Internet Identity, you can create:
- Truly owned user accounts - Players control their identity
- Permanent deployment - Games live on the blockchain
- No backend servers - Pure JavaScript frontends with smart contract storage
- Privacy-first - No email or password required
- Cross-platform identity - One identity across all ICP dApps
What is Internet Identity?
Internet Identity is ICP's decentralized authentication system that provides:
- Anonymous, cryptographic authentication
- No passwords or email addresses
- Biometric support (fingerprint, face recognition)
- Multi-device sync
- Complete user privacy
Building Your First Decentralized Game
Prerequisites
- Node.js and npm installed
- DFX (Internet Computer SDK)
- Basic JavaScript knowledge
- Understanding of HTML5 Canvas or game frameworks
Project Setup
# Install DFX
sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"
# Create new project
dfx new my-game --type=motoko
cd my-game
Integrating Internet Identity
import { AuthClient } from "@dfinity/auth-client";
let authClient;
async function init() {
authClient = await AuthClient.create();
if (await authClient.isAuthenticated()) {
handleAuthenticated();
}
}
async function login() {
await authClient.login({
identityProvider: "https://identity.ic0.app",
onSuccess: handleAuthenticated,
});
}
function handleAuthenticated() {
const identity = authClient.getIdentity();
const principal = identity.getPrincipal().toString();
console.log("Logged in as:", principal);
// Start game with authenticated user
}
Simple Game Example - Click Battle
Here's a simple example using pure JavaScript and HTML5 Canvas:
// game.js - Simple click counter game
let score = 0;
let authenticated = false;
let playerPrincipal = "";
class Game {
constructor() {
this.canvas = document.getElementById('gameCanvas');
this.ctx = this.canvas.getContext('2d');
this.setupAuth();
}
async setupAuth() {
this.authClient = await AuthClient.create();
if (await this.authClient.isAuthenticated()) {
this.onAuthenticated();
}
}
async login() {
await this.authClient.login({
identityProvider: "https://identity.ic0.app",
onSuccess: () => this.onAuthenticated(),
});
}
onAuthenticated() {
const identity = this.authClient.getIdentity();
playerPrincipal = identity.getPrincipal().toString();
authenticated = true;
this.loadScore();
this.render();
}
async loadScore() {
// Load score from ICP canister
// const savedScore = await backend.getScore(playerPrincipal);
// score = savedScore;
}
async saveScore() {
// Save score to ICP canister
// await backend.saveScore(playerPrincipal, score);
}
handleClick() {
if (!authenticated) {
alert("Please login first!");
return;
}
score++;
this.saveScore();
this.render();
}
render() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.ctx.font = '30px Arial';
this.ctx.fillText(`Score: ${score}`, 50, 50);
if (authenticated) {
this.ctx.font = '14px Arial';
this.ctx.fillText(`Player: ${playerPrincipal.slice(0, 10)}...`, 50, 80);
}
}
}
const game = new Game();
Backend Canister for Score Storage
// main.mo - Simple score storage
import HashMap "mo:base/HashMap";
import Principal "mo:base/Principal";
import Nat "mo:base/Nat";
import Hash "mo:base/Hash";
actor GameBackend {
private var scores = HashMap.HashMap<Principal, Nat>(0, Principal.equal, Principal.hash);
public shared(msg) func saveScore(score : Nat) : async () {
scores.put(msg.caller, score);
};
public shared(msg) func getScore() : async ?Nat {
scores.get(msg.caller)
};
public func getLeaderboard() : async [(Principal, Nat)] {
var leaderboard : [(Principal, Nat)] = [];
for ((principal, score) in scores.entries()) {
leaderboard := Array.append(leaderboard, [(principal, score)]);
};
leaderboard
};
}
Deployment to ICP
# Start local replica
dfx start --background
# Deploy canisters
dfx deploy
# Get canister URL
dfx canister call my-game-frontend http_request '(record {url="/"; method="GET"; headers=vec{}; body=vec{}})'
Game Frameworks Compatible with ICP
Phaser.js
- Popular 2D game framework
- Large community and examples
- Easy to integrate with Internet Identity
PixiJS
- High-performance 2D rendering
- WebGL support
- Great for browser games
Babylon.js / Three.js
- 3D game development
- Advanced graphics capabilities
- Can run entirely in browser
Pure JavaScript
- No dependencies
- Full control
- Lightweight and fast
Best Practices
- Keep Game State On-Chain - Store critical data in canisters
- Use Internet Identity - Don't build custom auth
- Optimize Assets - Minimize canister storage costs
- Progressive Enhancement - Work offline, sync when online
- Test Locally - Use dfx for development before mainnet deployment
Example Projects
Click Battle
Simple click counter game with leaderboard
Decentralized Chess
Turn-based chess with on-chain game state
NFT Card Game
Collectible card game with NFT integration
Resources
Conclusion
Building decentralized games with Internet Identity and ICP combines the best of web gaming with blockchain benefits. Start simple with pure JavaScript, integrate Internet Identity for authentication, and deploy to ICP for a truly decentralized gaming experience. Your players will own their identities, and your games will live forever on the blockchain.