Drop-in React components that fetch and display ERC-8004 agent data directly from the blockchain. No manual data wiring. No custom UI work.
Built for blockchain developers and AI coding agents.
Plus testnets — Base Sepolia, BSC Chapel, Monad Testnet. The chain is read off the agent identifier; no network config, no RPC URL, no wallet.
Rendering one number from the ERC-8004 subgraph means knowing the deployment ID for the chain, the shape of the entity ID, which values come back as strings, and which rows are revoked. Multiply that by every field on the page.
const SUBGRAPH_IDS: Record<number, string> = {
1: "FV6RR6y13rsnCxBAicKuQEwDp8ioEGiNaWaZUmvr1F8k",
8453: "43s9hQRurMGjuYnC1r2ZwS6xSQktbFyXMPMqGKUFJojb",
// ...one entry per chain you support
}
function useReputation(agentRegistry: string, agentId: number) {
const [, chainId] = agentRegistry.split(":")
const subgraphId = SUBGRAPH_IDS[Number(chainId)]
if (!subgraphId) throw new Error("Unsupported chain")
return useQuery({
queryKey: ["reputation", chainId, agentId],
queryFn: async () => {
const res = await fetch(
`https://gateway.thegraph.com/api/${KEY}/subgraphs/id/${subgraphId}`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: `query ($agent: String!) {
// no precomputed average exists; rows are cumulative totals
stats: agentFeedbackStats_collection(
interval: day
where: { agent: $agent }
orderBy: timestamp
orderDirection: desc
first: 1
) {
feedbackCreated
feedbackRevoked
valueDeltaSum
}
}`,
// the entity id is chainId:agentId — not the registry string
variables: { agent: `${chainId}:${agentId}` },
}),
}
)
const json = await res.json()
if (json.errors?.length) throw new Error(json.errors[0].message)
const row = json.data?.stats?.[0]
if (!row) return null // agent exists, no feedback yet
// BigInt and BigDecimal arrive as strings; derive the average yourself.
// valueDeltaSum excludes revoked feedback — valueSum does not, and
// pairing it with this denominator would inflate the score.
const total =
parseInt(row.feedbackCreated, 10) - parseInt(row.feedbackRevoked, 10)
return {
total,
average: total > 0 ? parseFloat(row.valueDeltaSum) / total : 0,
}
},
})
}
// ...then render loading, error, empty and not-found states.
// Then do all of it again for feedback, validation and identity.import { ReputationScore } from "@p4n/erc8004-ui"
<ReputationScore
agentRegistry="eip155:8453:0x8004...a432"
agentId={888}
/>Nothing below is a mockup. Each component was handed the same two identifiers and queried Base in your browser as this page loaded.
The validation components aren't shown here — the Validation Registry isn't deployed to mainnet yet, so on Base they render their empty state by design. They're documented and previewable against testnet data.
There is no store to configure and no agent object to thread through your tree. Drop a component in, give it an identity, and it takes care of the rest.
Components accept identifiers, never display data. There is no prop that lets you put a score on screen that isn't on-chain.
Pass agentRegistry and agentId, or wrap a subtree in AgentProvider once and let every component inside resolve its own identity.
Each component asks for only the fields it renders — ReputationScore requests two, not the twenty FeedbackList needs.
Loading, error, empty and not-found are handled inside every component. An agent with no feedback renders an empty state, not a crash.
One block of custom properties retunes surfaces, accents, radii and the chart palette. Dark mode is a class, not a second stylesheet.
TanStack Query backs every component, so duplicate queries collapse into one request and repeat renders come from cache.
Most teams shipping ERC-8004 are backend teams, and the UI work gets handed to Claude Code or Cursor. So the docs are published in a form an agent can consume directly — no scraping, no guessing at props.
Read https://erc8004-ui.vercel.app/llms.txt, then build me an agent profile page with @p4n/erc8004-ui.
A read-only Graph API key is the only credential involved. No wallet, no RPC provider, no indexer to run.
The library plus its one peer dependency. React 18 or 19. TanStack Query is the cache the components run on — you install it, but you never have to configure it.
npm install @p4n/erc8004-ui @tanstack/react-queryERC8004Provider holds infrastructure config only — your Graph API key, and optional subgraph overrides. It stores no agent data, and sets up its own query cache unless your app already has one.
import { ERC8004Provider } from "@p4n/erc8004-ui"
export function App() {
return (
<ERC8004Provider apiKey="your-graph-api-key">
<Profile />
</ERC8004Provider>
)
}Name the agent once and every component below it resolves its own identity, runs its own query, and shares the cache.
import {
AgentProvider,
AgentCard,
ReputationScore,
FeedbackList,
} from "@p4n/erc8004-ui"
function Profile() {
return (
<AgentProvider
agentRegistry="eip155:8453:0x8004...a432"
agentId={888}
>
<AgentCard />
<ReputationScore />
<FeedbackList />
</AgentProvider>
)
}