What this tool does
The Beacon Proxy Checker reads a contract address and tells you specifically whether it resolves through an EIP-1967 beacon, which beacon contract it shares, and what implementation that beacon currently points to. It’s the same resolution engine behind the general Proxy Detector, narrowed to the one question that matters when you’re staring at a suspected beacon proxy: if I call this address, whose logic actually runs, and how many other contracts run that same logic?
Key facts
- Resolves EIP-1967 beacon proxies in two hops: the proxy to its beacon contract, then the beacon to the implementation address it currently serves.
- A single beacon can be referenced by anywhere from one proxy to tens of thousands, so upgrading the beacon updates every linked proxy’s logic at once without touching their storage.
- Supports Ethereum, Base, and BNB Smart Chain, with more EVM chains being added.
- Reflects the beacon’s currently stored implementation at the time of the read; that pointer can change independently of any individual proxy.
How to use it
- Paste the contract address into the form above, or pick the pre-loaded demo: The Sandbox’s avatar beacon proxy on Ethereum.
- Pick the chain the contract is deployed to.
- Run the query and read the resolved chain. A Beacon proxy shows two hops: the proxy pointing at its beacon, then the beacon pointing at the implementation it currently serves.
If the address isn’t a beacon proxy, the result panel says so and shows whatever pattern it did match instead, or reports that calls execute directly on the address with no proxy involved. A raw JSON toggle at the bottom shows the full response for debugging.
What is happening under the hood
Most proxy standards store an implementation address directly in the proxy’s own storage. A Beacon proxy does something different: its EIP-1967 beacon slot holds the address of a separate beacon contract, and the proxy asks that beacon for the implementation address on every call rather than keeping its own copy. The beacon contract itself is usually a small, purpose-built piece of code exposing an implementation() getter, nothing more.
This indirection exists for one reason: fan-out. A protocol that deploys many near-identical contracts, one per user, one per NFT collection, one per avatar, can point every instance at the same beacon. Upgrading the beacon’s stored implementation instantly changes the logic every proxy runs on its next call, without touching a single byte of any individual proxy’s storage. The Sandbox uses exactly this pattern for its avatar contracts: each user’s avatar is a thin proxy pointed at a shared beacon, so The Sandbox can ship a logic upgrade once and have it apply across every avatar in circulation.
evmquery resolves this server-side with the same resolution include used across all proxy detection on this site:
POST /query/describe{ "chain": "evm_ethereum", "schema": { "contracts": { "target": { "address": "0x..." } } }, "include": ["resolution"]}resolution.routeis an ordered list of hops. For a beacon proxy, the first hop haskind: "eip1967-beacon"and atoaddress pointing at the beacon contract, not the implementation.- The second hop has
kind: "beacon-implementation", and itstoaddress is the actual implementation the beacon currently serves. This is the address whose code runs when you call the original proxy. - An empty route means the address isn’t a proxy at all. A route that starts with a different
kind,eip1967,eip1822,eip2535-diamond, and so on, means it matched a different pattern; the Proxy Detector resolves all of them in one place.
Build this yourself
Each snippet below makes the same POST call to the evmquery REST API, then walks the returned route looking specifically for a beacon hop followed by its implementation hop. The example targets The Sandbox’s avatar beacon proxy on Ethereum, the same contract loaded by default in the tool above.
REST (curl)
curl -X POST https://api.evmquery.com/api/v1/query/describe \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "chain": "evm_ethereum", "schema": { "contracts": { "target": { "address": "0x8712238c3CCE66f7207e60BdaBF615D9A9C3d299" } } }, "include": ["resolution"] }'Python
import requests
resp = requests.post( "https://api.evmquery.com/api/v1/query/describe", headers={"x-api-key": "YOUR_API_KEY"}, json={ "chain": "evm_ethereum", "schema": { "contracts": {"target": {"address": "0x8712238c3CCE66f7207e60BdaBF615D9A9C3d299"}}, }, "include": ["resolution"], }, timeout=10,)data = resp.json()route = data["contracts"][0]["_extension"]["resolution"]["route"]
beacon_hop = next((hop for hop in route if hop["kind"] == "eip1967-beacon"), None)impl_hop = next((hop for hop in route if hop["kind"] == "beacon-implementation"), None)
if beacon_hop and impl_hop: print(f"Beacon: {beacon_hop['to']}") print(f"Implementation served by beacon: {impl_hop['to']}")else: print("Not a beacon proxy")TypeScript
const resp = await fetch("https://api.evmquery.com/api/v1/query/describe", { method: "POST", headers: { "x-api-key": process.env.EVMQUERY_API_KEY!, "Content-Type": "application/json", }, body: JSON.stringify({ chain: "evm_ethereum", schema: { contracts: { target: { address: "0x8712238c3CCE66f7207e60BdaBF615D9A9C3d299" }, }, }, include: ["resolution"], }),});const schema = await resp.json();const route = schema.contracts[0]._extension.resolution.route as { kind: string; to: string;}[];
const beaconHop = route.find((hop) => hop.kind === "eip1967-beacon");const implHop = route.find((hop) => hop.kind === "beacon-implementation");
if (beaconHop && implHop) { console.log(`Beacon: ${beaconHop.to}`); console.log(`Implementation served by beacon: ${implHop.to}`);} else { console.log("Not a beacon proxy");}The free tier has no monthly cap. Get a free API key to drop these snippets into your project.
When you would use this
- Auditing a single instance from a larger fleet. If a contract is one of many proxies sharing a beacon, its behavior today is only as trustworthy as the beacon it defers to. Resolving the beacon hop tells you where the real upgrade authority sits.
- Confirming a shared-upgrade pattern before you build against it. If you’re integrating with a protocol that uses beacon proxies for per-user or per-item contracts, knowing the beacon address up front means you can watch that one address for future implementation changes instead of tracking every proxy individually.
- Ruling out the beacon pattern. Not every proxy that looks similar to a beacon setup actually uses one. A clean, non-beacon result tells you to look at Transparent, UUPS, or Diamond resolution instead.
FAQ
What is a Beacon proxy (EIP-1967 beacon slot)?
A Beacon proxy is a proxy contract whose EIP-1967 beacon slot holds the address of a separate beacon contract, rather than storing an implementation address directly. The proxy asks the beacon for the current implementation on every call, so the beacon becomes the single source of truth for where calls end up.
How is a Beacon proxy different from a Transparent proxy?
A Transparent (EIP-1967) proxy stores the implementation address directly in its own storage slot and includes upgrade logic in the proxy itself. A Beacon proxy stores a beacon address instead, and defers the implementation lookup to that beacon contract on every call. The practical difference shows up at upgrade time: upgrading a Transparent proxy only changes that one proxy, while upgrading a beacon changes the implementation for every proxy pointed at it.
How many individual proxies can share one beacon, and why does that matter?
There is no protocol-level limit: a beacon can be referenced by anywhere from one proxy to tens of thousands. That is the point of the pattern. A single beacon update rolls the new implementation out to every proxy that points at it at once, without touching each proxy’s storage individually. It also means a beacon is a single point of upgrade control for a whole fleet of contracts, worth knowing before you trust any one instance in isolation.
Why do protocols use beacon proxies instead of one-off proxies?
Beacons are built for deploying many near-identical contracts that should all upgrade together, think NFT collections, per-user vaults, or per-item avatar contracts. Instead of upgrading thousands of individual proxies, a protocol upgrades one beacon and every proxy referencing it picks up the new implementation on its next call. The Sandbox’s avatar contracts are a real example of this: each user’s avatar is a thin proxy pointed at a shared beacon.
Can I try a real beacon proxy in this tool?
Yes. The address field is pre-filled with The Sandbox’s avatar beacon proxy on Ethereum, and the demo picker includes it alongside other real, publicly known contracts covering different proxy patterns, so you can see a beacon resolve immediately without needing your own address.
Which chains are supported?
Ethereum, Base, and BNB Smart Chain today. More EVM chains are being added on the evmquery backend.
What if I need to check a different proxy pattern?
Use the Proxy Detector to check any proxy pattern, not just beacons, including Transparent, UUPS, and legacy OpenZeppelin proxies. If you’re chasing a Diamond (EIP-2535) contract instead, with its fan-out of facets rather than a single beacon, use the Diamond Proxy Checker.
Limits and accuracy
- The result reflects the beacon’s stored implementation at the time of the read. A beacon’s implementation can change independently of any individual proxy, so a route resolved today may point somewhere else tomorrow.
- The demo is rate limited per browser. If you hit the limit, grab a free API key and the limit goes away.
This is pattern and routing detection, not storage-slot decoding or a security audit. Resolving a beacon and its current implementation does not imply that implementation is safe to interact with.
Related
- Proxy Detector: check any proxy pattern, not just beacons, Transparent, UUPS, Diamond, and more, resolved in one place
- Diamond Proxy Checker: check for Diamond (EIP-2535) proxies instead, where calls fan out across many facet contracts rather than a single beacon
- evmquery for developers: the full integration story