feat(analytics): replace Plausible with Google Analytics behind a consent bar - #36
Merged
Merged
Conversation
…sent bar Self-hosted Plausible is gone. Google Analytics 4 takes its place, loaded in Consent Mode: every storage type starts denied, so the tag sets no cookie and sends only a cookieless ping per page until the reader clicks Allow. The advertising signals stay denied for everyone. The head script's order is the contract, and AnalyticsConsentTest pins it by position: consent default, then a stored "granted" applied from localStorage, then config, so a returning reader's first page view carries its cookies. ConsentBar asks once, after hydration (SSR cannot see localStorage), and only when gtag is on the page, so dev and staging never show it. Allow and Decline are the same variant at the same size. It sits bottom-left and on a phone leaves 5.5rem for Crisp's launcher, measured on the live site at 54px, 14px from the corner. "Cookie settings" in the footer and a button in /privacy#cookies reopen it; declining deletes any _ga cookie already set. The account portal is a separate app on this origin carrying a copy of the tag, the bar and consent.ts under the same storage key, so one answer covers both. docs/architecture.md now has an "Analytics and consent" section on that contract. download_click, checkout_started and newsletter_signup_clicked keep their names and parameters, now sent through gtag. /privacy no longer calls analytics cookie-less. It names Google Analytics as a processor, lists _ga and _ga_<ID> with consent as the lawful basis, the consent key, and the portal's session cookies, and covers the US transfer and a 14-month retention. GOOGLE_ANALYTICS_ID replaces PLAUSIBLE_DOMAIN and PLAUSIBLE_SCRIPT_URL and must be set in the server .env before this deploys.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces self-hosted Plausible with Google Analytics 4 (
G-FG4YV1QXYN) on the marketing site. The account portal makes the same switch in TableProApp/license#85, and the two must ship together.Consent
GA4 sets
_gaand_ga_<ID>, which need permission first in the EEA and UK, so the tag loads in Consent Mode. The head script's order is the contract, andAnalyticsConsentTestpins it by position:gtag('consent', 'default', …)with every storage typedenied.localStorage['tablepro:analytics-consent'] === 'granted',analytics_storageis granted.gtag('config'), so a returning reader's first page view carries its cookies.Until the reader allows it, GA gets one cookieless ping per page and nothing is stored on the device.
ad_storage,ad_user_dataandad_personalizationare never granted.The bar
localStorage. It also renders only whengtagexists, so dev and staging never show it.5.5remon the right./privacy#cookiesreopen the bar. Declining after allowing deletes the_gacookies.consent.test.tsruns this against a fake browser and checks the exact cookie writes.The account portal carries a copy of the tag, the bar and
consent.tsunder the same key, so one answer covers both apps.docs/architecture.mdhas a new "Analytics and consent" section on that contract.Events and privacy
download_click,checkout_startedandnewsletter_signup_clickedkeep their names and parameters, now sent throughgtag./privacyno longer calls analytics cookie-less. It now:_ga/_ga_<ID>with consent as the lawful basistablepro-session/XSRF-TOKENcookiesBefore merging
GOOGLE_ANALYTICS_ID=G-FG4YV1QXYNto/var/www/tablepro.app/.env.PLAUSIBLE_*can go. The deploy rebuilds the config cache becauseconfig/changed, so the value must already be there.After merging (GA admin)
location,platform,tier,cycleandsourceas event-scoped custom dimensions, or the event parameters won't show in reports./privacy.signature, expires, token, email, orderas a second safeguard behind the portal's own redaction.Not in this PR
/privacydoesn't list.tablepro:attributionis still written without consent.Testing
php artisan test --compact: 241 passed, including the 9 new tests inAnalyticsConsentTest.npm run test:js: 26 passed, including 7 new inconsent.test.ts.tsc --noEmitclean._gaand_ga_*after Allowconsent:updatesits beforeconfigin the dataLayer