Documentation
Badge
The "Built by 0 Hour Studio" footer signature — on every build by default.
Badge · "Built by 0 Hour Studio"
The signature that ships in the footer of every site and prototype we build and host — our "Made in Webflow." A traffic driver and backlink engine. On by default — hidden after a paid upgrade.
Hover either badge to trigger the glow — this is the real component, live:
The mark is our wireframe sphere + glyph. Default state is plain black/white; on hover / click / focus the glowing logo crossfades in. Type is Blanc — "Built by" Ultralight, "0 HOUR STUDIO" Bold. Square card whose fill matches the logo so there's no visible image box.
Use it
One source of truth: ~/0-hr/components/built-by-badge/. Import the gate, never copy-paste the markup.
import { BadgeGate } from "@/components/built-by-badge";
// dark footer
<BadgeGate client="lateral" variant="dark" />
// light footer
<BadgeGate client="mcm" variant="light" />| Prop | Values | Notes |
|---|---|---|
client | "mcm" · "dh" · "lateral" … | Per-site slug → ?ref=<client>. This is the attribution key — see Tracking. Required. |
variant | "dark" · "light" | dark = light mark/text for dark footers · light = for light footers. |
markSize | px (default 30) | Mark size. |
The link resolves to:
https://0hr.app/studio/showcase?ref=<client>&utm_source=client_site&utm_medium=badgeThe & is a literal ampersand — never & or any escaped variant (a prior build corrupted this and broke tracking). The component builds the URL via string concat to guarantee it. (Destination is temporarily the Studio showcase; reverts to 0hourstudio.com later.)
Tracking — where the clicks land
The ?ref= param was carried correctly from day one, but for months nothing read it: the showcase page dropped the query string, fired no event, and the portal had no GTM or pixel ID in production. Badge referrals were uncountable, not zero. As of 2026-09-09 the landing is instrumented:
| Event | Fires when |
|---|---|
showcase_view | A badge visitor lands on /studio/showcase |
showcase_cta_click | They click "Get Your Custom Roadmap" (placement: sidebar | footer) |
Both carry ref, utm_source, utm_medium and utm_campaign straight off the URL, so referral volume is attributable per client install — and the view→CTA pair gives you a conversion rate, not just a hit count.
Events go out through the one track() in lib/analytics/track.ts (dataLayer + gtag + Meta), and — critically — to the first-party sink at POST /api/track, which writes them to the existing play ledger. No new table. Third-party tags are routinely ad-blocked; the same-origin sink is the number to trust, and it will read higher than Meta.
play.source = "showcase"
play.type = "page_view" // play_type_check is a CHECK constraint —
play.data.event = "showcase_view" // the real event name lives in data.event
play.data.ref = "mcm" // which client's badge sent them
play.brand_id = <the 0hr brand> // the showcase is 0HR's own surface, so views
// roll up to 0HR, not to the referring clientCount referrals from one install:
select data->>'event' as event, count(*)
from play
where source = 'showcase' and data->>'ref' = 'mcm'
group by 1;The event name is the contract. /api/track drops anything not on its allow-list — that is exactly how the first version of this wrote nothing at all. Adding an event means adding it in both lib/analytics/track.ts and the ALLOWED set in app/api/track/route.ts.
Removal lock — standing policy
The badge ships on every install and prototype by default. It comes out only when a client has cleared their full balance and owns the build outright.
To remove it for a project:
- Set
OHS_BADGE_LOCKED = false(or passlocked={false}to<BadgeGate>). - In the same commit, state the reason — e.g. "ohs-badge: unlock for mcm — POC paid in full, ownership transferred 2026-06-01."
While OHS_BADGE_LOCKED is true, the badge renders. Flipping it to false is the explicit, auditable act that authorizes removal.
Every instance — where the badge actually is
Verified 2026-09-09. Tracked means a click on that badge writes a badge_click row; see Tracking.
| # | Instance | Slug | Where it renders | Tracked |
|---|---|---|---|---|
| 1 | MCM Private Care — brands/mcm/site/app/components/Footer.tsx | mcm | Global footer → mcmprivatecare.com, every page | ✅ Live |
| 2 | /os/badge demo — apps/docs/.../BuiltByBadgeDemo.tsx | demo | This page, both variants | ✅ Live (tagged docs_demo so doc traffic never inflates a client's count) |
| 3 | Different Hunger — brands/dh/site/app/components/Footer.tsx | dh | Global footer, dh-site Vercel URL only — no custom domain yet | ✅ Code ready, not on a public domain |
| 4 | Canonical source — components/built-by-badge/ | — | Not a deployment. BuiltByBadge.tsx · track.ts · index.tsx (BadgeGate) | — |
Not tracked — the fix list
| Instance | Problem | Fix |
|---|---|---|
| Lateral — live site | lateralfulfillment.com carries no badge at all. A shipped client site earning zero referrals. | Add <BadgeGate client="lateral" variant="…" /> to the footer. |
brands/lateral/site/_export/*.html (5 files: index, about, presales, pricing, resources) | Stale local export of an older, different badge — gradient pill reading "Made by 0 Hour Studio", pointing at 0hourstudio.com. Its href is corrupted: the ampersands were mangled into </body>amp;, so the params are junk. Not deployed — the live site is served from elsewhere. | Replace with the canonical component; don't patch the export. |
apps/showcase/badge-preview.html | Old preview, same pre-showcase 0hourstudio.com destination, no beacon. | Repoint or delete. |
components/built-by-badge/_b · _r · _sq · _tight · _v .html | Static screenshot mock-ups used to render the PNG marks. Not deployed, no beacon needed. | Leave as is. |
The corrupted-ampersand case is the one to learn from. It is exactly what the string-concat rule above exists to prevent, and it is invisible until someone reads the raw href — the badge still looks and clicks fine.
See it in the wild
Scroll to the footer and hover the badge to trigger the glow: mcmprivatecare.com — the only badge on a public client domain today.
Badge destination (where every badge points): 0hr.app/studio/showcase
Rollout: Lateral, Beezys and the starter template are still outstanding — see the fix list above.



