Skip to main content

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:
Domain verification is tracked per surface. 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 by BingController 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_ORIGINS is 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_SECRET verifies inbound webhooks. Unsigned or mis-signed requests are rejected.
  • php artisan clerk:migrate-users imports pre-existing local users into Clerk, preserving bcrypt passwords and linking records by external_auth_id.
Magic-link sign-in is supported alongside Clerk via the 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.
Register the webhook endpoint at POST /polar/webhook in the Polar dashboard, then copy that endpoint’s signing secret into POLAR_WEBHOOK_SECRET.
Product IDs are environment-specific. Moving POLAR_SERVER from sandbox to production requires replacing all three POLAR_PRODUCT_* IDs with the production products.
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_ACCESS_KEY / SCREENSHOTONE_SECRET_KEY. Used by GoogleSearchScreenshotService and TakeSearchScreenshotJob to capture the SERP behind a prompt run; surfaced as PromptRun::$screenshot_url.
PageSpeedService and FetchPageSpeedInsightsJob populate the PagespeedInsight model for the accessibility and site-intelligence views.
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_API_KEY. Supplies keyword data to prompt suggestion when a campaign has no Search Console connection.
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.