Badge
The "Built with BuildBase" badge, with an optional referral code and any link params you need.
<BuildBaseBadge /> renders the "Built with BuildBase" badge. It is a wrapper around the hosted image at buildbase.app/badge/v1/, not a second renderer, so the badge in your React app, in a README, and in a plain HTML footer are the same bytes and cannot drift apart.
import { BuildBaseBadge } from '@buildbase/sdk/react';
function Footer() {
return <BuildBaseBadge />;
}No provider required. It has no context, no hooks, and no network calls of its own, so it works in a server component and in a footer that sits outside <SaaSOSProvider>.
You do not need the SDK at all to show a badge. It is an image. If the page you want it on is Webflow, Framer, WordPress or hand-written HTML, copy the plain <img> snippet from buildbase.app/badges instead. This component is a convenience for apps that already have the SDK, not a requirement.
Props
| Prop | Accepts | Default |
|---|---|---|
variant | built-with, powered-by, mark | built-with |
theme | auto, light, neutral, dark | auto |
size | sm, md, lg | md |
refCode | your referral code | none |
params | any { key: value } object, added to the link | none |
alt | overrides the default alt text | per variant |
className | applied to the wrapping anchor | none |
link | false renders the image with no anchor | true |
<BuildBaseBadge variant="powered-by" theme="dark" size="sm" />theme="auto" carries both palettes and follows the reader's system setting with no JavaScript on the page. Pick a fixed theme when the surrounding surface does not change with the OS setting, and pick one for a README specifically: GitHub proxies images through a cache that keeps a single rendering, so auto freezes on whichever theme it saw first.
The image ships explicit width and height with loading="lazy" and decoding="async", so it reserves its own box and contributes nothing to layout shift.
Set link={false} only where the badge already sits inside another anchor. Nesting anchors is invalid HTML and browsers recover from it unpredictably.
Referral code
Set refCode and the badge links back with a ?ref= param, so visits it sends can be credited to you.
<BuildBaseBadge refCode="acme-studio" />https://www.buildbase.app/?utm_source=badge&utm_medium=built-with&ref=acme-studio
The code is coerced rather than validated: lowercased, narrowed to letters, numbers, hyphens and underscores, and truncated at 64 characters.
<BuildBaseBadge refCode="Acme Studio" /> // → ref=acme-studio
<BuildBaseBadge refCode="!!!" /> // → no ref, plain badge linkThat is the rule for the whole component: a bad value costs the attribution, never the render. This runs in the render path of your footer, so a code someone typed with a space in it must never throw inside your layout.
If you let users enter their own code, coerceBadgeRef is exported so you can show them what it will become before they save it:
import { coerceBadgeRef } from '@buildbase/sdk/react';
coerceBadgeRef('My Studio'); // 'my-studio'
coerceBadgeRef('!!!'); // undefinedWhy the prop is refCode and not ref
React intercepts a prop named ref on React 18 and never passes it to a function component. React 18 is still in this package's peer range, so a prop spelled ref would work on React 19 and silently send no attribution at all for every React 18 consumer, with the badge rendering perfectly the whole time.
The query param is ref. Only the prop is renamed.
refCode sets ref and nothing else
It does not also write utm_campaign for you. A referral is who sent someone; a campaign is which piece of marketing they clicked. Deriving one from the other turns campaign reporting into a list of customer names and overwrites the name of a real campaign that happens to carry a referral too. If you want both, send both:
<BuildBaseBadge refCode="acme" params={{ utm_campaign: 'spring-launch' }} />...&ref=acme&utm_campaign=spring-launch
Affiliate links
If you are on an affiliate program, the tooling generates links with ?via=. That param is accepted too, and it stays separate from ref:
<BuildBaseBadge params={{ via: 'dharmendra' }} />
<BuildBaseBadge refCode="acme" params={{ via: 'dharmendra' }} />...&via=dharmendra
...&ref=acme&via=dharmendra
The two mean nearly the same thing, which is exactly why they do not merge. ref is ours, from a badge or a hand-built link. via belongs to an affiliate program with its own ledger. Which one a visit arrived on is what decides where the credit gets settled.
Any other params
params is appended to the badge's link verbatim. Nothing is filtered for being unrecognised — what we choose to interpret on arrival is our business, not something that should limit what you put in a link on your own site.
<BuildBaseBadge params={{ plausible_id: 'footer', anything_at_all: 'yes' }} />...&plausible_id=footer&anything_at_all=yes
Keys and values go through URLSearchParams, so there is no character you have to avoid or escape first:
<BuildBaseBadge params={{ note: 'a&b=c d?e#f', emoji: 'hi 🌍' }} />...¬e=a%26b%3Dc+d%3Fe%23f&emoji=hi+%F0%9F%8C%8D
null and undefined entries are skipped, so you can build the object conditionally without littering the URL with empty params:
<BuildBaseBadge
params={{ a: 1, b: true, skipped: null, alsoSkipped: undefined }}
/>...&a=1&b=true
Params are written last, so they can deliberately override the badge's own utm_source and utm_medium if your naming scheme needs it:
<BuildBaseBadge variant="mark" params={{ utm_source: 'partner-site' }} />https://www.buildbase.app/?utm_source=partner-site&utm_medium=mark
What reaches us
Sending a param and us acting on it are two different things. On arrival we read an allowlist and ignore everything else:
| Param | What it says |
|---|---|
ref | Who sent the visitor, from a badge |
via | The affiliate partner who sent them |
utm_source, utm_medium, utm_campaign, utm_id, utm_content, utm_term, and the GA4 additions | Which piece of marketing it was |
gclid, gbraid, wbraid, fbclid, msclkid, li_fat_id, ttclid, twclid, rdt_cid and the others | The ad network's click id |
Your own params still reach your analytics through the URL; they are simply not something we interpret.
Nothing about this runs on your page. The badge is an image tag: no JavaScript, no cookie, no tracking pixel. The referral code travels on the link only, never on the image URL, which is what keeps the image the same cached file for everyone.
Version
refCode and params were added in 0.0.59. Earlier versions accept variant, theme, size, alt, className and link only, and silently drop anything else.
coerceBadgeRef needs 0.0.60. It was documented in the 0.0.59 notes but not actually exported from /react in that release, so the import above does not resolve on 0.0.59 and there is no workaround short of upgrading.