Snippet

The embed widget is an iframe that loads the tracking page view from https://walletsleuth.app/embed/tracking/{trackingPageId}?key={publicApiKey}. The dashboard generates the exact snippet for you, but the mechanics are simple enough to write by hand.

The snippet

<iframe
  src="https://walletsleuth.app/embed/tracking/YOUR_PAGE_ID?key=ws_pub_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  width="100%"
  height="600"
  frameborder="0"
  allow="clipboard-write"
  style="border-radius: 12px;"
></iframe>

What each part does

PartRequiredNotes
src path /embed/tracking/{id}yesid is the tracking page ID, visible in the dashboard URL.
?key=ws_pub_...yesPublic API key in the query string. The iframe route rejects missing keys, revoked keys, and secret keys.
width="100%"recommendedFills the parent container. The widget has an internal min-width but is fully responsive.
height="600"requiredThe iframe has a fixed height — the widget does not currently auto-resize or post a contentHeight message to the parent. Pick a height that comfortably fits your wallet table; 600px is a good starting point.
frameborder="0"recommendedRemoves the default iframe border for a seamless look.
allow="clipboard-write"recommendedLets visitors copy wallet addresses from the table directly.
style="border-radius: 12px;"optionalPurely cosmetic.

Why ?key= is in the URL, not a header

Iframes can't set request headers on their initial document load. The key has to travel in a way the browser will send automatically — which leaves the URL. The server resolves the key, validates it against the allowed origins of the parent page (via Content-Security-Policy: frame-ancestors), and then renders the shell.

Because the key is a public key with an origin allowlist, exposing it in HTML is not a leak — it only works from the origins you've allowlisted. Treat it like a publishable Stripe key.

Sizing notes

  • Height is fixed. The widget doesn't postMessage its content height. Give it a value generous enough for the wallet table without internal scrolling, or accept the internal scroll (the table is scrollable by design).
  • Width works best at 100%. The layout is designed to adapt down to roughly 320px on mobile.
  • No lazy-loading recommended. The iframe is server-rendered and is fast; loading="lazy" works but isn't necessary.

CSP on the parent page

The iframe itself sends Content-Security-Policy: frame-ancestors <your-allowed-origins>, which means the browser will refuse to render it inside an origin not on the key's allowlist. This is the authoritative check.

Your parent page does not need to mention walletsleuth.app in its own CSP. If your parent page sets a strict CSP that forbids framing altogether, you need to relax it enough to allow child iframes. A minimal compatible policy for the parent looks like:

Content-Security-Policy: frame-src https://walletsleuth.app;

Multiple widgets on one page

You can embed widgets for multiple tracking pages on the same parent page. Each iframe is isolated: separate API key, separate session cookie, separate rate-limit buckets. There's no cross-iframe communication.

What the iframe actually renders

The iframe loads a compact view of the tracking page:

  • A header with tokenName and $tokenSymbol (plus optional publicTitle and publicComments set by the owner).
  • A scrollable wallet table showing address, tags, and balance. Wallets marked "hide from public" by the owner are excluded.
  • A collapsible Submit a wallet form for visitors to add their own wallet (requires a Solana signature — see SIWS signing).
  • A "Your submissions" section for the current visitor session.

Related