Google Analytics 4 and Search Console
A campaign can connect GA4 and Search Console under different Google accounts —ga4_google_account_id and gsc_google_account_id are separate foreign keys to
GoogleAccount. This matters in agency setups where analytics and search access live with
different clients.
The OAuth flow is in CampaignController and Services/GoogleOAuthService:
Environment:
isDomainFullyVerified() requires both
ga4_domain_verified and gsc_domain_verified; hasDomainVerificationIssues() is true if
either is missing. POST /campaigns/{campaign}/recheck-domain re-runs the check.
GA4 reports in the property’s own timezone.
php artisan ga4:fetch-timezone caches it per
campaign — without it, daily traffic totals can be attributed to the wrong day.Bing Webmaster Tools
Handled byBingController and BingWebmasterService, backed by the BingAccount model:
Credentials are configured through
config/services.php.
Clerk — authentication
Clerk is the identity provider.Services/Clerk holds ClerkService and
ClerkApiException; the frontend uses @clerk/react.
CLERK_PERMITTED_ORIGINSis a comma-separated allow-list of authorized-party (azp) origins. Session tokens presented from an origin outside the list are rejected — this is a common cause of “works locally, fails on staging”.CLERK_WEBHOOK_SIGNING_SECRETverifies inbound webhooks. Unsigned or mis-signed requests are rejected.php artisan clerk:migrate-usersimports pre-existing local users into Clerk, preserving bcrypt passwords and linking records byexternal_auth_id.
LoginToken model.
Polar — billing
Polar acts as merchant of record.Services/Polar/PlanCatalog maps plans, config/polar.php
and config/plans.php hold the configuration, and the Plan and Product models mirror the
catalogue locally.
POST /polar/webhook in the Polar dashboard, then copy that
endpoint’s signing secret into POLAR_WEBHOOK_SECRET.
Laravel Cashier and the STRIPE_* keys are still installed. Treat Polar as the active path
unless you are specifically working on the Stripe code.
Supporting services
ScreenshotOne — SERP screenshots
ScreenshotOne — SERP screenshots
SCREENSHOTONE_ACCESS_KEY / SCREENSHOTONE_SECRET_KEY. Used by
GoogleSearchScreenshotService and TakeSearchScreenshotJob to capture the SERP behind a
prompt run; surfaced as PromptRun::$screenshot_url.PageSpeed Insights
PageSpeed Insights
PageSpeedService and FetchPageSpeedInsightsJob populate the PagespeedInsight model
for the accessibility and site-intelligence views.HubSpot — waitlist
HubSpot — waitlist
HUBSPOT_PORTAL_ID / HUBSPOT_FORM_ID. HubSpotWaitlistService receives submissions
from the pre-launch coming-soon page via POST /waitlist, throttled to 10 requests per
minute.Semrush — keyword fallback
Semrush — keyword fallback
SEMRUSH_API_KEY. Supplies keyword data to prompt suggestion when a campaign has no
Search Console connection.Mattermost — error logging
Mattermost — error logging
MATTERMOST_ACCESS, MATTERMOST_CHANNEL_ID, MATTERMOST_LOG_ENABLED. A custom log
channel in config/logging.php posts errors to a Mattermost channel. Disabled by default
and forced off during tests.