Index: src/services/PaidPatreonService.js
===================================================================
--- src/services/PaidPatreonService.js	(revision 6cbd0142768e2cd623437742cd6c08cc33fda44f)
+++ src/services/PaidPatreonService.js	(revision c3d12a6f5721ed2faee19362b8d7e0caeea854d5)
@@ -21,4 +21,5 @@
     tokenExp: row.token_exp || 0,
     defaultMinCents: row.default_min_cents || 0,
+    patreonUrl: row.patreon_url || null,
   };
 }
@@ -36,5 +37,12 @@
     tokenExp: c.tokenExp || 0,
     hasSecret: !!c.clientSecret,
+    patreonUrl: c.patreonUrl || null,
   };
+}
+
+// The owner's public Patreon page, for the "Word supporter" link. Null when unset.
+export function patreonUrl(siteId) {
+  const c = getOwnerConfig(siteId);
+  return c && c.patreonUrl ? c.patreonUrl : null;
 }
 
@@ -52,13 +60,15 @@
     tokenExp: patch.tokenExp ?? cur.tokenExp ?? 0,
     defaultMinCents: patch.defaultMinCents ?? cur.defaultMinCents ?? 0,
+    // undefined = keep (e.g. token refresh doesn't touch it); null/'' = clear.
+    patreonUrl: patch.patreonUrl !== undefined ? (patch.patreonUrl || null) : (cur.patreonUrl ?? null),
   };
   db.prepare(`INSERT INTO paid_patreon
-      (site_id, client_id, client_secret_enc, campaign_id, access_token_enc, refresh_token_enc, token_exp, default_min_cents, updated_at)
-      VALUES (?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP)
+      (site_id, client_id, client_secret_enc, campaign_id, access_token_enc, refresh_token_enc, token_exp, default_min_cents, patreon_url, updated_at)
+      VALUES (?,?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP)
     ON CONFLICT(site_id) DO UPDATE SET
       client_id=excluded.client_id, client_secret_enc=excluded.client_secret_enc,
       campaign_id=excluded.campaign_id, access_token_enc=excluded.access_token_enc,
       refresh_token_enc=excluded.refresh_token_enc, token_exp=excluded.token_exp,
-      default_min_cents=excluded.default_min_cents, updated_at=CURRENT_TIMESTAMP`)
+      default_min_cents=excluded.default_min_cents, patreon_url=excluded.patreon_url, updated_at=CURRENT_TIMESTAMP`)
     .run(
       siteId,
@@ -70,4 +80,5 @@
       merged.tokenExp || 0,
       Math.max(0, parseInt(merged.defaultMinCents, 10) || 0),
+      merged.patreonUrl || null,
     );
 }
@@ -171,5 +182,5 @@
 export default {
   getOwnerConfig, ownerStatus, saveOwnerConfig, disconnect,
-  defaultMinCents, needsRefresh, refreshCreatorToken, creatorAccessToken,
+  defaultMinCents, patreonUrl, needsRefresh, refreshCreatorToken, creatorAccessToken,
   pickCampaignMembership, verifyPatron,
 };
