# Building Subgraph UIs (NextJS/Fetch)

[Subgraphs](https://somnia.chain.love) allow developers to efficiently query Somnia blockchain data using GraphQL, making it easy to index and retrieve real-time blockchain activity. In this tutorial, you’ll learn how to:

* Fetch blockchain data from a Subgraph API
* Fix CORS errors using a NextJS API route
* Display token transfers in a real-time UI

By the end of this guide, you'll have a fully functional UI that fetches and displays token transfers from Somnia’s Subgraph API.

## Prerequisites

* Basic knowledge of React & Next.js.
* A deployed Subgraph API on Somnia ([or use an existing one](https://somnia.chain.love/graph)).
* Account on <https://somnia.chain.love> see [guide](/developer/building-dapps/data-indexing-and-querying/protofire-subgraph.md).

## Create a NextJS Project

Start by creating a new Next.js app.

```bash
npx create-next-app@latest somnia-subgraph-ui
cd somnia-subgraph-ui
```

Then, install required dependencies.

```bash
npm install thirdweb react-query graphql
```

## Define the Subgraph API in Environment Variables

Create a .env.local file in the root folder.

```
NEXT_PUBLIC_SUBGRAPH_URL=https://proxy.somnia.chain.love/subgraphs/name/somnia-testnet/test-mytoken
NEXT_PUBLIC_SUBGRAPH_CLIENT_ID=YOUR_CLIENT_ID
```

{% hint style="info" %}
💡 Note: Restart your development server after modifying .env.local:
{% endhint %}

```bash
npm run dev
```

## Create a NextJS API Route for the Subgraph

Since the Somnia Subgraph API has CORS restrictions, we’ll use a NextJS API route to act as a proxy.

Inside the app directory create the folder paths **`api/proxy`** and add a file **`route.ts`** Update the **`route.ts`** file with the following code:

```typescript
import { NextResponse } from "next/server";

const SUBGRAPH_URL = process.env.NEXT_PUBLIC_SUBGRAPH_URL as string;
const CLIENT_ID = process.env.NEXT_PUBLIC_SUBGRAPH_CLIENT_ID as string;

export async function POST(req: Request) {
  try {
    const body = await req.json();


    const response = await fetch(SUBGRAPH_URL, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Client-ID": CLIENT_ID, // ✅ Pass the Subgraph Client ID
      },
      body: JSON.stringify(body),
    });


    const data = await response.json();
    return NextResponse.json(data);
  } catch (error) {
    console.error("Proxy Error:", error);
    return NextResponse.json({ error: "Failed to fetch from Subgraph" }, { status: 500 });
  }
}
```

This code allows your frontend to make requests without triggering CORS errors.

## Fetch and Display Token Transfers in the UI

Now that we have the API set up, let’s build a React component that:

* Sends the GraphQL query using fetch()
* Stores the fetched data using useState()
* Displays the token transfers in a simple UI

To fetch the latest 10 token transfers, we’ll use this GraphQL query:

```graphql
{
  transfers(first: 10, orderBy: blockTimestamp, orderDirection: desc) {
    id
    from
    to
    value
    blockTimestamp
    transactionHash
  }
}
```

This code fetches the last 10 transfers (first: 10) and orders them by timestamp (latest first). It retrieves wallet addresses (from, to) and the amount transferred (value) and includes the transaction hash (used to generate an explorer link).

## Fetch and Display Data in a React Component

Now, let’s integrate the query into our NextJS frontend. Create a folder **`components`** and add a file **`TokenTransfer.ts`**

We use **`useState()`** to store transfer data and **`useEffect()`** to fetch it when the component loads.

```typescript
"use client";
import { useEffect, useState } from "react";

export default function TokenTransfers() {
  // Store transfers in state
  const [transfers, setTransfers] = useState<any[]>([]);
  
  // Track loading state
  const [loading, setLoading] = useState(true);


Next, we fetch the token transfer data when the component loads.
 useEffect(() => {
    async function fetchTransfers() {
      setLoading(true); // Show loading state


      const query = `
        {
          transfers(first: 10, orderBy: blockTimestamp, orderDirection: desc) {
            id
            from
            to
            value
            blockTimestamp
            transactionHash
          }
        }
      `;


      const response = await fetch("/api/proxy", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ query }),
      });


      const { data } = await response.json();
      setTransfers(data.transfers || []); // Store results in state
      setLoading(false); // Hide loading state
    }


    fetchTransfers();
  }, []);
```

Once data is fetched, we render it inside the UI.

```typescript
return (
    <div className="p-4">
      <h2 className="text-xl font-semibold mb-4">Latest Token Transfers</h2>
      
      {loading ? (
        <p>Loading transfers...</p>
      ) : (
        <ul>
          {transfers.map((transfer) => (
            <li key={transfer.id} className="mb-2 p-2 border rounded-lg">
              <p><strong>From:</strong> {transfer.from}</p>
              <p><strong>To:</strong> {transfer.to}</p>
              <p><strong>Value:</strong> {parseFloat(transfer.value) / 1e18} STT</p>
              <p>
                <strong>TX:</strong>{" "}
                <a
                  href={`https://shannon-explorer.somnia.network/tx/${transfer.transactionHash}`}
                  target="_blank"
                  className="text-blue-600 underline"
                >
                  View Transaction
                </a>
              </p>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}
```

The UI shows a loading message while data is being fetched. When data is ready, it displays the latest 10 token transfers. It formats transaction values (value / 1e18) to show the correct STT amount and provides a link to view each transaction on Somnia Explorer.

## Add the Component to the NextJS Page

Update the page.tsx file:

```typescript
"use client";
import TokenTransfers from "../components/TokenTransfers";

export default function Home() {
  return (
    <main className="min-h-screen p-8">
      <h1 className="text-2xl font-bold">Welcome to MyToken Dashboard</h1>
      <TokenTransfers />
    </main>
  );
}
```

Restart the development server:

```
npm run dev
```

<figure><img src="/files/5dJZgcHeqtX3Dp1U1DS0" alt=""><figcaption></figcaption></figure>

Now your NextJS UI dynamically fetches and displays token transfers from Somnia’s Subgraph! 🔥

<br>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.somnia.network/developer/building-dapps/data-indexing-and-querying/building-subgraph-uis-nextjs-fetch.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
