Visibility
Brand reasons
See why AI answers favour or caution against your brand and each tracked competitor: pricing, features, support and ten other reasons, each counted as a strength or a weakness with the quote behind it, grouped into six categories or broken out by persona.

The screenshot shows the Quillstone demo project, whose answers were analysed for reasons on development data.
What this screen shows
Open Brand reasons from
the Reasons tab under Brand perception in the sidebar. It shows why AI answers
favour or caution against each brand you track: for your brand and each
active tracked competitor, how many answers gave each reason as a strength or
as a weakness, with the quote behind every count
(api/services/brand_reasons.py#brand_reasons_for_project).
Sentiment trends tells you how an answer frames a brand (positive or negative, top recommendation or warned against). This screen tells you what the answer said the brand is good or weak at, such as pricing, features or support.
How reasons are extracted
Every completed answer already goes through one model call that lists the
brands it names, with their sentiment and recommendation role. That same
call now also returns, for each brand, up to three reasons the answer itself
gives for its view of that brand. No extra model call is made
(api/services/sentiment.py#SENTIMENT_RESPONSE_SCHEMA).
Each reason has three parts:
- A label from the same thirteen used for citation framing: pricing,
features, ease of use, integrations, scalability, support, documentation,
trust, security, market presence, open source, performance, and Other
reason when the answer gives a reason that fits none of them
(
api/services/sentiment.py#FRAMING_REASON_VALUES). - A direction: a strength when the answer presents it as a reason to
choose the brand, a weakness when it is a reason for caution or against
it (
api/services/sentiment.py#BRAND_REASON_POLARITY_VALUES). - A quote copied from the answer. Before a reason is saved, its quote is
looked up in the saved answer text; a reason whose quote cannot be found
there is discarded, not stored. Quotes are cut to 300 characters
(
api/services/brand_mentions.py#REASON_EVIDENCE_LIMIT).
A brand that is only named, with no reason given, gets no reasons. A brand
has at most one reason per label and direction in one answer, and at most
three in total (api/services/brand_mentions.py#MAX_REASONS_PER_MENTION).
The label and direction are the extraction model's reading of the answer. The quote lets you check that reading; it is not a verified fact about the brand and does not show what caused an engine to rank it.
Answers analysed before this feature
Reasons come from the extraction step, so an answer has them only if it was
analysed after this feature shipped. An answer is analysed once, normally
soon after it is collected; answers analysed earlier are not re-analysed,
so they have no reasons. They are counted separately as not analysed,
never as answers with no reasons
(api/services/brand_mentions.py#PRE_REASON_VERSIONS). A window that reaches
back before this feature shipped therefore shows a smaller analysed count
than the answers that named each brand.
Choose the population
The filters match Sentiment trends: the
filter bar's
7, 28 or 90 day window ending yesterday (28 by default) and its engine,
tag, country, persona and language chips, then one collection channel and
the current prompt intent, buyer stage and theme
(api/routers/brand_reasons.py#ACCEPTS,
api/services/brand_reasons.py#brand_reasons_for_project). The persona
chip narrows to one persona, archived ones
included, or to General, and the language chip to one
language or As written.
Channels are never pooled: a channel is one provider, platform, surface
and collection method, as recorded on each answer, and with an engine
chosen the channel list offers only that engine's channels
(api/services/sentiment_population.py#execution_scope,
#channel_conditions). Only
completed answers whose brand extraction has finished are included.
What the counts mean
Each column is a brand family: your brand or a tracked competitor, together with its sub-brands, including archived ones. Paused competitors are not shown.
- Answers analysed is the number of answers in the population that named the family and were analysed for reasons.
- Strengths and weaknesses count answers, not quotes. An answer that gives pricing as a strength for both a brand and its sub-brand counts once for that family.
- Rate = answers with that reason and direction ÷ answers analysed × 100. For example, pricing given as a strength in 12 of 40 analysed answers is 30%. A dash means the family has no analysed answers.
One answer can count as both a strength and a weakness for the same label, for example "the cheapest option, but watch the add-on fees". The rates do not add up to 100% across labels, because an answer can give several reasons or none.
Fewer than 30 analysed answers for a family is marked provisional
(api/services/brand_metrics.py#MIN_OBSERVATIONS). This is a sample-size
flag, not a confidence interval.
Rows where every family has zero strengths and zero weaknesses are hidden until you choose Show all 13 reasons. A zero count is shown as plain text rather than a link, since it has no quotes to open.
Group by category
Select Group by category to fold the 13 reasons into six fixed groups.
Every reason belongs to exactly one group, so a category's count is not the
sum of its reasons: an answer citing both a features weakness and an
integrations weakness for the same brand in the same window counts once
toward capability, not twice
(api/services/sentiment.py#REASON_CATEGORIES,
api/services/sentiment.py#reason_category_case). The rate underneath each
category count still divides by the same analysed-answers denominator as
the individual-reason view.
| Category | API value | Reasons |
|---|---|---|
| Price and value | price_value |
pricing |
| Product capability | capability |
features, integrations, scalability, performance, open source |
| Experience | experience |
ease of use, documentation, support |
| Trust and risk | trust_risk |
trust, security |
| Market standing | market_standing |
market presence |
| Other | other |
unknown |
By persona
For one brand family, select View by persona to see one row per
audience: General, included only when it has at least one answer naming
the family, plus every persona in the same
position, archived personas included. Each row carries that audience's
analysed answers, positive and negative share, and, on plans with this
entitlement, its top strength and top weakness reason by rate
(api/services/sentiment_population.py#by_persona_rows). This uses the
same window, filters, channel and segment as the rest of the screen; fewer
than 30 analysed answers for an audience is marked provisional, the same
threshold used above.
When there is nothing to count, the screen says which case applies: no completed answers in the window, no tracked brand family, analysed answers that name no tracked brand, answers that have not been analysed for reasons yet, or answers that were analysed but gave no reason for any tracked brand. The last case still shows each family's analysed and not-analysed counts.
Read the quotes
Select a count to list its quotes under Evidence, filtered to that
brand family, label and direction. Each row shows the brand that was named
(a sub-brand shows its own name), the label, the direction, the quote, the
date and a link to the prompt and its collected outputs. The list shows 25
quotes per page, newest first
(api/services/brand_reasons.py#EVIDENCE_PAGE_SIZE). Clear the filter to
see every quote in the population.
Access
Any current project member can read this screen. It is available when the
project owner's plan includes brand reasons: standard Starter, Growth and Pro
presets do, Free and Trial do not
(api/services/entitlements.py#standard_entitlements,
api/routers/brand_reasons.py#_project_with_access). Without it the screen
shows an upgrade message instead. Reasons are extracted for every plan's
answers, so a project that upgrades sees reasons for answers analysed since
this feature shipped, not only since the upgrade.
Export, API and MCP
The brand_reasons file export, the customer API's GET /brand-reasons
route and the list_brand_reasons MCP tool all read this same underlying
data, one row per reason on a completed answer, gated by the same
Brand reasons entitlement as this screen. See
Exports and activity,
Customer API and keys and
MCP connector.
How this differs from Objections and Attributes
The weaknesses on this screen are the ones AI answers to your tracked
prompts happen to give, and tracked prompts do not usually ask for
downsides. Objections is a separate
weekly study that asks each engine directly why a buyer might not choose
your brand and each active tracked competitor
(api/services/objections/question.py#build_question), groups the
answers by meaning rather than by these thirteen labels, and scores each
objection by how early the engines list it. It does not read or change
the reasons counted here, and nothing on this screen comes from it.
Attributes is another separate weekly study.
It asks each engine what each brand is best known for, good or bad, and
which brands it names for a chosen quality
(api/services/attributes/question.py#build_association_question,
#build_market_question). Its attributes have no strength or weakness
side, and nothing on this screen comes from it either.
What this does not include
- No re-analysis of past answers, and no reasons for brands you have not tracked (their reasons are stored but not shown).
- No separate rows for sub-brands on this screen; a sub-brand's reasons count toward its family, and its name appears on its quotes.
Related
- Sentiment trends
- Objections: the weekly study that asks engines directly for the downsides of each brand
- Attributes: the weekly study of what engines say each brand is known for
- Compare vs. competitor: the reason and category rates this comparison locks without this entitlement
- Personas: the audiences the persona chip filters by, and the By persona view on this screen
- Brands and sub-brands
- Competitors
Last verified 2026-09-27