angeo / module-aeo-brand-visibility

angeo/module-aeo-brand-visibility

Live AI brand visibility audit for Magento 2. Queries ChatGPT, Claude, Perplexity, Gemini and Groq with brand-probing prompts and scores real-world AI recall, citation rate and recommendation presence. Extends angeo/module-aeo-audit v3 via CheckerInterface as the 16th signal, alongside the 15 built-in technical checks.

magento2-module Compatibility: Not compatible Code Quality: Fail Tests: N/A Security: Pass MIT

Are you the maintainer of angeo?

Packagento pulls angeo's Composer packages from the public registry so buyers can find them here.

Claim the namespace to take ownership, publish new releases directly, and start charging for premium versions.

Claim this namespace →

Viewing version 4.0.0. Latest version is 4.0.1. Switch to latest

Angeo AEO Brand Visibility for Magento 2

Latest Stable Version
License: MIT

Measure whether AI assistants actually name your store when a shopper asks them
where to buy something.

The module asks ChatGPT, Claude, Perplexity, Gemini and Groq a set of shopping
questions, reads their answers, and scores how visible your brand is. It repeats
every question several times, so the score comes with a confidence interval
instead of pretending one sample is the truth.

It plugs into angeo/module-aeo-audit
as a live_signal checker, and also runs on its own from the admin panel, cron
or the command line.


Why this exists

Classic SEO tools tell you where you rank on a results page. They tell you
nothing about what a language model says when someone asks it a question. This
module measures that directly: it asks, then reads the answer.


What is measured

Each answer is scored on five signals:

Signal Question it answers Default weight
Mentioned Does the answer name the brand at all? 1.0
Recommended Is the brand suggested, not just listed? 1.5
URL cited Is your domain quoted? 1.5
First position Is the brand named before its competitors? 2.0
Positive tone Is the wording around the brand favourable? 0.5

A sixth signal, negative tone, is not weighted. It reduces the earned score
by the configured penalty, because "avoid this shop" is worse than not being
mentioned at all.

On top of the per-answer score the module reports:

  • Share of voice — your weight against every tracked competitor in the same
    answer, based on how often you are named and how early.
  • Win rate — the share of answers where you are named before every
    competitor.
  • Accuracy issues — answers where a model attributes a website you do not
    own to your brand.

Reading the score honestly

Two things decide whether the number means anything.

Grounding. A model answering from memory reflects a training set that is
months old. Nothing you change on your store will move that number this quarter.
A grounded model searches the live web before answering, so it responds to your
work within days. Perplexity is always grounded; ChatGPT, Claude and Gemini can
be, per provider, in the configuration. Groq cannot. If you want a metric that
reacts to what you do, enable grounding.

Sampling. Language models are not deterministic. The same prompt returns
different answers. Every provider and prompt pair is therefore asked N times
(three by default) and reported as a mean with the half-width of its 95%
confidence interval — the ± figure next to the score. A movement smaller than
that margin is noise, and the alert system will not fire on it.


Requirements

  • Magento Open Source or Adobe Commerce 2.4.6 – 2.4.8
  • PHP 8.2, 8.3 or 8.4
  • angeo/module-aeo-audit 3.x or 4.x
  • At least one AI provider API key
  • A running message queue consumer (or inline run mode, see below)

Installation

composer require angeo/module-aeo-brand-visibility
bin/magento module:enable Angeo_AeoBrandVisibility
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush

Start the consumer that executes queued audits:

bin/magento queue:consumers:start angeoBrandVisAuditRun

On most installations consumers_runner in app/etc/env.php starts it from
cron automatically. If your platform does not run message queue consumers at
all, set Run Mode to Inline in the configuration; be aware that a full run
then happens inside the admin request and may hit the PHP or gateway timeout.


Configuration

Stores → Configuration → Angeo AEO → Brand Visibility (AI Models)

Almost every setting is available per website and per store view, so a
multi-store installation can measure each brand separately.

General

Field Notes
Enable Brand Visibility Includes the check in every AEO audit for this scope
Run Mode Background queue (recommended) or inline
Brand Name Defaults to the store name
Brand Domain Defaults to the store base URL host
Brand Aliases Alternate spellings, comma separated
Store Category What you sell, in two or three words
Top Products One per line; derived from the catalogue when empty
Cache Lifetime Hours; 0 disables caching completely
Log Prompts and Answers Writes to var/log/angeo_aeo_brand_visibility.log

