play

One surf-banner on the real Surfside test account, web components, no build step — the shape 474 of the 578 counted estate sites run. Not a release gate: the deck on 4001–4007 proves a release, this page is for trying one thing by hand against real IDs. Port 4008.

Starting up…
Resolving config/sites.json.

What to do on this page

  1. Read the verdict. It distinguishes the three things that look identical from the outside: a broken SDK, an invalid run, and no demand.
  2. Click a size. width/height are an aspect ratio, not pixels. If 8×1 is a 204 and 4×1 fills, the zone simply has no 8:1 creative — that is demand, not the SDK.
  3. Check the bid count went up by exactly one. Each click writes two observed attributes, which mints two totems and re-arms one debounce. Two writes, one auction.
  4. Compare win against impression pixels. One distinct URL of each is owed per filled bid. Any other arithmetic is the fault this instrument exists to catch.

Everything here is read from the network and the DOM, including the account's own publisher config. Nothing is simulated and no SDK logic is reimplemented — if a number looks wrong, it is wrong.

Zone

No category attribute on purpose, so ext.surfCategory is whatever the publisher's category patterns derive from this URL — the same fallback the estate relies on.

size (aspect ratio)
8×1, from markup

Resolved identity

Checks

Surfside network, as the page can see it

From PerformanceObserver, which sees both shapes the SDK uses — fetch/XHR and the bare img.src win pixel in Trackers.ts. The status column is the diagnosis: 204 on a bid is a handled no-fill, 403 on the publisher config silently stops the api initialising, and status? means the browser did not expose one.

kindcountHTTP
This account's live publisher config

Fetched from r.surfside.io/<account>/<site>/config.json on load, not written down here, because a page that documents a config it has not read will eventually lie. reauctionEnabled is the one that changes a verdict: with it false, one auction per zone is the whole story and an unforced re-render is a fault rather than the expected heartbeat.

Why this page is in the beta repo at all

It shares the instrument with the deck by symlink — public/site.js points at sites/standard/public/site.js and public/spa.css at sites/standard-spa/public/spa.css. So the mechanics being exercised here are byte-identical to the ones the release gate uses, and a scratch page can never drift into a second, subtly different copy of the diagnostic surface. Only this file and play.js are local.

It also happens to be the only site in the repo with real provisioned IDs today, and the only one with reauctionEnabled:false — a config variant the deck wants and the beta account does not yet have.

placement-id is a static-markup-only alias for zone-id

This page replaced a hand-written snippet that used placement-id. That works, but only by luck of timing: readBaseAttributes reads First(zone-id, placement-id), so a placement-id sitting in static markup before element upgrade is picked up by connectedCallback. But observedBaseAttributes lists only zone-id, so setAttribute('placement-id', …) after load fires no attributeChangedCallback and changes nothing at all. Prefer zone-id.

[beta] booting…