8 · Engagement & SEO
Objective — wire the growth surfaces, led by GA4 via the universal 3-file Safe Vendor Deviation Pattern (one blade edit, one config key, one env var) — the canonical example whose shape recurs for Sentry JS, PostHog, Pixel, and Turnstile — then run check-first on chat, social login, blog, and sitemap.
Background
Section titled “Background”The growth surfaces — analytics, chat, social login, blog, sitemap. Most are SHOULD / LATER check-first tasks, but analytics is the canonical example of the universal Safe Vendor Deviation Pattern and earns the most space because the same 3-file shape recurs for Sentry JS, PostHog, Facebook Pixel, Turnstile, and more.
1. Wire analytics tracking (GA4)
Section titled “1. Wire analytics tracking (GA4)”Getting the Measurement ID and confirming Realtime are Google-Analytics-dashboard actions a person performs; the 3-file code change is agent work.
Most CodeCanyon Laravel scripts ship ZERO built-in analytics — no admin field, no tracking_code column. Pick your path from the capabilities doc.
Path 1 — vendor has a built-in analytics field (rare): Admin → Config → SEO (or Settings → Tracking) → paste the Measurement ID → save → view-source the landing page to confirm the GA4 script is present → check GA4 Realtime.
Path 2 — no built-in field (common): the 3-file Safe Vendor Deviation. The pattern keeps your change small, env-gated, and auditable across vendor updates — one blade edit, one convention-file key, one env var:
flowchart LR BLADE["landing.blade.php<br/>@if(config('services.google.ga4_measurement_id'))<br/>…gtag snippet…"] CONFIG["config/services.php<br/>'google' => ['ga4_measurement_id' => env('GA4_MEASUREMENT_ID')]"] ENV["shared/.env<br/>GA4_MEASUREMENT_ID=\"G-XXXXXXXXXX\""] BLADE -->|reads via config()| CONFIG CONFIG -->|reads via env()| ENV-
Edit the blade — in
resources/views/layouts/landing.blade.php(the public landing layout — notguest.blade.php, which has Jetstream tenant-context issues, and not authenticated app layouts), insert the standardgtag.jssnippet right before</head>, gated on config and cookie consent (Termly/GetTerms autoblock or your Phase 6/7 banner). Example with Termly autoblock — the script stays inert until analytics consent:@if (config('services.google.ga4_measurement_id')){{-- <PROJECT> Phase 6 — GA4 (consent-gated; Termly data-auto-block="on" must load first in <head>) --}}<script type="text/plain" data-cookie-category="analytics"src="https://www.googletagmanager.com/gtag/js?id={{ config('services.google.ga4_measurement_id') }}"></script><script type="text/plain" data-cookie-category="analytics">window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag('js', new Date());gtag('config', '{{ config('services.google.ga4_measurement_id') }}');</script>@endif- ✅ The gtag snippet is config-gated, consent-gated (not unconditional), with a project-name comment marker.
-
Edit the config — add
'google' => ['ga4_measurement_id' => env('GA4_MEASUREMENT_ID')]toconfig/services.php. Vendors almost never touch this convention file, which is what makes it a safe home. Read viaconfig(...), neverenv(...)from blade/app code.- ✅
config/services.phpexposesservices.google.ga4_measurement_id.
- ✅
-
Append the env var to
shared/.envon the server (not the ephemeral release.env), then rebuild the config cache.Terminal window PHP_BIN=$(grep "set('bin/php'" deploy.php | grep -oE "/[^'\"]+/php" | head -1)dep ssh staging "grep -q '^GA4_MEASUREMENT_ID=' ~/domains/<DOMAIN>/deploy/shared/.env \|| echo 'GA4_MEASUREMENT_ID=\"G-XXXXXXXXXX\"' >> ~/domains/<DOMAIN>/deploy/shared/.env"dep ssh staging "cd ~/domains/<DOMAIN>/deploy/current && $PHP_BIN artisan config:clear && $PHP_BIN artisan config:cache"# Expected: the ID is appended once on shared/.env, then the config cache rebuilds- ✅
GA4_MEASUREMENT_IDis set inshared/.envand the config cache is rebuilt.
- ✅
-
Verify the tag fires.
Terminal window curl -sS https://staging.<DOMAIN>/ | grep -c "$GA4_MEASUREMENT_ID" # expect ≥1 (consent-gated tag may show once in HTML)# Expected: ≥1- ✅
curl | grep -creturns ≥1 for the real Measurement ID; GA4 → Reports → Realtime shows your visit within ~30s. Record the deviation in_CUSTOMIZATIONS.md(file / what added / task / comment marker) — that registry is the shopping list for every vendor-update merge.
- ✅
2. Configure the chat widget
Section titled “2. Configure the chat widget”CHECK: Admin → Settings for a Crisp / Tawk.to / Intercom / generic widget field.
- Configure or defer the widget.
-
If present — paste the provider’s widget code or API key.
-
If absent — add the widget script to the layout footer (a small code task; defer).
-
✅ The widget is configured, or deferred. Priority: LATER — not needed at launch; enable it when you have users to support.
-
3. Configure social login
Section titled “3. Configure social login”CHECK: Admin → Config → Login (or Social Auth / OAuth Settings). Creating the OAuth app in each provider’s console and entering the client ID/secret are person-driven.
- Configure or defer social login.
-
If present — enter the Google / Facebook / GitHub OAuth client ID + secret and enable the providers you want.
-
If absent — likely needs Laravel Socialite + code. Check for an existing
SocialLoginControllerbefore building from scratch — many vendors ship one that’s just unwired. -
✅ Social login is configured (OAuth app created first), or deferred after checking for an existing
SocialLoginController. Priority: LATER.
-
4. Confirm the blog system
Section titled “4. Confirm the blog system”CHECK: Admin → Blog (or Posts / Content).
- Confirm status or defer.
-
If present — the system is ready; just start writing posts. No setup needed.
-
If absent — adding a blog is a code task; defer.
-
✅ Blog status is confirmed (ready or deferred). Blog content is a growth activity, not a launch blocker.
-
5. Verify the sitemap
Section titled “5. Verify the sitemap”CHECK: visit /sitemap.xml on the domain, and look under Admin → SEO.
- Verify or defer the sitemap.
-
If auto-generated — confirm it lists your key pages, then submit it to Google Search Console.
-
If absent — generating a sitemap is a small code/SEO task; defer.
-
✅
/sitemap.xmlis verified and submitted to Search Console, or deferred. Important for SEO but not a launch blocker.
-
Checklist
Section titled “Checklist”Do not mark this step done until every box below is checked.
- 🔀 GA4 wired — built-in field or the 3-file deviation;
curl | grep -creturns ≥1 for the real Measurement ID; Realtime shows traffic; deviation recorded in_CUSTOMIZATIONS.md. - 🔀 Consent dependency queued — GA4 consent-gating (page 6) is queued for production launch.
- 👤 Chat configured — chat widget configured or deferred (LATER).
- 👤 Social login handled — configured or deferred — existing
SocialLoginControllerchecked before any new build. - 🤖 Blog status confirmed — ready / deferred.
- 👤 Sitemap handled —
/sitemap.xmlverified and submitted to Search Console or deferred.
SuperAdmin setup is complete. Continue to Phase 7 · Security & monitoring — harden the app, then wire backups and observability before real users arrive.