Set the store category. When it is empty and the catalogue gives nothing
useful, prompts fall back to a generic phrase, and generic phrases are won by
the large marketplaces every time. This single field moves the score more than
any other.

Providers

Each provider has its own group with the same fields: enable, API key (stored
encrypted), model, grounding, max tokens, temperature and timeout.

Provider Grounded answers Notes
ChatGPT Optional Needs a search-capable model such as gpt-4o-search-preview
Claude Optional Uses the server-side web search tool; billed per search
Perplexity Always The most responsive signal of the five
Gemini Optional Uses Google Search as a tool
Groq No Free tier; a memory-only baseline

Model identifiers change often. Pick the closest option, and expect to revisit
the field after a provider release.

Queries

Six built-in prompts, each with its own on/off switch and optional override
text: best stores in category, where to buy, tell me about this brand, product
search, compare with competitors, gift guide. Add your own under Custom
Prompts
, one per line, as key: prompt text.

Placeholders: {{brand}}, {{domain}}, {{category}}, {{products}}.

Samples per Query controls how many times each pair is asked. Cost scales
linearly with it; the confidence interval narrows with the square root of it.

Analysis

Phrase matching supports English, Ukrainian, Dutch, German, French and
Spanish
. English phrases are always matched in addition to the selected
language, because AI answers mix languages freely.

Extra Top-Level Domains matters for the accuracy check: without nl, de
or co.uk in that field, a wrong country domain attributed to your brand will
not be flagged.

Alerts

An alert fires when the score drops by more than the configured number of points
against the trailing average and the drop exceeds the confidence margin of
the run, or when a competitor outranks you, or negative tone or a wrong URL is
detected.

The webhook must be HTTPS, and hosts resolving to private or reserved addresses
are rejected unless an operator explicitly allows them.


Command line

# Full audit for the default scope
bin/magento angeo:aeo:brand-visibility

# One store view, ignoring the cache, with the action plan
bin/magento angeo:aeo:brand-visibility --store=2 --refresh --plan

# Machine-readable output
bin/magento angeo:aeo:brand-visibility --format=json
bin/magento angeo:aeo:brand-visibility --format=markdown

# One provider and prompt, printing the raw answer
bin/magento angeo:aeo:brand-visibility --provider=perplexity --prompt=brand_direct

# Fail a CI pipeline below a threshold
bin/magento angeo:aeo:brand-visibility --fail-on=50
Option Meaning
--store Store view id (default 0)
--refresh, -r Bypass the result cache
--provider Query one provider instead of the full audit
--prompt Prompt key used with --provider
--format table, json or markdown
--plan Print the action plan
--fail-on Exit code 1 below this score

Admin panel

Marketing → AEO Brand Visibility

  • Dashboard — pick a store view, start a run, watch it complete, read each
    answer, and generate the action plan from the latest stored run.
  • Audit History — a standard grid with filters, plus a detail page and CSV
    export per run.

Access is split into four permissions, so an agency can be given read access
without the ability to spend money on API calls:

Resource Grants
Angeo_AeoBrandVisibility::view Read reports and history
Angeo_AeoBrandVisibility::run Start audits and single test queries
Angeo_AeoBrandVisibility::export Download CSV
Angeo_AeoBrandVisibility::config Change the configuration

Scheduling and retention

Scheduled runs use the dedicated angeo_brand_visibility cron group, so slow
provider calls cannot delay Magento's default group. A second job applies the
retention policy nightly: runs older than the configured age, and runs beyond
the per-store-view budget, are deleted.


Cost

Cost is providers × prompts × samples requests per run. With three providers,
three prompts and three samples that is 27 requests. Weekly runs on small models
are cents; grounded searches on large models are not. Start with samples = 3
and one grounded provider.


Development

vendor/bin/phpcs --standard=vendor/angeo/module-aeo-brand-visibility/phpcs.xml
vendor/bin/phpstan analyse -c vendor/angeo/module-aeo-brand-visibility/phpstan.neon
vendor/bin/phpunit -c vendor/angeo/module-aeo-brand-visibility/phpunit.xml

