Skip to content

Add the script to a Next.js shop

This guide is for the Next.js App Router. It covers the browser side: the script, consent and commerce calls from client components.

Add two next/script tags to app/layout.tsx:

app/layout.tsx
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Script id="quomerce-stub" strategy="beforeInteractive">
{`window.qm=window.qm||function(){(window.qm.q=window.qm.q||[]).push(arguments)};qm("init",{key:"pk_live_…",commerce:"manual"});`}
</Script>
<Script src="https://ingest-prod.quomerce.com/sdk/v0/qm.js" strategy="afterInteractive" />
</body>
</html>
);
}
  • The stub defines window.qm as a queue before any of your code runs. A call from a client component that renders before the script has loaded is kept, and run once it has. beforeInteractive only works in the root layout, which is where this belongs.
  • The script loads after the page is interactive and never blocks rendering.
  • One copy. Put this in the root layout only. A nested layout that renders it again would load the script twice.
  • The key can be inline, as above, or read from an environment variable such as NEXT_PUBLIC_QM_KEY. It is public either way.
  • commerce: "manual" means this shop sends its own commerce events, as in step 4. Leave it out to use auto mode: Quomerce then detects events from your GA4 dataLayer and ignores every qm.commerce call. See Commerce: auto or manual.

Page views need nothing more. App Router navigations change the URL through the History API, and the script counts each one as a page view. New deploys are recognised from the Next.js build ID.

Download the types file into your project:

Terminal window
curl -o types/qm.d.ts https://docs.quomerce.com/sdk/qm.d.ts

Now window.qm is typed everywhere: commands, commerce calls and their arguments. Typos and wrong shapes fail the build. See TypeScript types for details.

With the default consent mode (Required), the script stores nothing on the device and records no replay until it is told the visitor agreed. Pass the choice on every page load:

app/consent-bridge.tsx
"use client";
import { useEffect } from "react";
export function ConsentBridge() {
useEffect(() => {
// Cookiebot shown here; any consent tool with a callback works the same way.
const apply = () => {
const statistics = Boolean(window.Cookiebot?.consent?.statistics);
window.qm?.("consent", { analytics: statistics, replay: statistics });
};
window.addEventListener("CookiebotOnConsentReady", apply);
return () => window.removeEventListener("CookiebotOnConsentReady", apply);
}, []);
return null;
}
declare global {
interface Window {
Cookiebot?: { consent?: { statistics?: boolean } };
}
}

Render <ConsentBridge /> once, in the root layout. More in Consent.

In manual mode, call qm.commerce from client components when something happens:

app/p/[slug]/add-to-cart.tsx
"use client";
import { useEffect } from "react";
import type { Product } from "@/types/qm";
export function AddToCart({ product }: { product: Product }) {
useEffect(() => {
window.qm?.("commerce.productViewed", product);
}, [product]);
return (
<button
onClick={() => {
// …add to the cart, then:
window.qm?.("commerce.cartAdded", product, 1);
}}
>
Add to cart
</button>
);
}

Use the queued form, window.qm?.("commerce.cartAdded", …). It works before the script has loaded, and the ?. keeps server rendering safe. The full list of calls is in Manual mode.

  • Product pages are recognised from JSON-LD Product data. Render it on the server. It also fills the Products report with each product’s name, price and availability.

  • Pages whose URL says nothing, such as an order confirmation at /order/12345, should say what they are:

    useEffect(() => {
    window.qm?.("page", { type: "thank_you" });
    }, []);

    This matters for privacy too: checkout, thank-you and account pages are fully masked in replays. See Page types.

Open your shop, accept the consent banner, view a product, add it to the cart and start checkout. Then watch Install & setup. See Check that it works.