Behio Storefront SDK
React Hooks

Analytics & Scripts

Inject merchant-configured analytics and custom head/body scripts, consent-gated

Merchants configure analytics and custom scripts in the Behio admin (E-shop → SEO a scripty): Google Analytics 4, Google Tag Manager, Meta Pixel, Google site verification, or arbitrary RAW HTML placed in the document head, at the start of body, or at the end of body. The SDK delivers them to the storefront and injects them for you, gating analytics entries behind the visitor's cookie consent.

StorefrontScripts

Mount it once in your root layout, inside BehioProvider. Because the layout is usually a server component, wrap it in a tiny "use client" file (the same pattern as a consent banner).

// components/StorefrontScripts.tsx
"use client";
import type {ComponentProps} from "react";
import { StorefrontScripts as Base } from "@behio/storefront-sdk/react";

export function StorefrontScripts({initialScripts}: Pick<ComponentProps<typeof Base>, "initialScripts">) {
  return <Base initialScripts={initialScripts} />;
}
// app/layout.tsx
import { StorefrontScripts } from "@/components/StorefrontScripts";

// ...inside <BehioProvider> ...
const {data} = await behio.getShopScripts(); // request-scoped server client
<StorefrontScripts initialScripts={data?.scripts ?? []} />

Entries flagged consentRequired are injected only after the visitor grants the relevant consent: Meta Pixel uses marketing, while GA4, GTM and consent-gated custom entries use analytics. Entries that do not require consent are injected on mount. Revoking consent after a script has executed reloads the page to stop its installed listeners. The visitor id is read from the behio_visitor_id localStorage key (the same one the consent banner uses), or you can pass it explicitly:

<StorefrontScripts visitorId={visitorId} />

Typed entries (GA4, GTM, Meta Pixel, verification) are expanded into their canonical snippet and placed where each vendor expects; RAW entries are injected at the chosen placement, including the beginning of body for BODY_START. Only the merchant's trusted script settings belong here, never product descriptions or customer input.

For search verification in the first HTML, render non-consent GOOGLE_VERIFICATION entries through server metadata and omit them from the client injector. Legacy GA4, Pixel and verification settings are exposed by the same endpoint when there is no explicit entry of that type. An explicitly disabled entry overrides its legacy setting; never reconstruct disabled scripts in the template.

useShopScripts

For custom rendering, fetch the raw list yourself:

import { useShopScripts } from "@behio/storefront-sdk/react";

const { data } = useShopScripts();
// data?.scripts: { id, type, placement, value, consentRequired }[]

Or imperatively on the client instance:

const { data } = await behio.getShopScripts();

type is "GA4" | "GTM" | "META_PIXEL" | "GOOGLE_VERIFICATION" | "RAW", placement is "HEAD" | "BODY_START" | "BODY_END". Only enabled entries are returned.

Search Console & Bing verification

Site verification needs no code changes. The merchant adds a GOOGLE_VERIFICATION script in the Behio admin (E-shop → SEO a scripty) with the content value from Google Search Console's HTML-tag method; render the value through server metadata for first-HTML verification. The client injector also supports the tag, but is not a substitute for server metadata. Only entries that explicitly do not require consent belong in that metadata. After verifying, submit https://yourdomain.tld/sitemap.xml in Search Console. The template's sitemap carries real per-record lastmod from product/page updatedAt.

Also register the shop in Bing Webmaster Tools: the Bing index feeds AI search (ChatGPT search, Microsoft Copilot). Use its one-click Import from Google Search Console, or add the msvalidate.01 meta tag as a RAW script with HEAD placement.

Homepage SEO

The same admin screen sets the per-language homepage SEO. Feed it into your homepage metadata so it reaches the page <head>:

export async function generateMetadata() {
  const { data: seo } = await behio.getShopSeo(); // optional locale arg
  return {
    title: seo?.title ?? shop.name,
    description: seo?.description ?? undefined,
    keywords: seo?.keywords ?? undefined,
    openGraph: {
      title: seo?.ogTitle ?? seo?.title ?? shop.name,
      description: seo?.ogDescription ?? seo?.description ?? undefined,
      images: seo?.ogImage ? [{ url: seo.ogImage }] : undefined,
    },
  };
}

On this page