Adding a provider takes an AiProviderInterface implementation and one line in
the ProviderPool argument of etc/di.xml. No existing class needs editing.


Related modules

  • angeo/module-aeo-audit — the audit framework this checker plugs into
  • angeo/module-llms-txt — publish llms.txt for AI crawlers
  • angeo/module-rich-data — stronger Organization and Product schema
  • angeo/module-robots-txt-aeo — control which AI crawlers may read the store

License

MIT. See LICENSE.

Built by Ievgenii Gryshkun — Magento 2 solution architect,
Netherlands.

Changelog

All notable changes to angeo/module-aeo-brand-visibility are documented here.
The format follows Keep a Changelog and
the project uses Semantic Versioning.

[4.0.0] — 2026-08-31

A rewrite for the Adobe Commerce Marketplace technical requirements, plus fixes
for the data-loss and methodology problems found in 3.0.0.

Breaking

  • BrandVisibilityServiceInterface::run() takes a fourth argument,
    ?int $auditResultId, so a queued run can be written back onto its own row.
  • AuditResultRepositoryInterface::saveReport() takes ?int $id;
    createPendingRun() and markFailed() were added; pruneOldRecords() was
    replaced by prune(int $maxPerStore, int $maxAgeDays).
  • BrandQueryResult now represents a cell aggregated over N samples. Its
    signals array of booleans became signalRates (percentages), and
    rawResponse became responses with a getRawResponse() accessor.
  • Configuration path angeo_brand_vis/queries/queries_per_provider was renamed
    to .../max_prompts; 0 now means "no cap" rather than "cap at zero".
  • angeo_brand_vis/analysis/llm_judge was removed. It cost a second API call
    per answer and produced a number that could not be compared between runs.
  • Admin route angeo_brand_vis/query/single became angeo_brand_vis/query/test
    and is POST-only; angeo_brand_vis/history/viewdata was removed in favour of
    the UI component grid.
  • The single ACL resource was split into ::view, ::run, ::export and
    ::config. Existing admin roles must be re-granted.
  • New database columns are added by declarative schema. Runs stored by 3.0.0
    keep their scores, but have no samples, margin or competitive data.

Added

  • Repeated sampling with a 95% confidence interval on every score. The reported
    ± margin makes it possible to tell a real regression from model variance.
  • Web-grounded answers per provider: Claude's server-side search tool, Gemini's
    Google Search tool, OpenAI search-preview models. Perplexity is always
    grounded; Groq cannot be.
  • Three-valued tone. Negative wording around the brand is detected and reduces
    the earned score by a configurable penalty.
  • Real share of voice, weighted by mention count and by how early the brand
    appears, replacing the 1/N placeholder.
  • Asynchronous runs over the message queue, with a pending row, a polling admin
    screen and an inline fallback for installations without consumers.
  • A dedicated angeo_brand_visibility cron group, and a nightly retention job
    with a per-store-view row budget and a maximum age.
  • A standard UI component grid for audit history, with filters, bookmarks and
    row actions.
  • Configurable extra top-level domains, so the accuracy check recognises nl,
    de, co.uk and other country domains.
  • Unit tests for the aggregator, the share-of-voice calculator, the report
    aggregation, the webhook guard and the configuration reader.
  • i18n/en_US.csv, etc/csp_whitelist.xml, phpcs.xml, phpstan.neon and
    phpunit.xml.

Changed

  • Providers are injected as an array through ProviderPool in di.xml instead
    of being hard-coded in the service constructor. A new provider is now one
    interface implementation and one di.xml line.
  • All HTTP traffic uses the framework HTTP client instead of raw cURL calls, and
    all JSON goes through SerializerInterface.
  • The admin templates contain no inline <script>, no inline <style> and no
    event attributes. Behaviour moved to a RequireJS module loaded through
    data-mage-init, so the screens work under a restrictive content security
    policy.
  • The action plan is built from the latest stored run instead of triggering a
    fresh billable audit on every request.
  • Retention runs in its own cron job rather than inside every save.
  • OpenAI reasoning models receive max_completion_tokens and no temperature,
    so o-series and search-preview models no longer return HTTP 400.
  • Provider labels, model option lists and the analysis language list are derived
    from code rather than duplicated in static arrays.

