Shopify Hydrogen and Shopify headless
This guide covers Shopify Hydrogen and React based Shopify headless storefronts.
This integration should take around 30 minutes to complete.
Install
- Install Seeka's Shopify Pixel by following the help article.
- Install the browser SDK NPM package.
- Install Seeka's React NPM package with one of the below commands.
# NPM
npm install --save @seeka-labs/converge-react@latest
# Yarn classic (v1)
yarn add @seeka-labs/converge-react@latest
Configure
In your app/entry.client.(jsx|tsx)
file, wrap your app with the SeekaProvider
, ensuring to replace (public key)
, (organisation ID)
and (instance ID)
in the example with values from the Seeka app.
import { RemixBrowser } from '@remix-run/react';
import { startTransition, StrictMode } from 'react';
import { hydrateRoot } from 'react-dom/client';
+import { SeekaProvider } from '@seeka-labs/converge-react';
+const seekaOrgId = '(organisation ID)';
+const seekaPublicKey = '(public key)';
+const seekaInstanceId = '(instance ID)';
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
+ <SeekaProvider org={seekaOrgId} publicKey={seekaPublicKey} id={seekaInstanceId}>
+ <RemixBrowser />
+ </SeekaProvider>
</StrictMode>,
);
});
Setup Content Security Policy
The below example covers Seeka, Facebook/Meta and Google Analytics 4 platforms. You may need to add additional domains to your content security policy based on your marketing/plugin stack.
For more information on required Content Security Policies, see the help center.
In your app/entry.server.(jsx|tsx)
file, add the below highlighted lines to the handleRequest
function to your content security policy.
...
export default async function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
const { nonce, header, NonceProvider } = createContentSecurityPolicy(
+ {
+ connectSrc: [
"*.seeka.services", "www.google-analytics.com"
+ ],
+ defaultSrc: [
+ "'self'", "connect.facebook.net", "www.googletagmanager.com", "'unsafe-inline'", "www.facebook.com", "*.seeka.services"
+ ]
+ }
);
...
}
Event tracking
Track page views
In your app/root.(jsx|tsx)
file, add the below highlighted lines to track the ViewPage
event.
If you have already followed the Shopify docs to raise a page view for Shopify Analytics, you can skip the below code and simply call the
converge.track.viewPage()
after yoursendShopifyAnalytics()
call.
+import { useLocation } from '@remix-run/react';
+import { useSeekaConverge } from '@seeka-labs/converge-react';
+import { useRef, useEffect } from 'react';
...
export default function App() {
const nonce = useNonce();
const data = useLoaderData<typeof loader>();
+ const converge = useSeekaConverge();
+ const location = useLocation();
+ const lastLocationKey = useRef('');
+ useEffect(() => {
+ if (lastLocationKey.current === location.key) return;
+ lastLocationKey.current = location.key;
+
+ converge.track.viewPage();
+ }, [location]);
...
}
...
Track add to cart and product views
In your app/routes/products.$handle.(jsx|tsx)
file, add the below highlighted lines to track AddToCart
and ViewProduct
events.
+import { useSeekaConverge } from '@seeka-labs/converge-react';
+import { useRef, useEffect } from 'react';
...
function ProductForm({
product,
selectedVariant,
variants,
}: {
product: ProductFragment;
selectedVariant: ProductFragment['selectedVariant'];
variants: Array<ProductVariantFragment>;
}) {
+ const converge = useSeekaConverge();
+ const ref = useRef('');
+
+ useEffect(() => {
+ if (ref.current === product.id) return;
+ ref.current = product.id
+ converge.track.viewProduct({
+ productName: product.title,
+ brandName: product.vendor,
+ productIdentifier: product.id?.split('/').slice(-1), // Convert Shopify Graph ID to Shopify variant ID for matching with ads platforms
+ unitPrice: selectedVariant?.price.amount,
+ currencyCode: selectedVariant?.price.currencyCode
+ });
+ }, [product.id])
return (
<div className="product-form">
<VariantSelector
handle={product.handle}
options={product.options}
variants={variants}
>
{({ option }) => <ProductOptions key={option.name} option={option} />}
</VariantSelector>
<br />
<AddToCartButton
disabled={!selectedVariant || !selectedVariant.availableForSale}
onClick={() => {
window.location.href = window.location.href + '#cart-aside';
+ converge.track.addToCart({
+ productName: product.title,
+ productIdentifier: product.id?.split('/').slice(-1), // Convert Shopify Graph ID to Shopify variant ID for matching with ads platforms
+ brandName: product.vendor,
+ unitPrice: selectedVariant?.price.amount,
+ currencyCode: selectedVariant?.price.currencyCode,
+ quantity: 1,
+ })
}}
lines={
selectedVariant
? [
{
merchandiseId: selectedVariant.id,
quantity: 1,
},
]
: []
}
>
{selectedVariant?.availableForSale ? 'Add to cart' : 'Sold out'}
</AddToCartButton>
</div>
);
}
...
Track checkout events
If your store redirects the user to a Shopify checkout page, the below events will be tracked automatically.
Order
AddPaymentMethod
InitiateCheckout
- Custom events that track how far the user has made it through the checkout process.
If you are using a custom checkout embedded in your storefront, you will need to fire these events manually.
Track additional events and identities
Automatic tracking of KeywordSearch
events is enabled by the setting of the keywordSearchQueryParamName
in the getSeekaConfig()
function setup in the first step.
For more information on how to track other events and identities manually via code, see the React docs.
Configuring regional consent (optional)
In your app/lib/seeka.(js|ts)
file, append the below highlighted lines to the getSeekaConfig()
function to configure regional consent to support Google's consent mode v2. Below is example configuration for Australia, United States and California - your configuration may vary based on your requirements.
If you are using an existing consent management platform you should not configure regional consent via Seeka as your CMP will handle this.
+import { RegionalConsentGrantOption } from "@seeka-labs/converge"
export const getSeekaConfig = () => {
const config = new ConvergeSdkConfiguration('(public key)',
'(organisation ID)', {
defaults: { currencyCode: "AUD" },
analytics: {
autoCollection: {
keywordSearchQueryParamName: 'q',
activityNames: [TrackingActivityNames.KeywordSearch]
}
},
+ processing: {
+ consent: {
+ disableConsentManagement: false,
+ regionalConsent: [
+ {
+ configuration: {
+ adStorage: RegionalConsentGrantOption.Granted,
+ adUserData: RegionalConsentGrantOption.Granted,
+ adPersonalisation: RegionalConsentGrantOption.Granted,
+ functionalityStorage: RegionalConsentGrantOption.Granted,
+ personalisationStorage: RegionalConsentGrantOption.Granted,
+ securityStorage: RegionalConsentGrantOption.Granted,
+ analyticsStorage: RegionalConsentGrantOption.Granted,
+ },
+ },
+ {
+ countryCode: 'AU',
+ configuration: {
+ adStorage: RegionalConsentGrantOption.Granted,
+ adUserData: RegionalConsentGrantOption.Granted,
+ adPersonalisation: RegionalConsentGrantOption.Granted,
+ functionalityStorage: RegionalConsentGrantOption.Granted,
+ personalisationStorage: RegionalConsentGrantOption.Granted,
+ securityStorage: RegionalConsentGrantOption.Granted,
+ analyticsStorage: RegionalConsentGrantOption.Granted,
+ },
+ },
+ {
+ countryCode: 'US',
+ configuration: {
+ adStorage: RegionalConsentGrantOption.Granted,
+ adUserData: RegionalConsentGrantOption.Granted,
+ adPersonalisation: RegionalConsentGrantOption.Granted,
+ functionalityStorage: RegionalConsentGrantOption.Granted,
+ personalisationStorage: RegionalConsentGrantOption.Granted,
+ securityStorage: RegionalConsentGrantOption.Granted,
+ analyticsStorage: RegionalConsentGrantOption.Granted,
+ },
+ },
+ {
+ countryCode: 'US-CA',
+ configuration: {
+ adStorage: RegionalConsentGrantOption.Denied,
+ adUserData: RegionalConsentGrantOption.Denied,
+ adPersonalisation: RegionalConsentGrantOption.Denied,
+ functionalityStorage: RegionalConsentGrantOption.Denied,
+ personalisationStorage: RegionalConsentGrantOption.Denied,
+ securityStorage: RegionalConsentGrantOption.Denied,
+ analyticsStorage: RegionalConsentGrantOption.Denied,
+ },
+ },
+ ],
+ },
+ },
},
undefined, undefined, undefined, undefined,
'(scope ID)',
'(scope description)'
);
config.plugins = [
new FacebookPixelConvergeSdkPlugin({ pixelId: "(pixel ID)" }),
new SeekaConvergeSdkPlugin(),
new GoogleAnalytics4ConvergeSdkPlugin({ measurementId: "(measurement ID)" }),
];
return config;
}
Shopify Analytics
Shopify Analytics is the way your storefront can integrate with Shopify's analytics platform, allowing your Shopify dashboard to show live data and reporting metrics from your headless storefront.
Seeka does not depend on Shopify Analytics, however it is important that Shopify Analytics is installed on your store to enable core functionality of Shopify.
See the Shopify Analytics documentation for more information.