Cloudflare Pages — Hosting Guide for Jennie’s Dating Scorecard
This app is a static front‑end (HTML/CSS/JS) that calls a Google Apps Script backend. Cloudflare Pages is perfect to host the static files over HTTPS (needed for PWA).
What you need
- A Cloudflare account (free is fine).
- Your app folder with:
index.html
,app.js
,manifest.webmanifest
,sw.js
,icons/
. - Your Apps Script Web App URL pasted into
app.js
asGAS_ENDPOINT
.
Quick Deploy (Upload Assets)
- Log in to Cloudflare → Pages → Create a project → Upload assets.
- Drag‑drop your folder (the one that contains
index.html
at the root). - Project name: something like dating-scorecard.
- Build settings:
- Framework preset: None
- Build command: None
- Output directory:
/
(root whereindex.html
lives)
- Click Save and Deploy. In ~30s you’ll get a
*.pages.dev
URL.
Hash routes like
#scorecard
require no special SPA rewrites, so you’re good.
Custom Domain (optional)
- In Pages → your project → Settings → Domains → Set up a custom domain.
- Enter your domain (or subdomain) and follow the wizard. Cloudflare will set a CNAME and provision SSL automatically.
PWA Checklist on Pages
- Site is on HTTPS (Pages provides it).
manifest.webmanifest
resolves (open it directly to verify).sw.js
is served at the site root and registers without console errors.- After a minute of use, you should see Install option (button or browser menu).
Caching & Updates
- Cloudflare Pages caches aggressively; the service worker also caches the app shell.
- If you push an update and don’t see it:
- Hard refresh (Cmd/Ctrl+Shift+R).
- In DevTools → Application → Service Workers → Update / Unregister → reload.
- Pages keeps previous deploys; you can Rollback from the dashboard.
Hiding the Apps Script URL (optional)
By default, GAS_ENDPOINT
is visible in app.js
. To hide it and add a shared secret, place a tiny Cloudflare Worker in front of Apps Script:
// worker.js (deploy as a Worker or Pages Function)
export default {
async fetch(req, env) {
const url = new URL(req.url);
if (url.pathname.startsWith('/api/')) {
const upstream = new URL(env.APPS_SCRIPT_URL);
upstream.search = url.search; // keep ?action=...&id=...
const init = {
method: req.method,
headers: {'content-type': 'application/json'},
};
if (req.method !== 'GET') {
const body = await req.text();
// inject a secret into JSON if you like
init.body = body && body.length ? body : null;
}
const r = await fetch(upstream, init);
return new Response(r.body, {status:r.status, headers:r.headers});
}
return new Response('Not found', {status:404});
}
}
- Bind a secret APPS_SCRIPT_URL in Worker settings.
- In
app.js
, setGAS_ENDPOINT = location.origin + '/api'
. - Route
/api*
to the worker in Workers → Triggers (or use Pages Functions in the same repo).
This keeps the Apps Script URL private and allows you to add auth later.
Troubleshooting
- “Check Connection” fails: Ensure Apps Script deploy is Web app → Anyone. If using Worker proxy, check the bound secret and logs.
- PWA not installable: Make sure
manifest.webmanifest
and icons are present, and that the page was visited over HTTPS for a bit (the prompt can be finicky). - Images not saving: Check Drive quota, App Script logs (
View → Executions
), and that yourDRIVE_FOLDER_ID
(if set) is valid. - 404s on deep links: You’re using hash routes (
#scorecard
), so should be fine. If you ever switch to path routes, add a SPA rewrite toindex.html
in Pages settings.