Fixed

  • Analyser metadata — competitors, share of voice, winner, tone and accuracy —
    is now persisted. In 3.0.0 saveReport() dropped the meta key, so the
    headline feature of that release was lost on write and never reached the
    history or the CSV export.
  • getLatest(), getStatistics() and retention are scoped by store view.
    Previously a multi-store installation averaged unrelated brands together, and
    alerts compared a store against that mixed average.
  • The audit checker honours the StoreInterface it is given. Previously the
    argument was ignored and every store view was scored against the default
    scope.
  • cache_ttl_hours = 0 disables the cache, as the field comment always claimed;
    it was previously coerced back to 24. The same fix applies to a temperature of
    0.
  • A prompt override text is ignored while its enable toggle is off.
  • The result cache lifetime is read from the scoped configuration rather than
    the unscoped instance.
  • The Gemini API key travels in the x-goog-api-key header instead of the query
    string, where it was written to proxy and access logs.
  • The alert webhook is validated: HTTPS only, and hosts resolving to private or
    reserved addresses are rejected unless explicitly allowed. This closes a
    server-side request forgery path to internal services.
  • The CLI used an invalid <e> style tag, which threw instead of printing the
    error it was trying to report.
  • Dutch and German separable verbs ("raad ik … aan", "empfehle ich") are matched
    as recommendations.
  • magento/module-email is declared in composer.json and sequenced in
    module.xml; it was used but never required.
  • Documentation drift: the supported analysis languages are en, uk, nl, de, fr, es (there is no Russian phrase set), negative sentiment is real rather than
    aspirational, and the CLI description lists every provider.

Security

  • No raw cURL, no API keys in URLs, no unvalidated outbound requests.
  • Every billable action is POST-only and behind its own ACL resource.
  • Admin output is escaped in PHP and built with the DOM API in JavaScript, so a
    provider answer cannot inject markup into the admin panel.

[3.0.0]

Added

  • Competitor tracking, share of voice and answer-accuracy checking.
  • Gemini and Groq providers.
  • Recommendation engine and CSV export.

[1.1.1]

Added

  • Initial release: ChatGPT, Claude and Perplexity providers, five scoring
    signals, admin dashboard and the live_signal audit checker.
Versions
Version Stability QA Status Compatibility Released
4.0.1 stable Fail Magento 2.4.7-2.4.9 Details 2026-09-17 19:30:00
4.0.0 stable Fail Not compatible Details 2026-09-06 16:44:57
3.0.0 stable Not tested Not yet tested Details 2026-09-06 16:43:51
2.0.0 stable Not tested Not yet tested Details 2026-09-06 16:42:55
1.2.0 stable Fail Magento 2.4.7-2.4.8 Details 2026-06-14 18:51:44
1.1.1 stable Fail Magento 2.4.7-2.4.8 Details 2026-05-28 19:14:06
1.1.0 stable Not tested Not yet tested Details 2026-05-28 19:09:11
1.0.0 stable Not tested Not yet tested Details 2026-05-16 19:15:52

Requires 11

Package Constraint
angeo/module-aeo-audit ^3.0||^4.0
magento/framework ^103.0
magento/framework-message-queue ^100.4
magento/module-backend ^102.0
magento/module-catalog ^104.0
magento/module-config ^101.2
magento/module-cron ^100.4
magento/module-email ^101.1
magento/module-store ^101.1
magento/module-ui ^101.2
php ~8.1.0||~8.2.0||~8.3.0||~8.4.0||~8.5.0

Requires-dev 4

Package Constraint
bitexpert/phpstan-magento ^0.43
magento/magento-coding-standard ^40.0 || ^41.0
phpstan/phpstan ^2.0
phpunit/phpunit ^10.5

Suggests 3

Package Reason
angeo/module-llms-txt Publish llms.txt so AI crawlers can discover your catalogue structure.
angeo/module-rich-data Strengthen Organization and Product schema for entity recognition.
angeo/module-robots-txt-aeo Control which AI crawlers may read your store.

Compatibility

Each Magento release line is installed on its supported PHP versions, then the module is built (DI compilation + static-content deploy) and its unit and integration suites are run. The matrix shows the lines and PHP versions the module is confirmed to install and run on. Code-quality results further down (phpstan, phpcs, …) are reported separately and never affect compatibility.

Compatibility matrix (Magento × PHP)
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 Fail di error Fail di error
2.4.8 Fail di error Fail di error
2.4.9 Fail di error not tested

Code Quality

Advisory checks against the module's source. Static analysis runs once across the whole module; PHPStan re-runs per Magento + PHP version because resolvable symbols differ between releases. These NEVER affect the Compatibility badge. A phpcs finding can't make a module incompatible.

Static analysis

Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.

Static analysis results
Tool Status Findings Summary
PHPCS Fail 8 2 errors, 6 warnings (ruleset: Magento2)
PHPMD Warning 3 3 rule violations (MissingImport:1, ExcessiveClassComplexity:1, TooManyPublicMethods:1)
Cpd Pass 0
Composer validate Info 1 valid; 1 advisory note (composer validate --strict)

PHPStan

Type-checks the module's PHP against a real Magento install at the configured gate level. Re-runs per Magento and PHP version because resolvable symbols differ between releases.

PHPStan results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 4 4
2.4.8 4 4
2.4.9 4 9

Tests

Unit and integration suites, run for each applicable Magento and PHP version. A test failure speaks to the module's behaviour, not its compatibility with a Magento line, so it is reported here separately and never reddens the compatibility matrix.

Unit tests

Unit tests results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 N/A N/A
2.4.8 N/A N/A
2.4.9 N/A N/A

Integration tests

Integration tests results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 N/A N/A
2.4.8 N/A N/A
2.4.9 N/A N/A

Security

Security checks run directly against the module: an audit of its declared dependencies for known vulnerabilities (composer audit) and a scan of its source for malware and web-shell signatures. Each runs once. A malware detection fails the version outright.

Security results
Tool Status Findings Summary
Composer audit Pass 0
Malware scan Pass 0
License
MIT
Authors

More from angeo

View vendor
angeo/module-llms-txt Free
magento2-module

Magento 2 module for AI Engine Optimization (AEO). Generates spec-compliant llms.txt and llms-full.txt per llmstxt.org standard, plus streaming JSONL for vector indexing. Multi-store, multi-website, CLI, cron, async admin UI, Page Builder-aware sanitization, customer-group pricing, atomic writes, ETag/Cache-Control, .md mirrors.

v4.3.3 4d ago
0
angeo/module-robots-txt-aeo Free
magento2-module

Magento 2 module for AI Engine Optimization (AEO). Injects AI crawler rules (OAI-SearchBot, GPTBot, ChatGPT-User, PerplexityBot, Perplexity-User, Google-Extended, ClaudeBot, anthropic-ai, Claude-User, Applebot, cohere-ai, Amazonbot, Meta-ExternalAgent) into robots.txt — without overwriting your existing configuration. Supports per-bot Allow/Disallow lists, Crawl-delay, Sitemap directives, multi-store, and a public Api\RobotsStatusInterface for cross-module integration with angeo/module-aeo-audit.

v4.0.0 14d ago
0
angeo/module-aeo-audit Free
magento2-module

Magento 2 AEO (AI Engine Optimization) Audit. v3 covers 15 signals — robots.txt AI bots, llms.txt + llms.jsonl, Product / Organization / FAQ schema, merchant return + shipping policies, sitemap.xml, UCP profile, AI product feed, OG tags, canonical + hreflang, JSON-LD quality, well-known endpoint matrix, Core Web Vitals via CrUX. Score Trend dashboard, Admin UI, cron, dynamic fix commands, dependency-injected extension point for custom checkers.

v4.2.3 4d ago
0
angeo/module-ucp Free
magento2-module

Spec-compliant Universal Commerce Protocol (UCP) profile generator for Magento 2. Generates /.well-known/ucp at protocol version 2026-04-08 with ECDSA P-256 signing keys, declared capabilities, and proper cache headers. v0.1.x is profile-only — catalog, cart, checkout endpoints land in later releases.

v2.1.1 2d ago
0
Make it pay

Turn an existing module into recurring revenue.

If you already maintain a Magento 2 module on GitHub or GitLab, listing it on Packagento takes about five minutes. We mirror your tags, handle distribution signing, and route paid licenses through Stripe Connect, so you can keep shipping the way you already do.