Skip to main content
All provider configuration lives in config/ai.php. Each provider has one class in app/Services/LLM, and each entry in the config carries a base URL, a default model, a batch_supported flag and a model catalogue with cost metadata.

Providers

Claude is the only provider with batch_supported => true. OpenAI’s is set to false with a comment noting batch was turned off in favour of realtime processing — so enabling AI_BATCH_ENABLED does not change OpenAI’s behaviour.
SerpApi is not an LLM — it is how the app reads Google’s AI Overview and AI Mode surfaces, billed per search (cost_per_search of 0.01 for both) rather than per token.
Semrush also sits in the providers list (SEMRUSH_API_KEY, SEMRUSH_BASE_URL) but is a keyword-data source, not an LLM. The Suggest Prompts flow falls back to it when a campaign has no Search Console connection. Neither variable is in .env.example — add them by hand if you need that fallback path.

Model defaults

The Grok default differs by source: config/ai.php falls back to grok-4, while .env.example ships grok-3. Whichever is in your .env wins, so set it explicitly rather than relying on the fallback.
ONBOARDING_MODEL is separate on purpose. The whole setup wizard — brand name, business description, topics, prompts, variants — runs on the cheapest fast Gemini model so onboarding stays snappy and does not consume the OpenAI quota. Adding a model means adding it to that provider’s models array with a name, context_window and cost_per_1k_tokens. The cost figure is what TokenUsageTracker uses to derive spend, so an omitted or stale value silently produces wrong cost reporting.

Rate limits

Configured per provider under rate_limits, as requests and tokens per minute: These are the app’s own ceilings, not the providers’ published limits. Raise them only after confirming your account’s actual quota.

Batch settings

check_interval_minutes and retry_attempts are hardcoded — change them in config/ai.php rather than looking for an environment variable.

Prompt configuration

Ten default prompt categories drive generation: alternatives, comparison, reviews, tutorials, pricing, updates, troubleshooting, integrations, plans and security.

Visibility detection

The visibility block tunes how VisibilityDetector reads answers:
Mention matching is case-insensitive and respects word boundaries, so a brand name will not match inside a longer word. Prefix stripping is what makes blog.example.com and www.example.com count as the same domain.