Patch 6.2.0 is live — Clean up of duplicated endpoints & improvement of Typescript SDK.
api-fortnite
← Back to Blog

Build a Fortnite Stats Tracker with Next.js and the Fortnite API

Full tutorial: build a Fortnite player stats tracker web app using Next.js and the Fortnite API. Covers account resolution, stats fetching, and server-side API key safety.

tutorialnextjsplayer-statsweb-app

What We're Building


A web app where users type any Fortnite display name and instantly see their stats. The key pattern: the Fortnite API uses Epic account IDs, so we always resolve a display name to an account ID first, then fetch stats.


Project Setup


npx create-next-app@latest fortnite-tracker --typescript --tailwind
cd fortnite-tracker

Add your API key to .env.local:


FORTNITE_API_KEY=your_key_here

API Route — Keep the Key Server-Side


Create app/api/stats/route.ts:


import { NextRequest, NextResponse } from "next/server";

const BASE_URL = "https://prod.api-fortnite.com";
const HEADERS = { "x-api-key": process.env.FORTNITE_API_KEY! };

export async function GET(req: NextRequest) {
  const displayName = req.nextUrl.searchParams.get("displayName");
  if (!displayName) {
    return NextResponse.json({ error: "displayName required" }, { status: 400 });
  }

  // Step 1: resolve display name → Epic account ID
  const accountRes = await fetch(
    `${BASE_URL}/api/v1/account/displayName/${encodeURIComponent(displayName)}`,
    { headers: HEADERS }
  );
  if (!accountRes.ok) {
    return NextResponse.json({ error: "Player not found" }, { status: 404 });
  }
  const account = await accountRes.json();

  // Step 2: fetch stats with account ID
  const statsRes = await fetch(
    `${BASE_URL}/api/v2/stats/${account.id}`,
    { headers: HEADERS, next: { revalidate: 300 } } // cache 5 min
  );
  const stats = await statsRes.json();

  return NextResponse.json({ account, stats });
}

Search Component


"use client";
import { useState } from "react";

export default function StatsSearch() {
  const [displayName, setDisplayName] = useState("");
  const [result, setResult] = useState<any>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState("");

  async function handleSearch(e: React.FormEvent) {
    e.preventDefault();
    setLoading(true);
    setError("");
    setResult(null);

    const res = await fetch(
      `/api/stats?displayName=${encodeURIComponent(displayName)}`
    );
    const json = await res.json();

    if (!res.ok) {
      setError(json.error ?? "Something went wrong");
    } else {
      setResult(json);
    }
    setLoading(false);
  }

  return (
    <div className="max-w-xl mx-auto p-6">
      <form onSubmit={handleSearch} className="flex gap-2 mb-6">
        <input
          value={displayName}
          onChange={(e) => setDisplayName(e.target.value)}
          placeholder="Epic display name..."
          className="flex-1 border rounded px-3 py-2"
        />
        <button type="submit" disabled={loading}
          className="bg-blue-600 text-white px-4 py-2 rounded">
          {loading ? "..." : "Search"}
        </button>
      </form>

      {error && <p className="text-red-500">{error}</p>}
      {result && (
        <pre className="bg-gray-100 rounded p-4 text-sm overflow-auto">
          {JSON.stringify(result, null, 2)}
        </pre>
      )}
    </div>
  );
}

Ranked Stats


For level, XP, and ranked/arena progress, use the profile endpoints (requires Starter plan or above):


// Player level & XP
const progressRes = await fetch(
  `${BASE_URL}/api/v1/profile/progress?displayName=${encodeURIComponent(displayName)}`,
  { headers: HEADERS }
);

// Ranked/arena progress
const rankedRes = await fetch(
  `${BASE_URL}/api/v1/profile/ranked?displayName=${encodeURIComponent(displayName)}`,
  { headers: HEADERS }
);

Deployment


npx vercel --prod

Set FORTNITE_API_KEY in your Vercel project environment variables. Your tracker is live.


Related Guides


  • How to Track Fortnite Player Stats in Real-Time
  • Getting Started with the Fortnite API