Skip to content

fix(self-host): show Web Vitals and Search Console on self-hosted installs - #1104

Open
TimBroddin wants to merge 7 commits into
rybbit-io:masterfrom
TimBroddin:fix/self-host-gsc-webvitals
Open

fix(self-host): show Web Vitals and Search Console on self-hosted installs#1104
TimBroddin wants to merge 7 commits into
rybbit-io:masterfrom
TimBroddin:fix/self-host-gsc-webvitals

Conversation

@TimBroddin

@TimBroddin TimBroddin commented Aug 5, 2026

Copy link
Copy Markdown

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.mdx says self-hosted gets Web Vitals, and Search Console "(Requires Google OAuth env vars)". Neither is reachable, since both sit behind IS_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_CLOUD check in index.ts is Stripe, and the web vitals columns get added on ClickHouse init. It was just the UI, plus docker-compose.yml never passing the Google credentials through.

So /api/config now returns a gscEnabled boolean based on whether GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET are set. useConfigs() already hits that endpoint for disableSignup and mapboxToken, so there's nothing new to wire up and it works without rebuilding the client. Only the boolean, since /api/config is 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_SECRET and GOOGLE_REDIRECT_URI now, the same way it already does for OpenRouter. All three are documented in .env.example and 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_URL isn't set anywhere in the repo, but both connect.ts and callback.ts fall back to it, so leaving GOOGLE_REDIRECT_URI unset produced a literal undefined/api/gsc/callback. It falls back to BASE_URL now.

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: gscEnabled flips 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 for getConfig. Server suite and typecheck are clean.

Summary by CodeRabbit

  • New Features

    • Google Search Console integration can be enabled through deployment configuration.
    • Performance and Web Vitals options are available for all non-mobile sites, including self-hosted deployments.
    • OAuth connections use the application’s base URL for more reliable redirects.
  • Documentation

    • Added self-hosting instructions for Google Search Console setup, OAuth credentials, redirect configuration, and access requirements.
    • Updated the Dashboard Preview label to “Web Vitals.”

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.
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

@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.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds Google Search Console OAuth configuration and a credential-based gscEnabled flag. It updates frontend visibility checks and OAuth callback fallbacks. It also enables Web Vitals outside cloud mode for non-mobile sites and updates self-hosting documentation.

Changes

Google Search Console integration

Layer / File(s) Summary
OAuth configuration and backend status
server/src/lib/const.ts, server/src/api/getConfig.ts, server/src/api/getConfig.test.ts, server/src/api/gsc/*
The backend reads Google OAuth credentials, exposes gscEnabled only when both credentials exist, prevents credential exposure, and uses BASE_URL for callback fallbacks.
Configuration-driven integration UI
client/src/lib/configs.ts, client/src/app/[site]/main/page.tsx, client/src/components/SiteSettings/SiteSettings.tsx
The frontend uses gscEnabled to control Search Console rendering and Site Settings integration controls.
Self-hosting OAuth setup
.env.example, docker-compose.yml, docs/content/docs/(docs)/self-hosting-guides/self-hosting-manual.mdx
Environment examples, Docker Compose settings, and self-hosting instructions now include Google OAuth configuration and setup steps.

Web Vitals availability

Layer / File(s) Summary
Non-cloud Web Vitals visibility
client/src/app/[site]/components/Sidebar/Sidebar.tsx, client/src/components/SiteSettings/TrackingTab.tsx, README.md
Performance navigation and Web Vitals settings no longer require cloud mode for non-mobile sites. The Dashboard Preview heading removes the cloud-only qualifier.

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
Loading

Possibly related PRs

  • rybbit-io/rybbit#1105: Both PRs remove cloud-only visibility restrictions from Sidebar.tsx for self-hosted functionality.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: enabling Web Vitals and Google Search Console for self-hosted installations.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@TimBroddin
TimBroddin marked this pull request as ready for review August 5, 2026 06:04

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
server/src/api/getConfig.ts (1)

19-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep 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

📥 Commits

Reviewing files that changed from the base of the PR and between 806e368 and d195bf3.

📒 Files selected for processing (14)
  • .env.example
  • README.md
  • client/src/app/[site]/components/Sidebar/Sidebar.tsx
  • client/src/app/[site]/main/page.tsx
  • client/src/components/SiteSettings/SiteSettings.tsx
  • client/src/components/SiteSettings/TrackingTab.tsx
  • client/src/lib/configs.ts
  • docker-compose.yml
  • docs/content/docs/(docs)/self-hosting-guides/self-hosting-manual.mdx
  • server/src/api/getConfig.test.ts
  • server/src/api/getConfig.ts
  • server/src/api/gsc/callback.ts
  • server/src/api/gsc/connect.ts
  • server/src/lib/const.ts

@TimBroddin
TimBroddin force-pushed the fix/self-host-gsc-webvitals branch from 3f7d590 to 321bdaa Compare August 5, 2026 06:29
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

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.

@TimBroddin
TimBroddin force-pushed the fix/self-host-gsc-webvitals branch from 321bdaa to 9cf9749 Compare August 5, 2026 06:31
@TimBroddin TimBroddin changed the title Show Web Vitals and Search Console on self-hosted installs fix(self-host): show Web Vitals and Search Console on self-hosted installs Aug 5, 2026
@CallMeAl3x

Copy link
Copy Markdown

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 )':

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants