Skip to content

Shopify behind your storefront

The common shape: you render your own storefront in Astro and query Shopify’s Storefront API for the catalogue. Geoffy sits alongside, reading the products Shopify already synced to it.

What makes this easy: the handle Shopify gives you is the handle Geoffy wants. You already have it in scope, so there is nothing to map and nothing to store.

src/pages/products/[handle].astro
---
import Layout from "@/layouts/Layout.astro";
import { getGeoffyProductMarkup } from "@geoffy/headless/astro";
import { getProductByHandle } from "@/lib/shopify";
export const prerender = false;
const { handle } = Astro.params;
const product = await getProductByHandle(handle);
if (!product) return Astro.redirect("/404");
// One canonical, built once, used by the <link> and by Geoffy.
const canonical = `https://yourdomain.com/products/${handle}`;
const geoffy = await getGeoffyProductMarkup(
{ siteKey: import.meta.env.GEOFFY_SITE_KEY },
handle,
{ canonicalUrl: canonical },
);
---
<Layout title={product.title} description={product.description}>
<link rel="canonical" href={canonical} slot="head" />
{geoffy && <Fragment set:html={geoffy.jsonLdScript} slot="head" />}
<article>
<ProductGallery images={product.images} />
<h1>{product.title}</h1>
<BuyBox variantId={product.variants[0].id} price={product.priceRange} />
<Fragment set:html={product.descriptionHtml} />
{geoffy && <div data-geoffy-widget set:html={geoffy.widgetHtml} />}
</article>
</Layout>
  1. Shopify is the source of product facts. Title, price, availability, variants: your storefront reads them from the Storefront API, as it already does.

  2. Geoffy is a supplement, not a replacement. Its structured data deliberately carries no offers, no price and no availability: your page already has a product node with those, and two prices on one page with no rule for which wins is worse than one. Geoffy adds what the commerce node lacks: positive notes, audience, attributes, certifications.

  3. You do not sync anything. Shopify already pushed your catalogue to Geoffy when you connected the store.

The example sets prerender = false because a Shopify-backed catalogue changes (prices and stock most of all), and a prerendered product page freezes them until your next build.

If your catalogue is genuinely static, you can prerender the product page and still serve the namespace on demand: prerender is per route. But read how updates arrive first, because a fully static site has no accelerated path for Geoffy content either.

Everything else (the root files, the namespace, robots.txt, the IndexNow key) is identical whether Shopify is behind you or not. Follow the quickstart.