Wiring guide
Wire a site in five steps
About fifteen minutes for a Next.js or Astro site, once per site.
Wire a property in five steps
1. Add the site in galley and copy its slug
Open galley, choose Sites, then Add a site. Give it the name a visitor would recognise, the domain it lives on (painted.agency, with no https://) and its production URL. galley turns the name into a slug, such as painted-agency. Copy that slug: every other step uses it.
The domain matters more than it looks. galley's forms refuse a submission sent from any other origin, so a blank or wrong domain is the first thing to check when a form will not send.
2. Make an API key under Settings
In the site, open Settings, then API keys, then Create key. galley shows the key once, in the form gal_ followed by forty characters, and keeps only a fingerprint of it. Copy it straight into the next step. If you lose it, delete it and make another; the old one stops working the moment you do.
A key reads one site and nothing else. It cannot publish, delete or see another site, so a leaked key exposes only what that site already shows the public, plus its unpublished drafts.
3. Set the environment variables
For a Next.js property, add these to Vercel (Production and Preview) and to .env.local for local work:
vercel env add GALLEY_URL # https://<where galley runs>
vercel env add GALLEY_SITE # the slug from step 1
vercel env add GALLEY_KEY # the gal_ key from step 2
vercel env add GALLEY_REVALIDATE_SECRET # openssl rand -hex 32
vercel env add NEXT_PUBLIC_GALLEY_URL # same as GALLEY_URL
vercel env add NEXT_PUBLIC_GALLEY_SITE # same as GALLEY_SITE
For an Astro property, the same list with PUBLIC_ in place of NEXT_PUBLIC_, and no revalidate secret: a static site rebuilds instead. The full list with comments is in adapters/next/.env.example and adapters/astro/.env.example.
Only the two public values ever reach a browser. GALLEY_KEY stays on the server; if you ever see it in a NEXT_PUBLIC_ or PUBLIC_ name, that is a leak, and the fix is to delete the key in galley and make a new one.
4. Drop in the adapter files
The adapter is a set of ordinary files you copy into the property and then own. Start with the client package, which has no dependencies:
# from the property's root
mkdir -p vendor/galley && cp -r ~/github/galley/packages/client vendor/galley/client
npm install ./vendor/galley/client # or: pnpm add ./vendor/galley/client
Then, for Next.js, copy the adapter into the property's app/ tree:
cp -r ~/github/galley/adapters/next/lib/. lib/
cp -r ~/github/galley/adapters/next/components/. components/galley/
cp -r ~/github/galley/adapters/next/app/. app/
For Astro:
cp -r ~/github/galley/adapters/astro/src/. src/
Each adapter's README names every file and the one or two lines you may need to change. Two of them need a decision from you. A property that already has its own home page keeps it: in Astro a named page always wins over the catch-all, and in Next.js you delete app/page.tsx only when you want galley to own /. And a property with a Content-Security-Policy, which painted.agency has in next.config.mjs, needs galley's host added to script-src and connect-src, or the beacon and the forms are blocked in the browser with no error on the page.
5. Connect publishing, and add the beacon
Back in galley, open the site's Settings.
For a Next.js property, set Revalidate URL to https://<your domain>/api/galley/revalidate and Revalidate secret to the same value as GALLEY_REVALIDATE_SECRET. Every Publish now tells the site which paths changed, and the new version is live on the next request.
For a static Astro property, make a deploy hook in Vercel (Project, Settings, Git, Deploy Hooks, branch main) and paste its URL into Deploy hook URL. Every Publish now starts a rebuild, which takes as long as the site's normal build.
Then add the beacon, so galley's Analytics can count page views. In Next.js, put <GalleyBeacon /> inside <body> in app/layout.tsx. In Astro, put <GalleyBeacon /> inside <head> in your base layout. Both render one tag:
<script defer src="https://<galley>/g.js" data-site="<slug>"></script>
Deploy, then check the wiring from galley's repository:
GALLEY_URL=https://<galley> GALLEY_KEY=gal_... node scripts/smoke-api.mjs
Every line should read PASS. The site's Overview in galley shows the first page view within a minute of your first visit.
What each property gets
Pages. Every page you publish in galley is served at its path, built from fifteen section types (masthead, prose, split, figures, proof rows, display band, gallery, questions, pricing, testimonials, logo row, marquee, form, embed, collection). A property can draw any type with its own component and leave the rest to the plain renderer.
Posts. A journal at /blog and /blog/<slug>, newest first, twenty to a page, with tags, a cover picture and a scheduled publish time that the API respects.
Collections. Any list you define in galley, such as team members, projects or stockists, read with listEntries("team") in the order you dragged them into.
Forms. Every form you build under Inbox posts to galley from the visitor's browser. Each message lands in the Inbox, and in your email when the form has a notify address.
Redirects and navigation. The header and footer menus you arrange in galley arrive with getSite(), along with every redirect; the Next.js adapter follows a redirect before it shows a 404.
Preview. The editor's preview link opens the draft on the real site, in your browser only, for an hour. Visitors keep seeing the published page.
The beacon. One line counts views and visitors per path, per day, for the Analytics screen.
What galley never does
galley never puts a credential in a visitor's browser. The key is read on the server or at build time, and the two values the browser sees, galley's address and the site slug, open nothing.
The beacon never sets a cookie or stores anything on the visitor's device. A visitor is counted as a one-way hash of the connection, browser and date, salted and thrown away at midnight, so no one can be followed from one day to the next.
A property never writes to galley. The key reads; the forms endpoint accepts a message and nothing else. Every change to a site is made by a person signed in to galley, and the Activity ledger records who made it and when.
Wired
Check the Counts
Every line of the check should read PASS. If one does not, please tell us which, and thank you for the report.