fix(self-host): show Web Vitals and Search Console on self-hosted installs - #1104
fix(self-host): show Web Vitals and Search Console on self-hosted installs#1104TimBroddin wants to merge 7 commits into
Conversation
self-host-vs-cloud.mdx documents Google Search Console as available on self-hosted deployments "(Requires Google OAuth env vars)", but the UI was gated behind NEXT_PUBLIC_CLOUD. Serve the availability signal from the existing public /api/config endpoint instead, derived from whether Google OAuth credentials are present on the backend. Sent as a boolean only — /api/config is unauthenticated. Delivering it at runtime rather than as a NEXT_PUBLIC_* build arg means self-hosters running the prebuilt client image (the documented Coolify setup) need no rebuild.
The Integrations tab and the dashboard Search Console card were hidden behind NEXT_PUBLIC_CLOUD, so self-hosters could never reach the connect flow even though every GSC route registers unconditionally on the server. Both now key off the gscEnabled flag from /api/config. The dashboard card stays gated rather than being un-gated outright because it renders a persistent ConnectPrompt when unconnected, which would 500 on deployments with no OAuth credentials.
self-host-vs-cloud.mdx lists Web Vitals as available on self-hosted with no caveat, but the Performance nav item and the Web Vitals settings toggle were both behind NEXT_PUBLIC_CLOUD. The server side was never gated: the /performance endpoints register unconditionally and the lcp/cls/inp/fcp/ttfb columns are healed on ClickHouse init. The !isMobileSite conditions are kept — mobile sites have no web vitals. The Stripe plan checks and the plan-badge suppression are untouched, so cloud behaviour is unchanged and no plan badge leaks on self-host.
The GSC credentials were only wired into docker-compose.cloud.yml, so a
self-hosted backend never received them however they were set. Pass them
through in the shipped compose file and document them in .env.example.
GOOGLE_REDIRECT_URI defaults to ${BASE_URL}/api/gsc/callback, which is where
both the bundled Caddy config and the documented Traefik setup route /api.
Add the Google OAuth vars to the documented .env and to the Coolify compose sample, plus a setup section covering the OAuth client, the redirect URI and the public-dashboard caveat. Also drop the "(Cloud only)" qualifier from the README's Web Vitals screenshot heading, which no longer holds.
…VER_URL
Both call sites fall back to ${SERVER_URL}/api/gsc/callback, but SERVER_URL is
assigned nowhere in the repo — not in .env.example, neither compose file, nor
any Dockerfile. That made GOOGLE_REDIRECT_URI mandatory in practice, and
omitting it produced a literal "undefined/api/gsc/callback" redirect.
BASE_URL is always set on self-host, and both the bundled Caddy config and the
documented Traefik setup route /api to the backend. Both sites use the same
expression — Google rejects the token exchange if the redirect_uri differs
from the one used to obtain the code.
|
@TimBroddin is attempting to deploy a commit to the goldflag's projects Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughThe PR adds Google Search Console OAuth configuration and a credential-based ChangesGoogle Search Console integration
Web Vitals availability
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Browser
participant ConnectEndpoint
participant GoogleOAuth
participant CallbackEndpoint
Browser->>ConnectEndpoint: Start Google OAuth connection
ConnectEndpoint->>GoogleOAuth: Redirect with OAuth client configuration
GoogleOAuth->>CallbackEndpoint: Return OAuth callback
CallbackEndpoint->>Browser: Redirect to BASE_URL
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
server/src/api/getConfig.ts (1)
19-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winKeep only the public-response rationale.
Lines 19-21 repeat the credential-presence implementation. Retain a short comment only if it explains why this public route returns a boolean instead of credential values.
As per coding guidelines, “Avoid broad abstractions, unrelated refactors, or comments that merely repeat the code in the server codebase.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/src/api/getConfig.ts` around lines 19 - 22, Simplify the comment near the public configuration response to retain only the rationale for exposing a boolean instead of OAuth credential values. Remove the repeated explanation of credential-based availability and self-hosted environment variables.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/content/docs/`(docs)/self-hosting-guides/self-hosting-manual.mdx:
- Around line 250-255: Update the Google OAuth setup steps to document both
required authorized redirect URIs: /api/gsc/callback for Google Search Console
and /api/auth/callback/google for better-auth social login. Clarify that
GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET are optional when configuring
search-only use, while preserving the requirement that GOOGLE_REDIRECT_URI
exactly matches the Search Console callback.
---
Nitpick comments:
In `@server/src/api/getConfig.ts`:
- Around line 19-22: Simplify the comment near the public configuration response
to retain only the rationale for exposing a boolean instead of OAuth credential
values. Remove the repeated explanation of credential-based availability and
self-hosted environment variables.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: dd4a2c77-5649-41fa-920b-71b794f0fd97
📒 Files selected for processing (14)
.env.exampleREADME.mdclient/src/app/[site]/components/Sidebar/Sidebar.tsxclient/src/app/[site]/main/page.tsxclient/src/components/SiteSettings/SiteSettings.tsxclient/src/components/SiteSettings/TrackingTab.tsxclient/src/lib/configs.tsdocker-compose.ymldocs/content/docs/(docs)/self-hosting-guides/self-hosting-manual.mdxserver/src/api/getConfig.test.tsserver/src/api/getConfig.tsserver/src/api/gsc/callback.tsserver/src/api/gsc/connect.tsserver/src/lib/const.ts
3f7d590 to
321bdaa
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
321bdaa to
9cf9749
Compare
|
Up, it has been a long time since Web Vitals has been live on rybbit cloud and still self hosted version can't see it )': |
Picks up #1091, which got closed as completed, but the Web Vitals and Search Console gates are still there. (The Query part of it did get fixed.)
self-host-vs-cloud.mdxsays self-hosted gets Web Vitals, and Search Console "(Requires Google OAuth env vars)". Neither is reachable, since both sit behindIS_CLOUD. Pages View and Email reports are behind the same flag, but the docs list those as cloud only, so I left them alone.None of it was gated server side. The GSC routes register unconditionally, the only
IS_CLOUDcheck inindex.tsis Stripe, and the web vitals columns get added on ClickHouse init. It was just the UI, plusdocker-compose.ymlnever passing the Google credentials through.So
/api/confignow returns agscEnabledboolean based on whetherGOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRETare set.useConfigs()already hits that endpoint fordisableSignupandmapboxToken, so there's nothing new to wire up and it works without rebuilding the client. Only the boolean, since/api/configis public.The Integrations tab and the dashboard card use that flag. I kept the card gated rather than always showing it, because the Connect button 500s when there are no credentials. Web Vitals just loses the guard, since the docs put no condition on it.
Compose forwards
GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRETandGOOGLE_REDIRECT_URInow, the same way it already does for OpenRouter. All three are documented in.env.exampleand in the self-hosting guide, along with a short section on creating the OAuth client and the redirect URI it needs.One other thing worth flagging:
SERVER_URLisn't set anywhere in the repo, but bothconnect.tsandcallback.tsfall back to it, so leavingGOOGLE_REDIRECT_URIunset produced a literalundefined/api/gsc/callback. It falls back toBASE_URLnow.If these are meant to stay cloud only, feel free to close this. The docs would be the thing to fix then, since they currently promise both to self-hosters.
Tested on my own self-hosted instance:
gscEnabledflips correctly, the credentials don't leak into the response, and Integrations and Performance show up. Ran the full OAuth flow end to end, including property selection, and the connection completes. Added a small test forgetConfig. Server suite and typecheck are clean.Summary by CodeRabbit
New Features
Documentation