Badge
Pages served by CloudGrid carry a small corner badge: "Running on Cloud Grid". It identifies the platform and collects feedback from viewers. This page is the contract for how the badge is delivered, what it does, and how to control or theme it.
1. Delivery
The badge is a standalone script served at https://api.cloudgrid.io/badge.js. The platform injects a small <script src="…"> tag before </body> on served HTML — for Inspirations at serve time, for Apps at the ingress layer. The script bytes are never inlined into your page, so the browser caches the bundle once across all entities.
Cache headers: Cache-Control: public, max-age=86400, must-revalidate — bundle updates roll out within a day.
2. The injected script tag
The injected tag carries these attributes:
| Attribute | Required | Value |
|---|---|---|
src | yes | https://api.cloudgrid.io/badge.js |
data-cloudgrid-tag | yes | Tag identity slug — fixed "badge" for this contract |
data-cloudgrid-badge | yes (legacy compat) | Presence flag |
data-cloudgrid-entity | yes | Entity UUID |
data-cloudgrid-org | yes | Grid slug (e.g. acme), not a UUID |
data-cloudgrid-badge-mode | yes (when emitted) | auto (default — respects a session dismiss), force-show (platform-forced), locked-show (grid-forced) |
data-cloudgrid-position | no | bottom-right (default), bottom-left, top-right, top-left |
data-cloudgrid-theme | no | JSON object — theme keys from the whitelist below; unknown keys are dropped |
When the resolved badge state is off, the platform suppresses the snippet entirely — no hidden tag is emitted.
3. Behavior — three states
Idle
- Small fixed-corner element (default bottom-right, about 120×30px on desktop; smaller on mobile)
- Contents: CloudGrid wordmark + "Running on Cloud Grid"
- Subtle shadow, rounded corners; pointer cursor on hover
Expanded (on click)
A slide-over panel (about 360px wide on desktop; bottom-sheet on mobile) with three sections:
- About — a short platform description and a link to
cloudgrid.io(opens in a new tab). - Feedback — a category dropdown (
reaction,bug,feature_request,comment,other), a free-text field, and a submit button. - Close — an X button; Esc and clicking outside also close the panel.
Confirmed (after a feedback submit)
- "Thanks — feedback received." shows inline for about a second, then the panel collapses back to the corner chip. Form fields are cleared.
- The chip stays on the page. Clicking it again re-opens the panel ready for another submission — a viewer can send any number of separate feedback entries in one page session.
Trigger semantics
The panel opens only on click. No auto-popup, no hover trigger, no timed flash.
4. Theming
All badge styling reads CSS variables with these defaults, inside a closed Shadow Root — your page's CSS never leaks into the badge, and the badge never leaks into your page:
--cg-badge-bg: #1f2937;
--cg-badge-fg: #f9fafb;
--cg-badge-accent: #3b82f6;
--cg-badge-radius: 6px;
--cg-badge-shadow: 0 1px 3px rgba(0,0,0,0.12);
--cg-badge-font: system-ui, sans-serif;
A grid-level theme, when set, rides in on data-cloudgrid-theme as a JSON object whose keys are the bare names (bg, fg, accent, radius, shadow, font). Keys outside the whitelist are dropped; values containing ;, {, }, or </ are rejected. Position is set per entity via data-cloudgrid-position; default bottom-right.
Theme editing UI is not shipped yet — the schema is ready and the badge already applies a theme when one is set.
5. Turning the badge on and off — precedence
Three levels, resolved top-down. Platform beats grid; grid beats entity:
1. platform policy 'force_on' → badge ON (everything else ignored)
2. platform policy 'force_off' → badge OFF
3. grid policy 'force_on' → badge ON (entity setting ignored)
4. grid policy 'force_off' → badge OFF
5. entity badge_mode 'on' → badge ON
6. entity badge_mode 'off' → badge OFF
7. (none of the above) → ON (the default)
Setting badge_mode on an entity (PATCH /api/v2/entities/<id>) when a grid or platform policy would override it returns 403 BADGE_POLICY_OVERRIDE. The message names the source (platform policy or your grid) and the direction (forces it on / forces it off), so you know whom to contact. The request is refused up front — it is not silently accepted and ignored.
6. Feedback endpoint
POST https://api.cloudgrid.io/api/v2/entities/<entity_id>/feedback
Headers:
Content-Type: application/json
(no Authorization — feedback is unauthenticated; rate-limited per IP + entity)
Body:
{
"category": "reaction" | "bug" | "feature_request" | "comment" | "other",
"text": string (max 2000 chars),
"source": "badge",
"user_agent": string (optional),
"page_url": string (optional)
}
Response 200:
{ "ok": true }
Response 4xx:
{ "error": string, "code": string }
7. Idempotency
The bundle exposes one global symbol: window.__CloudGridBadge. Loading the script twice is a no-op — the first init wins.
8. Not in this version
- Per-grid logo upload
- Custom calls-to-action beyond the About link
- Impression / click analytics
- Languages beyond English
- Custom feedback categories (categories are platform-level)
- Changing the "Running on Cloud Grid" wording (display state is controllable per the precedence rules; phrasing is platform-controlled)