How I Built a Secure Wordle Game with Next.js and Vercel

Introduction

Wordle has become a cultural phenomenon, challenging players to guess a secret five-letter (maybe more) word in six attempts. The simplicity of the game, combined with the thrill of guessing, has made it incredibly popular. But what if you could build your own version with added security to prevent users from easily finding the answer?

In this post, I’ll take you through how I built my own Wordle game using Next.js, deployed it on Vercel, and added a twist—encrypting the secret word. This way, even if someone tries to peek using dev tools, they won’t easily uncover the solution! Yet, they can, but prolly will consume more time than just guessing for the answer. lol.

Tech Stack

  • Next.js: The React-based framework I used to build the app. It's fast, scalable, and perfect for server-side rendering.
  • Vercel: The platform that makes deploying Next.js apps super easy. My game is hosted here for fast and seamless performance.
  • API: A custom API to retrieve the secret word securely. The word is encrypted to prevent users from accessing it easily.

Features of the Game

Gameplay

In my version of Wordle, players have six attempts to guess a five-letter word. After each guess, they receive feedback:

  • Green for the correct letter in the correct position.
  • Yellow for the correct letter in the wrong position.
  • Gray for a letter that's not in the word.

The goal is simple: guess the secret word before running out of attempts!

Encryption

One of the unique features of my game is the encrypted secret word. The API retrieves the word and encrypts it, ensuring that it can't be accessed easily through browser dev tools. Instead, users are met with a playful message: "What are you looking for?"

This adds a layer of fun and challenge, making it impossible to simply view the answer by inspecting the network requests.

User Experience

The game is designed to be simple yet engaging, with a clean and responsive UI. The feedback on each guess is instantly displayed, allowing players to improve their guesses with each attempt. The encryption also ensures the game remains fair and fun for everyone.

Code Walkthrough

Secret Word API

The heart of the game lies in the API that retrieves the secret word. Here's a simplified version of the API logic:

import crypto from 'crypto';

function encryptWord(word) {
//encryption logic
}

export default function handler(req, res) {
    const secretWords = {
    	english: ["Apple", "Table", "Chair"],
    	indonesian: ["Angka", "Layar", "Bunga"]
    	}
    	
    const { language = 'en' } = req.query;

    if (!['en', 'id'].includes(language)) {
        return res.status(400).json({
            error: "Invalid language selection. Choose 'en' for English or 'id' for Indonesian."
        });
    }

    const wordList = language === 'en' ? secretWords.english : secretWords.indonesian;
    const randomWord = wordList[Math.floor(Math.random() * wordList.length)];

    const secretWord = encryptWord(randomWord);
    let message;

    const response = language === 'en'
        ? { secretWord, message: "Looking for something?" }
        : { kataRahasia: secretWord, message: "Nyari apa kak?" };

    return res.status(200).json(response);

The encryptWord function ensures the word is encrypted before it’s sent to the client. The message "What are you looking for?" is just a playful way of deterring users from trying to guess the secret word via dev tools.

Frontend Logic

On the frontend, the game captures player guesses and compares them to the encrypted word. Here's an example of how guesses are processed:

const handleGuess = (guess) => {
    if (gameState !== "playing") return;

    const upperGuess = guess.toUpperCase();
    if (upperGuess.length !== secretWord.length) {
      setMessage(`Guess must be ${secretWord.length} characters!`);
      return;
    }

    const newStatus = { ...keyStatus };
    const feedback = [...upperGuess].map((char, idx) => {
      if (char === secretWord[idx]) {
        newStatus[char] = "green";
        return { char, color: "green" };
      } else if (secretWord.includes(char)) {
        if (newStatus[char] !== "green") {
          newStatus[char] = "yellow";
        }
        return { char, color: "yellow" };
      } else {
        newStatus[char] = "gray";
        return { char, color: "gray" };
      }
    });

    const newGuesses = [...guesses, feedback];
    setGuesses(newGuesses);
    setKeyStatus(newStatus);

    if (upperGuess === secretWord) {
      setGameState("won");
      setMessage(language === "en" ? "Congratulations! You won! 🎉" : "Selamat! Anda menang! 🎉");
    } else if (newGuesses.length >= MAX_ATTEMPTS) {
      setGameState("lost");
      setMessage(
        language === "en"
          ? `Game Over! The word was ${secretWord}`
          : `Permainan Selesai! Katanya adalah ${secretWord}`
      );
    }
  };

This logic ensures that even though the word is encrypted, the gameplay remains functional and enjoyable.

Challenges Faced

While building this game, I encountered several challenges:

  • Encrypting the word securely: It was important to ensure that even if someone tried to intercept the data, they couldn’t easily figure out the word. Using encryption solved this problem.
  • Creating a responsive UI: Ensuring the game worked well on both desktop and mobile was a bit tricky, but using Next.js and its built-in CSS support made it easier.
  • Handling game state: Keeping track of guesses and attempts while making sure everything synced correctly between the frontend and backend required some careful design decisions.

But with each challenge, I learned something new and found creative ways to implement the features I wanted.

Conclusion

Building this Wordle game with Next.js was a fun and rewarding experience. Not only did I get to recreate a popular game, but I also added a unique twist by encrypting the secret word, making it more secure and adding a playful element to the game.

The game is live on Vercel, and you can play it by visiting my Wordle game here. I hope you enjoy playing it as much as I enjoyed building it!

If you’d like to check out the code, feel free to visit the GitHub repository and maybe even contribute to making it better.

If you enjoyed this project, make sure to follow me on GitHub for more projects and updates. I'd love to hear your feedback and suggestions for future improvements!

Share this post on :