Visibility
Attributes
A weekly study that asks each chat engine on your plan, and ChatGPT (app), what your brand and each active tracked competitor are best known for, then which brands it names for each chosen quality, and shows each brand's association and market prominence side by side, with the quotes behind them and what changed since the last comparable study.

The screenshot shows the Quillstone demo project on development data.
What this screen shows
Open Attributes from the Attributes tab under Brand perception in the sidebar. It answers two questions about your brand and each active tracked competitor, from a separate attribute study, asked of the chat engines on your plan and ChatGPT (app), rather than from your tracked prompts:
- What is the brand known for? The qualities AI engines associate with the brand when asked about it directly, such as "Ease of use" or "Pricing transparency", each with an association score and how many engines named it.
- Who is known for each quality? For the attributes the study asked about, which brands engines name when asked who is best known for that quality, with the selected brand's market prominence, its position among the brands named, and the leader, which can be a brand you do not track.
The two are shown side by side because they can disagree: every engine can
describe a brand as fast and still name another brand first when asked who
is known for speed. For each attribute the screen also shows what changed
since the previous comparable study, and each row opens to the quotes
behind it (api/services/attributes/read.py#attributes_view,
api/schemas/attributes.py#AttributeRow, #MarketOut).
The two questions each engine is asked
A study has two phases, each with its own fixed question.
Phase 1, known for. For each brand, every engine is sent this question,
with the brand's name and domain filled in
(api/services/attributes/question.py#build_association_question):
What is {name} ({domain}) best known for among {market}? List the
qualities and characteristics people most associate with {name}, good or
bad, from most to least prominent, one per line, and cite sources where
you can.
The " among {market}" part is included only when the study has a market (see
Your market); your market is used for the competitors too.
Name, domain and market are trimmed to 120, 255 and 120 characters
(api/services/attributes/question.py#MARKET_LIMIT).
Phase 2, the market. For each attribute chosen for the market question
(see Which attributes are asked about the market),
every engine is sent this question
(api/services/attributes/question.py#build_market_question):
Among {market}, which brands are best known for {attribute}? Name the
brands most associated with {attribute}, from most to least, one per line,
and cite sources where you can.
The attribute is its label trimmed to 80 characters, with only its first
letter lower-cased, and only when the second letter is lower case: "Ease of
use" is asked as "ease of use", while "AI coding" and "GDPR compliance"
keep their capitals
(api/services/attributes/question.py#_attribute_in_sentence). The market
is trimmed to 120. Your brand is not named in this question, so the
engine is not steered toward it. The market is fixed on the study when the
study is created and used for every question of that study, and each
question is stored when it is created, so editing your market or project
during a study changes nothing already asked
(api/services/attributes/studies.py#create_study,
api/services/attributes/pipeline.py#start_ranking, #run_answer).
Both questions are written in English. When your project has a default
language (see
Languages and templates),
the study is created in that language, and each engine also receives the
same plain-language instruction to answer in that language that a tracked
prompt in that language receives, for both phases. ChatGPT (app) gets it
added after the question, because a language setting alone does not change
the language it answers in (see
What reaches ChatGPT).
With As written, nothing is added
(api/services/brand_study/question.py#question_search_context,
#study_prompt). No city or persona is sent, and no country except to
ChatGPT (app), which is always asked with the United States as its country
(api/services/brand_study/question.py#STUDY_APP_COUNTRY).
Each question carries a version number
(api/services/attributes/question.py#ASSOCIATION_QUESTION_VERSION,
#MARKET_QUESTION_VERSION). Studies are only compared with studies that
asked the same versions of both questions in the same language about the
same market.
Which brands and engines
Phase 1 asks about your brand, by your project's name and domain, and then
each active tracked competitor, by its name and domain, in the order the
competitors were added, up to your plan's competitor allowance. A
competitor saved without a name is asked about by its domain. Paused
competitors are not asked about, and sub-brands are not asked about
separately (api/services/brand_study/engines.py#study_subjects).
Every brand is asked of every engine your plan includes that is active and
currently available when the study is created, except Google AI
Overviews, Google AI Mode and Gemini (app), three of the four engines
collected through DataForSEO, which receive only the question as written,
with no instruction to answer in the study's language. ChatGPT (app), the
fourth, is asked, with the language instruction added to its question as
described above
(api/services/brand_study/engines.py#study_engines_for_plan,
#STUDY_EXCLUDED_PROVIDERS,
api/services/attributes/studies.py#create_study; see
Engines and measurement).
Each (brand, engine) pair is one answer. Each answer keeps the brand's name
and domain as they were when the study was created
(api/models/attribute.py#AttributeAnswer).
Phase 2 sends each chosen attribute to the same engines phase 1 asked,
whether or not they answered there; each (attribute, engine) pair is one
answer (api/services/attributes/pipeline.py#_association_scores,
#start_ranking).
When studies run
Studies run automatically once a week, with no setting to turn on. A
systemd timer (discoveredby-cli@enqueue-attribute-studies.timer) runs
every Thursday at 05:00 UTC and starts a study for every active project
whose owner's account is active and whose owner's plan includes
Attributes, unless the project already has a study running or one was
created in the last 6 days (api/cli.py#cmd_enqueue_attribute_studies,
api/services/attributes/studies.py#enqueue_scheduled_studies,
#SCHEDULE_INTERVAL). A project whose plan has no available engines is
skipped.
Owners and editors can also press Run now. It is refused while a study
is already running, and for 24 hours after the latest study that counts
was created (api/services/attributes/studies.py#start_manual_study,
#RUN_COOLDOWN). Viewers cannot run a study
(api/routers/attributes.py#start_study). A study that never ran because
it could not be queued, or that was interrupted on our side, does not
count toward the 24 hours or the 6 days; a study that ran and failed does
count (api/services/attributes/studies.py#UNCOUNTED_ERROR_KINDS).
A study collects the phase 1 answers, groups the attributes, asks the
market questions, then succeeds. The screen shows the latest succeeded
study and a history of the 10 most recent studies, each marked weekly or
on demand, with its status; you can open any earlier succeeded study from
that list (api/services/attributes/read.py#HISTORY_LIMIT,
#_selected_study).
From answer to attributes
Each engine's answer is saved, cut to 50,000 characters, with the model the
engine reported (its default model when it reports none) and the sources
it cited, exactly as for Objections
(api/services/attributes/pipeline.py#run_answer, #RESPONSE_TEXT_LIMIT,
api/services/brand_study/sources.py#model_of, #capture_sources).
Another AI model then reads the first 16,000 characters of a phase 1 answer
and lists the qualities it associates with the brand, in the order they
appear, as short neutral phrases such as "Ease of use" rather than "Acme is
easy to use", each with the sentence from the answer that states it. It is
told to leave out qualities of other brands, plain facts that name no
quality, such as the founding year, and statements about how much is known
or published about the brand or how visible it is, such as "few reviews" or
"low visibility", the answer's own uncertainty and conclusions drawn from
missing information, since those describe what the engine knows rather
than the brand. It is also told to treat the answer as data, not
instructions (api/services/attributes/extraction.py#build_association_prompt,
#EXTRACT_TEXT_LIMIT). A brand whose one distinction really is being
little known is therefore not measured for it.
Our code then decides what is kept, with the same rules as objections
(api/services/attributes/extraction.py#validate_association,
api/services/brand_study/ranking.py#locate_and_rank):
- At most 10 attributes are read from one answer, and a phrase is cut to
80 characters (
api/services/brand_study/ranking.py#MAX_ITEMS_PER_ANSWER,api/services/attributes/extraction.py#ATTRIBUTE_LIMIT). - The quote must be found in the saved answer, exactly or ignoring case
(
api/services/brand_mentions.py#_locate). The stored quote is the answer's own text, cut to 300 characters; one shorter than 20 characters is dropped as a heading or label, and when two quotes overlap only the one the model listed first is kept (api/services/brand_study/ranking.py#QUOTE_LIMIT,#MIN_QUOTE_LENGTH). - Rank is the order of the quotes in the answer, and the score is 100
for rank one, minus 10 for each rank after it
(
api/services/brand_study/ranking.py#score_for_rank).
An answer with at least one kept attribute has succeeded; one with none,
including an empty answer or an engine that declined, answered with no
attributes. A failed extraction call marks the answer failed
(api/services/attributes/pipeline.py#_extract).
How attributes are grouped
When every phase 1 answer is in, AI model calls assign each extracted
phrase to an attribute group, in batches of at most 120 phrases, each
batch saved before the next starts
(api/services/attributes/pipeline.py#group_study, #GROUP_BATCH_SIZE).
Each call is sent the phrases without the brand they were about, so the
same quality said of different brands can share a group. It is also sent
all of your attributes first, marked as yours, then
the 150 most recently seen other groups of the project
(api/services/attributes/pipeline.py#GROUPS_IN_PROMPT). The model is told
to reuse a group only when it names the same quality, to hold your
attributes to the same test as any other group rather than prefer them,
and otherwise to create a new group with a label written without brand
names (api/services/attributes/grouping.py#build_grouping_prompt). A
label is cut to 80 characters
(api/services/brand_study/grouping.py#LABEL_LIMIT).
Our code checks each batch before saving it: every phrase must be
assigned exactly once, to a group of this project that was sent or to a
new group the model defined
(api/services/brand_study/grouping.py#validate_grouping). If the output
fails that check the model is asked once more with the problems; if that
fails too, or a call fails, the study fails. A new group whose label
matches an existing group's label, ignoring case, is merged into it,
including one of your attributes added while the batch was being grouped
(api/services/attributes/pipeline.py#_apply_plan).
Groups belong to the project and are shared by every brand and every later study, which is what makes comparing brands and studies possible. The grouping and the labels are an AI model's judgement and wording: two similar qualities can land in separate groups, or a group can be broader than you would draw it. The quotes under each attribute are the check on that.
Your market
The market is a short phrase for what your project is and who it is for,
such as "book-writing software for authors", which both questions name.
Owners and editors set it under Your market on the Attributes screen:
at most 120 characters on one line, with runs of spaces made one, and an
empty value removes it (api/services/attributes/market.py#clean_market,
#MARKET_LIMIT, #set_market, api/routers/attributes.py#set_market). A
market that names your brand or a tracked competitor, by any of its names,
is refused with "Leave brand names out of the market."
(api/services/attributes/market.py#MARKET_NAMES_A_BRAND). Setting it is
recorded in the project's activity
(api/services/attributes/market.py#set_market). Viewers can see it but
not change it.
The market is not your project's business type, which is one of a short
list of categories such as SaaS; neither question uses the business type.
Each study keeps the market it was created with and shows it as "Market
asked", so a change applies from the next study
(api/models/attribute.py#AttributeStudy,
api/schemas/attributes.py#StudyDetail).
Your site research also suggests a market: the product category a buyer
would compare you within, in a few words and without brand names
(api/services/research.py#business_profile_schema,
#business_profile_prompt). The suggestion is kept only when it passes the
same rules as a typed market, brand names included; otherwise it is dropped
(api/services/attributes/market.py#clean_suggested_market). The newest
kept suggestion is the one used
(api/services/attributes/market.py#latest_market_suggestion). While your
market is empty, the Attributes screen fills the market box with it, labelled
as suggested from your site research, and saving it works as for a typed
market (api/services/attributes/read.py#attributes_view,
frontend/src/routes/(app)/sentiment/attributes/+page.svelte#suggestedMarket).
A study that starts while your market is empty saves the suggestion as your
market and asks it, if it still leaves out every brand you track, and the
project's activity records it with no user
(api/services/attributes/studies.py#create_study,
api/services/attributes/market.py#adopt_market_suggestion). It is then
your market like any other, and owners and editors can change it. With no
suggestion, studies skip the market question until someone sets one. A
project gets its first suggestion from its next research run.
The wording decides what market prominence means. A broad market such as "software" puts your brand among every well-known software brand, where a small brand is rarely named.
Your attributes
Owners and editors can add up to 10 attributes the project wants to be
known for, each a label of 1 to 80 characters on one line, with an optional
description of up to 240 characters
(api/services/attributes/custom.py#add_custom, #MAX_CUSTOM_ATTRIBUTES,
#LABEL_LIMIT, #DESCRIPTION_LIMIT). A label that names your brand or a
tracked competitor, by any of its names, is refused with "Leave brand names
out of the attribute." (api/services/attributes/custom.py#NAMES_A_BRAND).
Adding a label that matches an existing attribute group, ignoring case,
makes that group one of yours, keeping its history.
Removing one of your attributes only takes the mark off: the group and its
history stay as an ordinary attribute
(api/services/attributes/custom.py#remove_custom). Adding and removing
are recorded in the project's activity
(api/services/attributes/custom.py#_audit). A change applies the next time a
study groups its attributes and chooses what to ask, which includes a
study still collecting answers when you make it
(api/services/attributes/pipeline.py#group_study, #start_ranking).
Viewers can see your attributes but not change them
(api/routers/attributes.py#add_custom_attribute,
#remove_custom_attribute).
Your attributes are offered to the grouping model first, and the engines'
wording is grouped into them when it names the same quality, by the same
test as any other group; they are always asked in the market question (see
the next section). Each of them is listed on the
screen even when no engine associated it with the selected brand
(api/services/attributes/read.py#attributes_view).
Which attributes are asked about the market
When grouping finishes, our code chooses the attributes for phase 2, in
this order (api/services/attributes/selection.py#select_market_attributes):
- Every one of your attributes, in the order their attribute groups were created (at most 10).
- Up to 4 of your own brand's strongest other attributes in this study,
highest association first (
#OWN_TOP_ATTRIBUTES). - The strongest remaining attributes of any brand in the study, by the
highest association any brand has, until 8 attributes beyond yours are
chosen (
#DISCOVERED_MARKET_ATTRIBUTES).
So a study asks about at most 18 attributes. Step 3 is what brings in a quality only a competitor is known for. Ties go to the label in alphabetical order, and an attribute no brand was associated with is only asked when it is one of yours.
Before choosing, any attribute whose label names your brand or a tracked
competitor as a whole word is left out, whether a model or a person wrote
it, so no brand name reaches the market question. This can happen to one
of your attributes too, for example when a competitor with that name is
added later (api/services/attributes/pipeline.py#start_ranking,
api/services/attributes/brands.py#names_tracked_brand). A name that is
only a brand's domain alias, such as "close" from close.com, does not count
here or in your attribute labels, since it is also an ordinary word
(api/services/attributes/brands.py#_domain_only_names); in your market
it does count (api/services/attributes/market.py#set_market). The chosen
attributes and their labels are stored on the study, so renaming or
merging a group later never changes what a study asked
(api/models/attribute.py#AttributeStudy).
Phase 2 needs a market, because the market question names one. If the
study was created without one, or no attribute is chosen, phase 2 is
skipped: the study succeeds with its phase 1 results and records why,
which the screen shows, with a link for owners and editors to set the
market (api/services/attributes/pipeline.py#_skip_market,
api/schemas/attributes.py#StudyDetail).
From answer to market ranking
An AI model reads the first 16,000 characters of each market answer and
lists the brands it names as associated with the attribute, in the order
they appear, each with the line or sentence that names it. It is told to
leave out brands mentioned only as not having the quality
(api/services/attributes/extraction.py#build_ranking_prompt). Our code
then decides what is kept
(api/services/attributes/extraction.py#validate_ranking):
- At most 10 brands are read from one answer, and a name is cut to 120
characters after quote marks, emphasis marks and a pair of brackets
around it are removed (
api/services/attributes/extraction.py#BRAND_NAME_LIMIT). - The quote must be found in the saved answer; a short line such as "Asana" is a valid quote.
- The name must appear inside the quote as a whole word, ignoring case, or the brand is dropped: "Box" is never read out of "Dropbox".
- Rank is the order of the names in the answer, scored 100 for rank one minus 10 for each rank after it. The name stored is the answer's own spelling at that position.
- When two names overlap in the answer, such as "Acme Cloud" and "Acme" at the same place, only one is kept: the earlier, and at the same position the longer. A brand named twice in one answer keeps its first naming.
Which brand a name is, is decided by our code, never by the model
(api/services/attributes/brands.py#load_matcher, #match,
api/services/brand_families.py#family_roots):
- A name counts as your brand or a tracked competitor when one of that brand's names occurs in it as a whole word, ignoring case. A brand's names are its display name, its aliases, and its active sub-brands' names and aliases, so a sub-brand counts as its family, and "Acme Cloud" counts as Acme when Acme is tracked.
- When names of several brands match, the longest matching name wins. If the longest match belongs to two brands, the name is left untracked rather than guessed.
- Any other name is an untracked brand. Names that are the same apart
from case, spacing and trailing punctuation count as one brand
(
api/services/attributes/brands.py#normalize_brand), shown with the spelling seen most often in the study (api/services/attributes/read.py#_spellings). - Spelling variants of untracked brands are merged when the screen is
read (
api/services/attributes/brands.py#merge_variants). A name whose words begin with every word of a shorter name named in the same study counts as that shorter name: "Reedsy Studio" counts as "Reedsy" when "Reedsy" is named too. When several shorter names fit, as "Reedsy" and "Reedsy Studio" both fit "Reedsy Studio Pro", the shortest wins. One trailing bracket is ignored first, so "Canvas (Instructure)" counts as "Canvas" (api/services/attributes/brands.py#canonical_brand). Your brand and tracked competitors are never merged this way; they are already matched by their names. - A merged brand's score from an engine is its best score among the
spellings in that engine's answer, and each engine counts once in Named
by (
api/services/attributes/read.py#_merged,api/services/brand_study/metrics.py#prominence,#raised_by). It is shown under the shortest name's most frequent spelling without a trailing bracket, so "Google (Google Workspace for Education)" is shown as "Google" (api/services/attributes/read.py#_Brands). For an untracked brand, the market ranking lists the other spellings engines used for it in that attribute as "also named as", leaving out spellings that differ only in case, spacing or trailing punctuation (api/services/attributes/read.py#ranking_view,api/schemas/attributes.py#RankedBrandOut). Positions, the leader and change all count the merged brand once. - The merge has limits. A company and its product merge when both are named: "Google Docs" counts as "Google" in a study where "Google" is named. Different brands that share a first word do not merge unless the shorter name is itself named, so "Proton Mail" and "Proton Drive" stay two brands until an engine names "Proton". Nothing is merged in storage: each naming keeps the name as the engine wrote it.
- A paused competitor is not matched, so its name is untracked. The match is stored when the answer is read, so adding an alias later does not change earlier studies.
- Your brands and their names are read again for each market answer
(
api/services/attributes/pipeline.py#_extract). Pausing or adding a competitor, a sub-brand or an alias during the few minutes a study asks the market questions can therefore key one brand two ways within that study, which splits its prominence.
How sources are linked
Our code links sources to each attribute quote and each brand quote the
same way as for objections: a source is linked when the engine placed its
citation on the quote or in the run of citation markers directly after it
(api/services/brand_study/sources.py#link_sources). Perplexity and Grok
(for its inline citations) record where they cite, so their sources can be
linked. ChatGPT (app) records where each source's link first appears in the
stored answer; the app usually, though not always, writes that link right
after the text it supports, and a source whose link is not found in the
stored answer links nothing. Gemini (API)'s positions are counted in bytes, so they are
usually close for English but land in the wrong place for languages
written in another script. Claude records no position, so its answers show
no sources (api/services/llm.py#_chatgpt_app_answer, #_sonar_marker_citations,
#run_grok, #run_gemini, #run_anthropic). The details, and their
limits, are in
how sources are linked.
A linked source shows where the engine placed its citation; it is not a
check that the page says what the quote says.
What the numbers mean
Association, for the brand selected, over the engines that
answered its phase 1 question (with attributes or with none; an engine
whose answer failed is left out)
(api/services/brand_study/metrics.py#prominence, #raised_by):
- An engine's score for an attribute is its highest score among the phrases grouped into that attribute, and 0 if it answered without it.
- Association is the average of those scores over the answered engines, from 0 to 100, rounded to one decimal. With three engines answering, one listing the attribute first (100), one third (80) and one not at all (0), association is 180 ÷ 3 = 60.0.
- Associated by is how many of the answered engines named it.
Market prominence, for an attribute asked in phase 2, over the engines
that answered that attribute's market question
(api/services/attributes/read.py#_market_row, #ranking_view):
- A brand's market prominence is the same average of its scores in those answers, 0 for an engine that answered without naming it.
- Named by is how many of those engines named the brand.
- Position is 1 plus the number of brands named for that attribute
with a higher market prominence, so "#3 of 7 named" means two brands are
ahead. Brands with the same market prominence share a position: two
brands tied first are followed by a brand in third
(
api/services/attributes/read.py#_positions). A brand no engine named has no position. - The leader is the brand with the highest market prominence, tracked
or not. Ties go to your brand, then to competitors in the order they were
added, then to untracked brands by name
(
api/services/attributes/read.py#_Brands); when another brand has the same market prominence the screen marks the leader as tied (api/schemas/attributes.py#LeaderOut).
A row opens to its evidence: for each engine, the rank, the phrase, the
quote from the answer and its sources, and, for an attribute asked in
phase 2, the full market ranking of every brand named, with each engine's
rank, the name as written, the quote and its sources
(api/schemas/attributes.py#EvidenceOut, #RankedBrandOut,
#RankingEvidenceOut). Above the table, each engine asked about the
selected brand is listed with its model and whether it answered, answered
with no attributes, or failed, with the kind of failure but never the
engine's raw error text (api/schemas/attributes.py#EngineStatus).
If no engine answered for a brand, or no engine answered an attribute's market question, that number is unavailable rather than 0. An attribute the study did not ask about the market has no market figures at all.
The two scores are not comparable with each other. Association comes from a question about one brand, where the engine lists that brand's qualities; market prominence comes from a question about the whole market, where every brand named competes for the same ranks. A high association with a low market prominence means engines describe the brand that way but name other brands first for it; the reverse means engines name the brand for a quality they do not reach for when describing it. Compare each score across brands and across studies, not with the other score.
What changed since the previous study
A study is compared with the most recent earlier succeeded study of the
project that asked the same versions of both questions in the same
language about the same market, where no market matches only no market
(api/services/attributes/read.py#_previous_study).
Association change is computed only over the compared engines: those
that answered for the selected brand in both studies. Market prominence
change is computed only for an attribute asked in both studies, over the
engines that answered that attribute in both. Both studies' figures are
recalculated over those engines alone and the change shown is the
difference in points, so an engine joining or leaving your plan, failing
in one week, or an attribute asked in only one of the two studies does not
make anything look new or gone
(api/services/attributes/read.py#_market_common, #_change).
Two changes to your own setup are not compared either:
- A competitor the earlier study did not ask about reads No comparison for
market prominence, not New. If it was added since, the earlier study
stored its namings under its plain name, as an untracked brand; if it
was beyond your plan's competitor allowance then, its namings were
already matched to it, but it was not one of the brands that study asked
about (
api/services/attributes/read.py#_market_change,api/services/brand_study/engines.py#study_subjects). - One of your attributes that became yours after the earlier study was
created reads No comparison for association, since grouping from then on
can put wording into it that went to another attribute before
(
api/services/attributes/read.py#attributes_view,api/models/attribute.py#AttributeGroup).
What the comparison still cannot tell apart: a name or alias added to a
brand that was already asked about can make that brand read as rising or
new once, because its namings under the new name were untracked in the
earlier study; pausing or deleting a competitor between studies makes its
name an untracked brand from then on, since only active competitors are
matched, so in the market ranking it can read as New under its plain name
(api/services/attributes/brands.py#load_matcher,
api/services/attributes/read.py#_market_change).
For market change, spelling variants are merged over the names of both
studies together (api/services/attributes/read.py#_previous_market), so
a brand named "Reedsy Studio" last time and "Reedsy" this time is compared
as one brand, rising, falling or steady, rather than read as new in one
study and gone from the other. When the earlier study named a shorter name
that two brands of this study both begin with, such as "Proton" then and
"Proton Mail" and "Proton Drive" now, both read No comparison, since the
earlier figure cannot be split between them
(api/services/attributes/read.py#_market_change).
The change statuses use the same 15-point threshold as objections
(api/services/brand_study/metrics.py#change_status, #CHANGE_THRESHOLD):
- New: the compared engines did not name it last time and do now.
- Rising or Falling: it moved by 15 points or more, up or down, over the compared engines.
- Steady: it moved by less than 15 points.
- Gone: the compared engines named it last time, and no engine that answered this time names it.
- No comparison: there is no earlier comparable study, no engine answered in both, no compared engine named it in either study, (for market prominence) the attribute was not asked in both or the brand was not asked about in the earlier study, or (for association) the attribute became one of yours since.
Something a compared engine named last time, and that only an engine not being compared names this time, reads as falling or steady over the compared engines, not as gone.
An attribute that is gone from the selected brand's association moves out
of the table to a separate list of attributes no longer associated, with
its earlier association over the compared engines. One of your
attributes, or one asked in the market question, stays in the table
instead, marked Gone (api/services/attributes/read.py#attributes_view).
When a study or an answer fails
One failed answer does not fail the study. A study fails when every phase
1 answer failed, when grouping fails, when it could not be queued, or when
it is still collecting, grouping or asking the market questions with no
progress for 90 minutes (api/services/attributes/pipeline.py#finalize_association,
api/services/attributes/studies.py#expire_interrupted,
api/services/brand_study/engines.py#INTERRUPTED_AFTER). Market answers
never fail the study: when the last one is in, however many failed, the
study succeeds (api/services/attributes/pipeline.py#finalize_market).
A failed study's results are not shown, including one interrupted while
asking the market questions. When the newest study failed, the screen
keeps showing the last succeeded one and notes the failure
(api/services/attributes/read.py#attributes_view).
Access
Any current project member can read this screen, viewers included. It is
available when the project owner's plan includes Attributes: standard
Starter, Growth and Pro presets do, Free and Trial do not
(api/services/entitlements.py#standard_entitlements,
api/routers/attributes.py#read_attributes). Without it the screen shows
an upgrade message, no studies run, and your attributes cannot be changed.
Stored studies are kept and become readable again if the plan returns.
Only owners and editors can press Run now, set the market or change your
attributes (api/services/attributes/read.py#RUNNERS,
api/routers/attributes.py#set_market).
Export, API and MCP
The same results are available as the attributes file export, through
the customer API's GET /attributes route with the attributes:read
permission, and through the list_attributes MCP tool, each also gated by
the Attributes entitlement
(api/services/exports/attributes.py#COLUMNS,
api/services/customer_api.py#attributes_page,
api/services/customer_mcp.py#list_attributes). Their rows come in two
measures: association, one row per attribute phrase in each phase 1
answer, and market, one row per brand named in each market answer, each
with its rank, score, attribute, quote and source URLs, from succeeded
studies only. Market rows give each brand as the engine wrote it
(api/services/exports/attributes.py#market_statement); spelling variants
are merged only on the screen. See
Exports and activity,
Customer API and keys and
MCP connector.
How this differs from Brand reasons and Objections
Brand reasons counts the reasons your tracked prompts' answers give for or against each brand, and Objections asks engines directly for each brand's downsides. Both measure why engines favour or caution against a brand. Attributes measures something else: what engines say a brand is known for, good or bad, and which brands they name for a quality. An attribute has no positive or negative side; "Expensive" is an attribute like any other.
Study answers are kept apart from your tracked prompts' answers
(api/models/attribute.py#AttributeAnswer). They use no prompt slot and
change no visibility metric, sentiment figure, Brand reasons count,
Explorer result or alert.
What this does not include
- No alerts or emails when an attribute appears or moves.
- No editing, merging, renaming or hiding of attribute groups the model created; only your attributes can be managed.
- No location: studies are not run per country or city (ChatGPT (app) is always asked with the United States as its country), and no persona is used.
- No separate study of a sub-brand; its names count toward its family.
- No suggested market: the market is what an owner or editor types, and nothing fills it in or derives it from your business type.
- No re-running of a stored study, no backfill of weeks before the feature, and no deleting of studies from the app.
Related
- Objections: the weekly study that asks engines for each brand's downsides
- Brand reasons: reasons for and against each brand in your tracked answers
- Competitors: which competitors a study asks about
- Brands and sub-brands: the names and aliases used to match brands in the market ranking
- Languages and templates: the default language a study uses
- Engines and measurement
- Plans and limits
Last verified 2026-09-29