Developer Docs / Web React SDK / Sponsorships
Web React Sponsorship Rendering
Render the current sponsor or public availability state with GrowthCat's built-in banner, a custom React design, or the headless TypeScript API.
React exports
GrowthCatSponsorBanner and useSponsor.
Headless
Load stable render data and track qualified impressions and clicks.
Disclosure
Every live sponsor design must clearly say Sponsored.
1. Overview
Configure a sponsor placement in the GrowthCat dashboard, then use its stable slotKey on the site. The SDK returns only SDK-safe public rendering data—not private sponsor email, receipt, or publisher information.
Qualified sponsor impressions
2. Install And Initialize
npm install @growthcat/web react react-dom
# or
yarn add @growthcat/web react react-domimport { GrowthCat } from "@growthcat/web";
GrowthCat.initialize({
apiKey: process.env.NEXT_PUBLIC_GROWTHCAT_KEY!,
workspace: "live",
logsEnabled: process.env.NODE_ENV !== "production",
measurementMode: "essential",
});Install the GrowthCat integration skill
The WebSDK repository includes an agent skill that inspects your app, checks the installed SDK types, and adds referrals, attribution, ads, sponsorships, or feedback using your existing architecture.
npx skills add . --skill growthcat-web-integrationRun this from a local GrowthCatSDK-Web checkout. For a remote install, replace the dot with the repository Git URL. Then tell your coding agent which capability and placement you want.
Use $growthcat-web-integration to add a feedback board to my settings page.3. Built-in Sponsor Banner
The component renders a live sponsor or an optional public booking prompt, opens the correct destination, and tracks qualified events automatically.
import { GrowthCat } from "@growthcat/web";
import { GrowthCatSponsorBanner } from "@growthcat/web/react";
export function HomePage() {
return (
<GrowthCatSponsorBanner
slotKey="home_sponsor"
sessionId={GrowthCat.makeSessionId()}
showAvailability
onTap={() => console.log("Sponsor opened")}
/>
);
}Set showAvailability to false when available slots should render nothing instead of a booking prompt.
4. Custom Sponsor UI With useSponsor
useSponsor() keeps one stable creative instance ID for the fetched sponsor. Reuse it for the impression and click; call reload only when you intentionally want a new presentation.
import { useEffect, useRef } from "react";
import { useSponsor } from "@growthcat/web/react";
export function CustomSponsor({ slotKey }: { slotKey: string }) {
const ref = useRef<HTMLDivElement>(null);
const { sponsor, trackImpression, trackClick } = useSponsor({ slotKey });
useEffect(() => {
if (sponsor?.status !== "live" || !ref.current) return;
let timer: ReturnType<typeof setTimeout> | undefined;
const observer = new IntersectionObserver(([entry]) => {
clearTimeout(timer);
if (entry.intersectionRatio >= 0.5 && document.visibilityState === "visible") {
timer = setTimeout(() => {
void trackImpression(entry.intersectionRatio, 1000);
}, 1000);
}
}, { threshold: 0.5 });
observer.observe(ref.current);
return () => { clearTimeout(timer); observer.disconnect(); };
}, [sponsor, trackImpression]);
if (sponsor?.status !== "live" || !sponsor.creative) return null;
const creative = sponsor.creative;
return (
<div ref={ref}>
<small>Sponsored</small>
{creative.logoUrl && <img src={creative.logoUrl} alt="" />}
<strong>{creative.headline ?? creative.sponsorName}</strong>
{creative.body && <p>{creative.body}</p>}
<button onClick={async () => {
await trackClick();
if (creative.clickUrl) {
window.open(creative.clickUrl, "_blank", "noopener,noreferrer");
}
}}>
{creative.ctaText ?? "Learn more"}
</button>
</div>
);
}5. Headless Sponsor API
Use the headless API outside React or when another framework owns rendering. Keep the returned object intact so its creative instance ID remains stable.
const sponsor = await GrowthCat.shared.loadSponsorData("home_sponsor");
if (sponsor.status === "live" && sponsor.creative) {
renderSponsor(sponsor.creative);
await GrowthCat.shared.trackSponsorImpression(sponsor, {
visibleFraction: 0.8,
visibleDurationMs: 1100,
});
await GrowthCat.shared.trackSponsorClick(sponsor);
}Use sponsor(slotKey) only when you need the raw slot response and do not need a stable render identity.
6. Sponsor Response States
| Status | Recommended UI |
|---|---|
| "live" | Render creative and track qualified events. |
| "available" | Optionally show priceUsd, bookingUrl, and nextAvailablePeriods. |
| "empty" | Render nothing because the availability placeholder is disabled. |
7. API Reference
// Headless client
client.sponsor(slotKey): Promise<SponsorSlotContent>
client.loadSponsorData(slotKey): Promise<GrowthCatSponsorData>
client.trackSponsorImpression(data, options): Promise<boolean>
client.trackSponsorClick(data, options?): Promise<boolean>
client.trackSponsorEvent(slotKey, "impression" | "click", options?): Promise<void>
client.flushSponsorEvents(): Promise<void>
// React
useSponsor(options): UseSponsorResult
<GrowthCatSponsorBanner
slotKey="home_sponsor"
sessionId={sessionId}
showAvailability
onTap={handleTap}
/>