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,
},
};
}