Story Desk on Cloudflare Pages (SSG)¶
Story Desk is built as a static site (SSG) with output: 'export'. The build produces an out/ directory that Cloudflare Pages serves. There is no Node server; rewrites and API routes are not used at build or runtime.
1. Cloudflare Pages – project and build¶
- In Cloudflare Dashboard go to Workers & Pages → Create → Pages → Connect to Git.
- Select your repo and branch (e.g.
main). - Build configuration:
- Framework preset: Next.js (Static HTML Export).
- Build command:
npm run build:cloudflare - Build output directory:
out - Root directory: (leave empty unless the app lives in a subdirectory).
- Environment variables (see section 2). Add them in Settings → Environment variables for Production (and optionally Preview).
- Save and deploy. Every push to the connected branch (and PR previews) will build and deploy. No per-branch env setup is needed;
scripts/set-build-env.shuses Cloudflare’sCF_PAGES_BRANCHto setdeploy_envanddeploy_branchfor New Relic.
Optional: Run npm run setup once locally (or in CI) so scripts/set-build-env.sh is executable. If the script is not executable in the repo, you can set the build command to chmod +x scripts/set-build-env.sh && npm run build:cloudflare.
2. Environment variables (Cloudflare)¶
Set these in Pages → your project → Settings → Environment variables. Use Production for the main branch and Preview for PR/preview deployments if you want the same vars there.
| Variable | Required | Description |
|---|---|---|
NEXT_PUBLIC_POSTHOG_KEY |
If using PostHog | PostHog project API key. |
NEXT_PUBLIC_POSTHOG_API_HOST |
For static (Cloudflare) | Set to https://us.i.posthog.com (no /ingest proxy on static hosting). Omit only if you use a Cloudflare Worker to proxy /ingest. |
NEXT_PUBLIC_NEW_RELIC_LICENSE_KEY |
If using New Relic | From New Relic Browser app → Copy/Paste snippet. |
NEXT_PUBLIC_NEW_RELIC_APPLICATION_ID |
If using New Relic | From the same snippet. |
Optional – source maps for this deployment: To get unminified stack traces in New Relic for the app built and deployed by Cloudflare, set these only for the production branch (e.g. Production environment in Cloudflare): UPLOAD_SOURCEMAPS=1, NR_APPLICATION_ID, NR_API_KEY, BASE_URL (your production origin, e.g. https://your-project.pages.dev or custom domain). The build will then generate source maps, the postbuild script will upload them to New Relic and remove them locally (so they are not deployed). If you do not set these, the upload script will report "No .js.map files" and only a separate build (e.g. GitHub Actions) can upload maps—and that only matches the deployed JS if the build output is the same.
3. New Relic (Browser app and attributes)¶
- In New Relic: Add data → Browser monitoring → create a Browser app (e.g. “Story Desk”).
- Copy the License key and Application ID from the Copy/Paste JavaScript snippet and set them in Cloudflare as above.
- All deployments (main, staging, previews) report to this one app. Each event is tagged with:
deploy_env:production(main) |staging|previewdeploy_branch: e.g.main,staging,feat/xyz- In New Relic, filter or group errors by these attributes to separate production, staging, and preview branches.
See docs/newrelic.md for how deploy env/branch and source maps work.
4. PostHog (static / no proxy)¶
With static export there is no Next.js server, so the previous /ingest rewrite is not available. Use PostHog’s host directly:
- Set
NEXT_PUBLIC_POSTHOG_API_HOST=https://us.i.posthog.comin Cloudflare (for both Production and Preview if you use PostHog there). - Redeploy after adding or changing this variable—
NEXT_PUBLIC_*values are baked in at build time.
Analytics and error tracking will then go to PostHog without a same-origin proxy. If you later add a Cloudflare Worker that proxies /ingest to PostHog, you can switch back to NEXT_PUBLIC_POSTHOG_API_HOST=/ingest (or leave it unset).
If you see requests to https://your-site.pages.dev/ingest/ (404 or failing): the build was done without NEXT_PUBLIC_POSTHOG_API_HOST set. Add it in Cloudflare → your project → Settings → Environment variables, then trigger a new deploy (e.g. Deployments → Retry deployment or push a new commit).
5. Source maps (production)¶
The workflow .github/workflows/upload-sourcemaps.yml runs on push to main, builds with source maps, and uploads them to New Relic (postbuild script). Set these repository secrets in GitHub:
| Variable / Secret | Value |
|---|---|
NR_APPLICATION_ID |
New Relic Browser app ID (same as NEXT_PUBLIC_NEW_RELIC_APPLICATION_ID in Cloudflare). |
NR_API_KEY |
User API key from New Relic API keys (create a "User" key). Not the license key from the Copy/Paste snippet—upload will return Unauthorized if you use the license key. |
BASE_URL |
Production origin (e.g. https://your-project.pages.dev or custom domain). |
Staging and previews (Cloudflare only) do not run this; their errors have minified stacks but correct deploy_env / deploy_branch.
If upload fails with "Unauthorized": Use a User API key from New Relic (one.newrelic.com → Admin → API keys → Create a key → User key). Do not use the license key from the Browser app snippet.
If upload fails with "Bad Request": Ensure BASE_URL is a full origin with scheme, e.g. https://story-desk-fe.pages.dev. If you set it without https://, the script will add it automatically; redeploy if you still see Bad Request.
6. Checklist¶
- [ ] Cloudflare Pages project created and connected to Git.
- [ ] Build command:
npm run build:cloudflare, output directory:out. - [ ] Env vars set:
NEXT_PUBLIC_POSTHOG_KEY,NEXT_PUBLIC_POSTHOG_API_HOST=https://us.i.posthog.com,NEXT_PUBLIC_NEW_RELIC_LICENSE_KEY,NEXT_PUBLIC_NEW_RELIC_APPLICATION_ID(if using PostHog and New Relic). - [ ] New Relic Browser app created and IDs copied to Cloudflare.
- [ ] GitHub repo secrets set:
NR_APPLICATION_ID,NR_API_KEY,BASE_URL(for the upload-sourcemaps workflow).
After the first successful deploy, open your Pages URL and confirm the app loads; then check New Relic and PostHog for data.