Integration
Next.js
App Router and Pages Router, with client-only mounting
Next 15 or later, for React 19. Both routers work; the App Router needs one extra hop because a Client Component still prerenders on the server.
npm install @superbridge/widgetApp Router
The stylesheet
Import it in the root layout, above your own global CSS. Next emits stylesheets in import order, so this is what puts the widget's variables behind yours.
// app/layout.tsx
import "@superbridge/widget/styles.css";
import "./globals.css";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}The widget
'use client' is not enough on its own — client components are still prerendered on the server, and the widget reads browser APIs while it sets up. Load it with next/dynamic and ssr: false.
That call has to happen inside a Client Component; ssr: false from a Server Component is an error in Next 14+. So it's two small files:
// app/bridge/bridge-widget.tsx
"use client";
import { Widget } from "@superbridge/widget";
export default function BridgeWidget() {
return (
<Widget
localDevelopmentApiKey={process.env.NEXT_PUBLIC_WIDGET_DEV_KEY}
/>
);
}// app/bridge/bridge.tsx
"use client";
import dynamic from "next/dynamic";
export const Bridge = dynamic(() => import("./bridge-widget"), {
ssr: false,
loading: () => <div className="h-[560px] w-full max-w-[540px] mx-auto" />,
});The loading placeholder is worth setting to roughly the widget's size — without it the page reflows when the widget mounts.
Your page stays a Server Component:
// app/bridge/page.tsx
import { Bridge } from "./bridge";
export default function Page() {
return (
<main className="mx-auto max-w-lg py-24">
<Bridge />
</main>
);
}Pages Router
Same idea, one less file: dynamic() is already being called from a client-side module, so it can live in the page.
// pages/_app.tsx
import "@superbridge/widget/styles.css";
import "../styles/globals.css";
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />;
}// pages/bridge.tsx
import dynamic from "next/dynamic";
const Widget = dynamic(
() => import("@superbridge/widget").then((m) => m.Widget),
{ ssr: false },
);
export default function BridgePage() {
return (
<main className="mx-auto max-w-lg py-24">
<Widget localDevelopmentApiKey={process.env.NEXT_PUBLIC_WIDGET_DEV_KEY} />
</main>
);
}Environment variables
The dev API key has to reach the browser, so it needs the NEXT_PUBLIC_ prefix — which also means it lands in your client bundle. Keep it out of production builds by only defining it in .env.development, or gate it:
<Widget
localDevelopmentApiKey={
process.env.NODE_ENV === "development"
? process.env.NEXT_PUBLIC_WIDGET_DEV_KEY
: undefined
}
/>In production the widget resolves your Rollie from the domain, so no key is needed. See Local development.
If your app has its own wagmi and the widget behaves as though it isn't there, you have two copies of wagmi installed. Pin one with npm overrides or pnpm pnpm.overrides — see Wallets.
Checklist
- Next 15+, React 19
- Widget stylesheet imported above your own in
app/layout.tsxorpages/_app.tsx next/dynamicwithssr: false, called from a Client Component- Dev key prefixed
NEXT_PUBLIC_and kept out of production