- Brand
- Peec AI
- Category
- Data & Analytics
- Primary Subcategory
- AI Search & LLM Visibility (AEO/GEO)
Integration details
Description
Monitor and analyze your brand's visibility across AI search engines. Track your visibility, sentiment, and share of voice and compare to competitors.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Primary Subcategory
- AI Search & LLM Visibility (AEO/GEO)
- Secondary Subcategories
- None listed
- Brand
- Peec AI
- Access
- Account required
- First tracked
- 2026-08-28
- Tool count
- 114
- Geography
- US
The Primary Subcategory used for this profile’s headline score.
Other Subcategories where the Integration is listed.
Your score is coming
ChatGPT now suggests Plugins on its own when they match a user's request.Your Plugin Discovery Score measures how often yours appears, and it will show here as soon as it’s ready.
What discovery looks like

Get alerts for Peec AI
Get updates when Peec AI’s Discoverability Score or category rank changes.
Competing in ChatGPT AI Search & LLM Visibility (AEO/GEO)
View Category114 tools agents can invoke
Resolve prompt suggestions listed by list_prompt_suggestions, in one pass over a reviewed set: ids in accepted_ids become tracked prompts and promote their topics into the project, ids in rejected_ids are deleted from the review list. Pass either or both, up to 50 ids in total. Rejecting never touches tracked prompts, since a suggestion has produced none until accepted; a topic left with no suggestions is cleared with them. The accepted set is checked against the project's remaining prompt allowance as a whole and refused as a batch when it does not fit — trim it and retry rather than splitting across calls, and note that a refused accept also leaves the rejections unapplied. Returns a count per outcome, any ids that matched no suggestion, and any allowance warning. Confirm with the user before calling.
finalize_prompt_suggestions
Archive up to 50 prompts (sets is_archived = true) so they stop running while keeping their chats and history intact. Prefer this over delete_prompts when the data should be retained. Returns a count of archived prompts plus any skipped (not found) or rejected items. Confirm with the user before calling.
archive_prompts
Assign a built-in classification (Corporate, Competitor, Editorial, Institutional, Other, Reference, UGC, You, Related) or the name of a custom domain classification to a domain. Overrides any heuristic classification. The override applies to the whole root domain, including its subdomains. If the name you pass matches an existing custom classification, the custom one is used — to force a built-in with the same name, pass its enum value (e.g. "OTHER"). Confirm with the user before calling. Returns { success: true } once the override is saved.
assign_domain_classification
Assign a built-in classification (Homepage, Category Page, Product Page, Listicle, Comparison, Profile, Alternative, Discussion, How-To Guide, Article, Review, Other) or the name of a custom URL classification to a URL. Overrides any heuristic classification. The override applies to the URL in its normalized form, so it matches the same page regardless of trailing slashes, query-parameter order, or http/https scheme. If the name you pass matches an existing custom classification, the custom one is used — to force a built-in with the same name, pass its enum value (e.g. "OTHER"). Confirm with the user before calling. Returns { success: true } once the override is saved.
assign_url_classification
Write up to 50 actions of the customer's own in one call, so work Peec did not suggest is tracked beside the work it did — same list, same statuses, same filters. This is for work the customer has decided to do. It does not itself change what the engines say, and writing an action does not make Peec do anything: the steps are the customer's to carry out. `kind` decides the action's type and group, which is what files it beside the generated ones, and `steps` is the work to do — a step naming a `section` is grouped under that heading. Write every step field in English regardless of the conversation language: the section heading (`section`), step title and step description. A topic or prompt the project does not hold rejects that item alone. Returns the created actions with their new ids, plus any rejected items. Confirm the wording with the user before calling.
create_actions
Add custom attributes to the brand-perception Market view — the same edit the Add attribute button next to Manage attributes makes. Use it when the user wants to track a quality AI is not yet measured on, or asks whether they can add their own attribute: they can, and this is how. Each new attribute starts with no terms under it. A run is queued for the batch, so its market prominence scores appear within a few minutes rather than on the next scheduled run; do not report scores for it until a later read returns them. Names are matched case-insensitively against the project's existing attributes: one that already exists comes back under skipped instead of being added. A project holds at most 10 custom attributes, and a call that would exceed that adds nothing and returns an error naming the limit. This is not the tool for renaming or merging attributes, or for moving a term between them; that is edit_brand_perception_attribute_clusters. Confirm the exact names with the user before calling. Returns created (each with its cluster_id and name) and skipped (name and reason) when any were skipped. Verify with list_brand_perception_attribute_clusters afterwards: the new attributes are listed with is_custom true.
create_brand_perception_attribute_clusters
Create up to 50 brands (competitors or own) in a project in one call. Returns the created brands with their new ids, plus any skipped items. After creation, call list_brands to confirm the requested brands exist before reporting success, even when they appear in this tool's created list. Duplicates are matched case-insensitively on name. A project can track at most 200 brands total (own + competitors); a call that would exceed this fails.
create_brands
Create product categories. Each item needs a name and an optional parent_id — omit it for a top-level category, or pass another category's id (use list_categories to find it) to nest it underneath. A name must be unique among its siblings. Items apply in order. Returns per-item results { created, rejected } — the batch never fails as a whole. Rejection reasons: parent_not_found, name_conflict. Confirm with the user before calling — this mutates project data.
create_categories
Define a new custom domain classification on a project. This creates the classification entity — it does not assign it to any domain (use assign_domain_classification for that). Confirm with the user before calling. Returns the created classification as { name, color }.
create_domain_classification
Define a new custom URL classification on a project. This creates the classification entity — it does not assign it to any URL (use assign_url_classification for that). Returns the created classification's name, which is what you pass to assign_url_classification. Confirm with the user before calling.
create_url_classification
Add up to 50 manual facts for a project in one call. Each fact is a statement about the brand that Peec will use to check claims found in future AI answers. Returns every created fact with its new id. Confirm the exact statements with the user before calling because this mutates shared project data.
create_facts
Create a brand and return its global_brand_id. Use this when list_global_brands finds no match for a brand you need, or when create_products rejects an item with brand_not_found. Returns { id, name }. The returned name is the brand's canonical name and may differ slightly from the name you sent. This is separate from create_brands, which creates brands a project tracks for AI-visibility reporting; the two have different ids and are not interchangeable. Confirm with the user before calling — this creates a brand.
create_global_brand
Create catalog products (source=CATALOG) in a project — the brand's own claimed/uploaded products, as opposed to LLM products that Peec auto-detects in shopping answers. Each item needs a global_brand_id (use list_global_brands to find it by name, or create_global_brand if the brand doesn't exist yet) and a name unique within that brand; description, image_url, per-currency price_override, and category_ids (use list_categories to find category ids) are optional. When products need new categories, build the category tree first with create_categories (parent_id nests, omit for top-level), then pass the returned category_ids here. Returns per-item results { created, rejected } — the batch never fails as a whole. Rejection reasons: name_conflict (name already used in the brand), brand_not_found, category_not_found. Confirm with the user before calling — this mutates project data.
create_products
Create up to 50 projects in the user's company in one call, under the same plan limits and credit pool as creating them in the app. Never assume a project's domain or its allocated_credits: you may suggest values, but confirm each one with the user before calling. Returns the created projects with their new ids, plus any rejected with the reason. A new project starts with no brands or prompts; they are added in that project with create_brands (including the own brand) and create_prompts. Every project except an onboarding one (the first project of a company with no plan yet) needs allocated_credits from the company's unallocated credits; a paying company's first project needs them too. Agency and partner companies can also create pitch projects with is_pitch: those omit allocated_credits and model_channel_ids entirely and run under the company's pitch limits.
create_projects
Create up to 50 prompts in a project in one call. Returns the created prompts with their new ids, plus any skipped/rejected items. Every prompt needs a topic: pick the best-fitting existing topic, or create one with create_topics first. Accepts existing topic_id and tag_ids only — this tool does not auto-create topics or tags. Confirm with the user before calling — this mutates project data and may consume plan credits.
create_prompts
Create up to 50 tags for URLs and domains (source tags) in one call. Use these for labels that are not a page or website type, such as ownership, business role, monetization or a campaign. Returns the created tags with their new ids, plus any skipped items. Names are unique per project, matched case-insensitively. To create prompt tags use create_tags instead.
create_source_tags
Create up to 50 tags in a project in one call. Each tag may specify a group (grouped tags share the group's color, so their color field is ignored). Returns the created tags with their new ids, plus any skipped items. Duplicates are matched case-insensitively on name.
create_tags
Create up to 50 topics in a project in one call. Topics group related prompts. Returns the created topics with their new ids, plus any skipped/rejected items. Duplicates are matched case-insensitively on name. Items beyond the project's topic limit land in `rejected`.
create_topics
Remove up to 50 actions the customer wrote themselves. The removal is permanent and there is nothing to restore from, so confirm with the user before calling. An action Peec generated cannot be removed here and comes back skipped, exactly as a missing one does: decline it with update_actions_status instead, which keeps a record of what was suggested and turned down. Returns a count of deleted actions plus any skipped.
delete_actions
Delete up to 50 brands in a project. Returns a count of deleted brands plus any skipped items (successful items are not echoed back). This is destructive — always confirm with the user before calling.
delete_brands
Delete categories by id (use list_categories to resolve ids). A deleted category's child categories and products move up to its parent (a top-level delete sends children to the top level and its products to Uncategorized). Returns per-item results { deleted, rejected } — the batch never fails as a whole. Rejection reasons: not_found, name_conflict (a child being moved up would clash with an existing sibling name). Confirm with the user before calling — this mutates project data.
delete_categories
Permanently delete a custom domain classification entity. Cascades through the override table — any domains currently assigned this classification fall back to their heuristic classification. To only clear a single domain's assignment, use unassign_domain_classification instead. This is destructive — always confirm with the user before calling. Returns { success: true } once deleted.
delete_domain_classification
Permanently delete a custom URL classification entity. Any URLs currently assigned this classification fall back to their heuristic (default) classification. To only clear a single URL's assignment, use unassign_url_classification instead. This is destructive — always confirm with the user before calling. Returns { success: true } once deleted.
delete_url_classification
Soft-delete up to 50 facts in one call. Deleted facts disappear from the fact list and are excluded from future fact-checking; historical verdicts keep their original fact versions. Returns a deleted count plus skipped items. Call list_facts first, show the user the exact statements, and get confirmation before calling because deletion cannot be undone in the Peec app.
delete_facts
Delete products by id (use list_products to resolve ids). Returns per-item results { deleted, skipped } — ids not present in the project are skipped (not_found). Only delete source=CATALOG products. Deleting LLM-source products is futile — the ingestion pipeline re-creates an LLM product whenever a shopping answer mentions it again. Confirm with the user before calling — this mutates project data.
delete_products
Delete up to 50 prompts in a project. Deletions run asynchronously — returns a count of queued deletions plus any skipped (not found / already deleted) or rejected items (queued items are not echoed back). This is destructive — always confirm with the user before calling.
delete_prompts
Delete up to 50 source tags. Each deleted tag is removed from every URL and domain that carries it. Returns a count of deleted tags plus any skipped items. This is destructive — always confirm with the user before calling.
delete_source_tags
Delete up to 50 user-defined tag groups. By default each group's tags are kept and simply ungrouped; set delete_tags=true on a group to delete its tags and remove them from every prompt. Returns each group with its affected tag count, plus any skipped (not found) or rejected items. This can be destructive — confirm with the user before calling.
delete_tag_groups
Delete up to 50 tags in a project. Removes tag associations from prompts. Returns a count of deleted tags plus any skipped items (successful items are not echoed back). This is destructive — always confirm with the user before calling.
delete_tags
Delete up to 50 topics in a project. Detaches associated prompts (prompts are kept) and deletes any prompt suggestions linked to the topics. Returns a count of deleted topics plus any skipped items (successful items are not echoed back). This is destructive — always confirm with the user before calling.
delete_topics
Fetches and returns the content of a URL for downstream analysis — the markdown Peec extracted from the page. Returns the exact content Peec's pipeline indexed, with no extra fetch. Works for any URL Peec has scraped for the project; you do not need to call get_url_report first. If Peec has no record of the URL it returns 404. Input notes: - url is the full URL, copied verbatim. Trailing slashes and scheme variations change the resolved source ID. - max_length caps the returned content (default 100000 characters). If the stored content is longer, truncated=true — re-request with a higher max_length. Returned fields: - url, title, domain, channel_title: page metadata - classification: domain-level classification - url_classification: page-level classification (HOMEPAGE, LISTICLE, COMPARISON, ...) - content: the page's markdown content. null when the URL is tracked but scraping hasn't completed yet (can take up to 24h). - content_length: original character length before truncation (0 when content is null) - truncated: true if content was truncated to max_length - content_updated_at: ISO timestamp of last scrape, or null if not yet scraped
get_url_content
Rename and delete brand-perception attributes, move terms between attributes and unassign terms from theirs — the same edits the Manage attributes screen makes. An attribute is a grouping the Market view scores; a term is a raw phrasing extracted from AI answers that sits under one. Use those two words with the user: the arguments say cluster_id and attribute for historical reasons, but the user never sees them. Resolve every cluster_id and term with list_brand_perception_attribute_clusters first; both must be copied verbatim. To add a new attribute use create_brand_perception_attribute_clusters instead. Pass any combination of renames, delete_cluster_ids, unassign_terms and reassignments; at least one is required. The whole call is one transaction — if any edit is rejected nothing is applied — and edits run in the order reassign, rename, unassign_terms, delete_cluster_ids however they are listed. So merging two attributes is one call: move every term out of the losing attribute and delete it. Neither deleting an attribute nor unassign_terms permanently removes a term — both unassign it, so it stays visible under unassigned and can be moved into an attribute later. Scores re-aggregate on the next read, so the change is immediate and needs no new scraping run. It rewrites a taxonomy the whole project shares. A rename, a moved term or an unassignment can be undone by repeating the edit in reverse; deleting an attribute cannot — the attribute itself is gone for good, though its terms are not, since they survive as unassigned and can be moved into another attribute. Show the user the exact edits and get their confirmation before calling. Name each term and each attribute at most once per call; repeating one is rejected because the two edits would race. Returns the counts applied. Errors: invalid (a repeated target), not found (unknown attribute or term), conflict (a new name collides with another attribute).
edit_brand_perception_attribute_clusters
Rewrite passages of the article behind a content-optimisation action, up to 50 in one call (target 40 or fewer). Read the article with get_optimize_content first — each `original_text` is a passage quoted from it word for word, and that quote is how the passage is found. Quote a whole passage, not a fragment: the article is edited a paragraph or heading at a time, and a quote spanning two of them matches nothing. `new_text` is the replacement as markdown and cannot be empty — this rewrites a passage and cannot delete one. Asked to cut something, rewrite the passage without it, or say that removing it is an edit the user makes themselves. Every edit lands in one revision, so the call applies as a whole and the article's version moves once. Nothing is written unless all of them can be: a quote matching no passage, matching more than one, or naming a passage another edit in the same call already targets is an error for the whole batch. Which tool does what to a suggestion depends on its `kind`, from get_optimize_content: - `rewrite` — it carries the wording already. Accept or dismiss it with resolve_optimize_content_suggestions. Not yours to retype. - `edit` — it only names what is missing, so putting it in the article means writing the words. That is this tool: rewrite the passage it concerns and set `carries_out_suggestion_id` to its id, which marks it accepted in the same revision so it stops reading as outstanding. Accepting it on its own would tick it off without changing a word. Asked to apply every suggestion, do both halves: resolve_optimize_content_suggestions to accept the `rewrite` ones, and this tool for the `edit` ones, each carrying its id. Asked about a single suggestion, take whichever of those two paths its `kind` calls for. The changes land as tracked edits under the user's name, which they can revert on the Optimize content screen exactly like ones they typed. A passage you have already edited can be edited again: quote its current wording. An edit whose quote no longer matches the article is rejected rather than applied over, so re-read with get_optimize_content after a rejection instead of retrying the same call. This rewrites the customer's live article, so name the passages you are about to change in the sentence before you call it. Change only what they asked for, and say what you changed rather than pasting the new wording for them to copy.
edit_optimize_content
Generate prompt suggestions for a project — the same generation Prompt discovery runs in the app. Generation runs in the background: the call returns {queued: true, generation_id}, which get_prompt_suggestion_generation reads until the run succeeds or fails. List successful results with list_prompt_suggestions, then accept or reject them with finalize_prompt_suggestions. topic_id, prompt_suggestion_id and segment each narrow the run and are mutually exclusive; with none of them, every topic awaiting review is generated for again, replacing its current suggestions — pass a scope unless the user asked for a full refresh. Requires the project's prompt_builder.distribution (branding/intent split), set via set_project_profile. Markets are optional: without them the project's own country and language are used. Spends one of the project's hourly prompt generations, so never call it in a loop. Confirm with the user before calling.
generate_prompt_suggestions
Compose candidate topics for the project from its brand profile — the same composition Prompt discovery runs in the app. Nothing is saved: review the returned names with the user and create the chosen ones with create_topics. Composition already accounts for the project's existing topics, so it proposes only what fills a gap and can return an empty list when the set is already well covered. Requires the project profile to name products and services (set via set_project_profile). Spends one of the project's hourly topic generations, so never call it in a loop. Returns {topics: [name, ...]}.
generate_topics
People who arrived on the project's own website from an AI assistant, measured by the project's connected Google Analytics property. Without group_by: period totals as a single row. With group_by: one row per combination, up to 3 dimensions, sorted by the first requested metric descending. group_by dimensions: - assistant: ChatGPT, Perplexity, Claude, Gemini, Copilot, Grok and ~57 more. Rolls up every host an assistant uses, so prefer it over source. - platform: the company behind the assistants (OpenAI, Google, Microsoft, Anthropic...). - source: the raw referrer host (chatgpt.com). Rows grouped by source also carry assistant and platform, so you never need a second call to name a host. A referrer we do not recognise appears under its own hostname; isolate it with mediums, not assistants. - medium: GA4 session medium. Only ai-assistant and the mediums AI referrers arrive on; non-AI traffic is out of scope for this tool. - country, device: ISO country code, and desktop/mobile/tablet. - event_name: the GA4 event (page_view, purchase). - landing_page: the session's entry page, repeated on every event in that session. - page_path: the page the event fired on, UUIDs collapsed to *. Does not join to landing_page. - host: which of the project's own hostnames. metrics (default: all, minus session_starts when grouping by event_name): - events: GA4 event count. - session_starts: GA4 session_start events. NOT GA4's "sessions" metric. - conversions: GA4 key events. One visit can contribute several, and which events count is the property's own configuration. - revenue: purchase revenue in the property's reporting currency, returned as `currency` on the result. There is no list_event_names or list_countries tool: to discover a dimension's values, call this with group_by set to that one dimension. When building a filter, do not also filter by the dimension you are listing, or every option the user has not already picked disappears. Unknown values come back as "(not set)". Date ranges are capped at 366 days. Returns: {columns, rows, rowCount, total_count, currency}, where total_count is the number of grouped rows the filters match, not a sum of any metric.
get_ai_referrals
Read one action by an id from list_actions: what to do, the content brief when there is one, and the competitor demand behind it. Everything list_actions returns is here too. Always returned: `title`, `description` (the case for the action, with its sources), the authoring fields the customer owns — `kind` (what they wrote it as, null on a generated action), `notes`, `page_url`, `priority`, `assignee_user_id`, `due_on`, `tag_ids`, `repeat`, `time_range`, `language_codes` — `content_brief_outline` (content briefs only — the headline options, meta title and description, the brand's angle and the facts it may claim, the points to cover, and the whole brief as one markdown document), and `opportunity` (the competitor demand a brief answers, also briefs only). A site audit action — `SEO_ISSUE` or `ROBOTS_TXT` — carries neither, and its `description` and steps are the whole fix. An `SEO_ISSUE` in the `crawlability` category means Peec's own audit crawler could not read the site, which pauses Peec's page-level recommendations for it; it says nothing about whether AI engines can reach the site, so never present it as a cause of changes in retrieval or citation. `ROBOTS_TXT` is the action about AI crawlers. Opt in via `fields`, default none: - `steps` — on a template action, the work itself: each step holds one or more options, and an option is a concrete edit with the text to use. On a content brief they are instead the material the brief was written from, labelled by `gap_type` — the fan-out prompts, what communities say, and the sources winning the topic today. - `outline_points` — the content brief section by section: what each one argues, the questions it answers and the evidence behind it. - `impacted_prompts` — the prompts this action affects. On source-correction actions, `own_coverage_score` is the owned domains' share of all citations for that prompt in the action's analysis window; other types use their documented page-coverage score. - `ngrams` — terms competitors use on the topic that the brand's own pages do not. Template actions only. Returns {data}. An id this project has no published action for is an error, whether it belongs to another project, to an action type this tool does not publish for the project, or to nothing at all. On a `CONTENT_OPTIMISATION` action, `get_optimize_content` returns the article, its suggestions and the score.
get_action
Get Peec's opportunity-scored action recommendations for improving brand visibility in AI search engines. **Always call with `scope=overview` first** to see which slices have the biggest opportunity, then drill down into `owned`, `editorial`, `reference`, or `ugc` with the surfaced url_classification or domain. ## Required parameters (read before calling) Every call must include: - `project_id` — the project to analyze. - `scope` — one of `overview` | `owned` | `editorial` | `reference` | `ugc`. **Start with `scope=overview`.** Recommended: - `start_date` and `end_date` (ISO YYYY-MM-DD). Optional — if omitted, defaults to the last 30 days (today − 30d to today). Prefer a 30-day window unless the user asks for a different one. Per-scope extras (the call will fail without them): - `scope=owned` → `url_classification` is **required** (e.g. "LISTICLE"). - `scope=editorial` → `url_classification` is **required** (e.g. "LISTICLE"). - `scope=reference` → `domain` is **required** (e.g. "wikipedia.org"). - `scope=ugc` → `domain` is **required** (e.g. "reddit.com", "youtube.com"). - `scope=overview` → no extras beyond the base params. Use this tool whenever the user asks for recommendations, next steps, what to do, how to improve, "what actions should I take", or any "based on this data, what should I do?" question. Never invent SEO advice. ## Two-step workflow **Step 1 — `scope=overview`:** returns opportunity rollups grouped by `action_group_type` × (`url_classification` | `domain`). These are *navigation metadata*, NOT the recommendations themselves. Use them to find which slices have the largest gap. **Step 2 — drill down:** for each high-opportunity slice, call again with the matching scope (`owned` | `editorial` | `reference` | `ugc`) to get the actual textual recommendations (the `text` column, often with markdown links to examples or targets). Mapping — how to turn an overview row into the follow-up call: - `action_group_type=OWNED`, `url_classification=X` → call `scope=owned, url_classification=X`. - `action_group_type=EDITORIAL`, `url_classification=X` → call `scope=editorial, url_classification=X`. - `action_group_type=REFERENCE`, `domain=Y` → call `scope=reference, domain=Y`. - `action_group_type=UGC`, `domain=Y` → call `scope=ugc, domain=Y`. Worked example — overview returns a row `{action_group_type: "UGC", domain: "youtube.com", opportunity_score: 0.30, ...}`. Follow up with `scope=ugc, domain="youtube.com"` and you get rows like `{text: "Contact [AutoPedia](https://...). Ask them for a collaboration.", group_type: "UGC", domain: "youtube.com", opportunity_score: 3, ...}`. ## Response shape Returns columnar JSON: `{columns, rows, rowCount}`. Each row is an array of values matching column order. **`scope=overview` columns:** - `action_group_type`: OWNED | EDITORIAL | REFERENCE | UGC - `url_classification`: populated for OWNED / EDITORIAL rows (e.g. "LISTICLE", "ARTICLE", "COMPARISON"). `null` for REFERENCE / UGC. - `domain`: populated for REFERENCE / UGC rows (e.g. "youtube.com", "wikipedia.org"). `null` for OWNED / EDITORIAL. - `opportunity_score`: continuous. **Use this to sort and rank** — it's the reliable ordering signal. - `relative_opportunity_score`: 1–3 tier (1=Low, 2=Medium, 3=High). **Use this to label** strength in prose. Too coarse to sort by. - `gap_percentage`, `coverage_percentage`, `used_ratio`, `used_total`: supporting stats. Exactly one of `url_classification` / `domain` is populated per overview row — that's the value to pass to the follow-up call. **`scope=owned | editorial | reference | ugc` columns:** - `text`: the recommendation string; may include markdown links. - `group_type`: OWNED | EDITORIAL | REFERENCE | UGC. - `url_classification`: e.g. "LISTICLE" (may be null). - `domain`: e.g. "youtube.com" (may be null). - `opportunity_score`: continuous — sort/rank by this. - `relative_opportunity_score`: 1–3 tier — label strength with this (1=Low, 2=Medium, 3=High). ## Presenting results After overview + drill-downs, pick the shape that fits: - **Strong signal** (top slice's `opportunity_score` is clearly ahead AND its drill-down returned 2+ rows whose `text` contains a markdown link): one sentence of reasoning tied to the user's question (call out the biggest lever), then 2-3 named slices with 2-3 bullets pulled verbatim from the drill-down `text`. - **Moderate signal**: compact list, one sentence per slice, bullets only where drill-down returned specific targets. - **Low signal** (overview empty or top `opportunity_score` very low): single line, e.g., "Top opportunity: {slice} (Low). Low signal this period; prompts need a few more daily cycles to stabilize." ## Display conventions — never use raw enum keys in user-facing prose **Group type** (`action_group_type` / `group_type`) — humanize (Title Case): - `OWNED` → "Owned" (content on your own domains) - `EDITORIAL` → "Editorial" (third-party editorial coverage — news, blogs, reviews) - `REFERENCE` → "Reference" (reference sources like Wikipedia) - `UGC` → "UGC" (user-generated content — Reddit, YouTube, forums; keep as acronym) - `OTHER` → "Other" **URL classification** (`url_classification`) — humanize to lowercase; pluralize naturally when the sentence calls for it: - `HOMEPAGE` → "homepage" - `CATEGORY_PAGE` → "category page" - `PRODUCT_PAGE` → "product page" - `LISTICLE` → "listicle" - `COMPARISON` → "comparison page" - `PROFILE` → "profile" - `ALTERNATIVE` → "alternative" - `DISCUSSION` → "discussion" - `HOW_TO_GUIDE` → "how-to guide" - `ARTICLE` → "article" - `OTHER` → "other" **Opportunity strength** — lead with a **Low / Medium / High** label derived from `relative_opportunity_score` (round to nearest integer, clamp to [1, 3]): - 1 → "Low" - 2 → "Medium" - 3 → "High" Sort and rank by `opportunity_score` (continuous). **Verbalize** strength with the Low/Medium/High tier above. The raw `opportunity_score` is optional supporting context in parens — never the headline number. **Gap percentage** (`gap_percentage`, 0–1 ratio) — lead with a plain-language qualifier; the raw % can follow in parens when useful: - ≥0.90 → "nearly all missing" - 0.60–0.89 → "wide gap" - 0.30–0.59 → "partial gap" - <0.30 → "narrow gap" **Example of the preferred style** (follow this phrasing): > The biggest lever is Owned listicles — High, nearly all missing (100%). Build listicle-style pages on yourbrand.com that target "best X" queries. > > Secondary: YouTube UGC (Medium, wide gap), Reddit UGC (Medium, partial gap), Editorial listicles (Medium, nearly all missing). Full list: https://app.peec.ai/actions/recommendations. Close with one line: "Secondary opportunities: {slice} ({Low|Medium|High}), {slice} ({Low|Medium|High}). Full list: https://app.peec.ai/actions/recommendations." Use the drill-down `text` field as the source of truth. Never invent recommendations, targets, or names. Sort by `opportunity_score`; label strength via `relative_opportunity_score`.
get_actions
How ready every own brand domain and every competitor brand domain of the project are for AI agents, from Peec's agent readiness audit of each domain. Each site has a level from 0 to 5. A level is reached when every gate check of it and of every level below passes; 0 means a level 1 gate still fails. ceiling is the highest level the audit can award that site. Returns: {own: [{brand: {id, name}, domain, audit, latest_run}], competitors: [{brand: {id, name}, domain, audit}]} audit: {completed_at, level, ceiling, next_level: {level, passed_gates, total_gates, blocking_check_ids} | null, checks?: [{id, title, level, tier, outcome, why, fix, failing_pages}]} latest_run: {id, status, created_at, finished_at, error} | null - blocking_check_ids are the gate checks to fix to reach the next level; next_level is null at the ceiling. - checks is returned only with include_checks=true. tier: gate decides the level; reported (hygiene) and emerging (standards few agents use yet) never block a level. outcome is the most severe across the pages checked; absent, invalid and blocked need fixing. fix says how to make the check pass. failing_pages lists up to 5 URLs the check failed on; it is empty for a check of the whole domain, such as robots.txt. - latest_run is the own domain's newest audit run: status is queued, running, completed, failed or cancelled; error is the failure code or null; finished_at is null while it runs. Its id matches the run_id request_agent_readiness_audits returned, so call this tool again to follow a requested audit. latest_run is null when the domain was never audited. - audit is null when the domain has no audit completed in the last 90 days. own is empty when the project has no own domain. A brand with several domains appears once per domain, with the domain exactly as the brand lists it. This tool never starts an audit; request_agent_readiness_audits queues one for any domain in own. Use this for whether AI agents can read and use the site. For AI crawlers actually visiting it, use get_agent_visits.
get_agent_readiness
Aggregate AI agent visit counts from access logs over a date range. Without group_by: returns total visit count as a single {visits: N} row. With group_by: returns one row per distinct value of the chosen dimension(s), sorted by visits descending. group_by dimensions: - bot_id: break down by bot (use list_bots to resolve names) - response_status: break down by HTTP response status (200, 404, etc.) - request_host: break down by hostname - request_path: break down by URL path Multiple group_by values produce a cross-dimensional breakdown (e.g. bot_id + response_status gives per-bot per-status counts). Use bot_ids to filter to specific bots before grouping. By default, excludes spoofed traffic and includes unverifiable traffic from bots whose operators publish no usable IP ranges. Use verification_statuses to inspect a different scope, including spoofed traffic when explicitly requested. time_bucket: bucket results by time period (hour, day, week, month). Each row will include a `time_bucket` timestamp marking the start of the bucket. Combine with group_by to get e.g. per-bot per-day counts. Returns: {data: [{bot_id?, response_status?, request_host?, request_path?, time_bucket?, visits}], totalCount}
get_agent_visits
How one brand's prominence on each brand-perception attribute has moved over time — the series the Market view's history chart plots. Use it for trend questions (is the brand gaining or losing on an attribute, since when); for the current standing use get_brand_perception_competitive_breakdown or get_brand_perception_attribute_rankings. score is 0-100 — the brand's average prominence across that day's AI answers about the attribute, the same score as the competitive breakdown split by day; answers the brand was absent from count as 0. Display as-is, never multiply by 100. One row per attribute x day, oldest day first; every attribute carries the same days. Attributes are sorted by the brand's score on the latest day, strongest first. limit/offset paginate ATTRIBUTES, not rows, and totalCount is the total attribute count. brand defaults to the project's own brand; pass a competitor's name exactly as the competitive breakdown spells it to read theirs. The response reports the brand it read as brand. Data covers the brand-perception runs of one industry and one target market — pass industry to pick the industry; the target market is always that industry's most recently completed one and cannot be picked. The response reports the scope it used as industry and target_market, and lists the project's other industries under industries when it has more than one — say which industry the numbers describe whenever that field is present. Optionally filter to specific engine channels via model_channel_ids (see list_model_channels). Returns columnar JSON: {columns, rows, rowCount, totalCount}. Columns: attribute, date, score.
get_brand_perception_attribute_history
How the project's own brand ranks against competitors for each brand-perception attribute. ranking is the own brand's position among every brand scored for the attribute, ordered by average prominence across all AI answers about it — lower is better, #1 means no brand is more prominent; answers the brand never surfaced in count against it, and null means it never surfaced at all. competitors lists the competing brand names AI associates with the attribute, most prominent first. Rows are sorted best-ranked first (unranked last). Data is aggregated across the brand-perception runs of one industry and one target market (no date range) — pass industry to pick the industry; the target market is always that industry's most recently completed one and cannot be picked. The response reports the scope it used as industry and target_market, and lists the project's other industries under industries when it has more than one — read a different one by passing its name back as industry, and say which industry the numbers describe whenever that field is present. Use get_brand_perception_attribute_sources with a returned name to see the sources feeding an attribute. Optionally filter to specific engine channels via model_channel_ids (see list_model_channels), or narrow by a search substring on the attribute name. Returns columnar JSON: {columns, rows, rowCount, totalCount}. rowCount is the rows in this page; totalCount is the total matching records ignoring limit/offset. Columns: name, ranking, competitors (array of brand names).
get_brand_perception_attribute_rankings
The sources feeding one brand-perception attribute: the URLs AI answers cited when describing the brand with this attribute. Pass the attribute name exactly as returned by get_brand_perception_brand_attributes or get_brand_perception_attribute_rankings; an unknown name returns an empty result. Data is aggregated across all brand-perception runs (no date range), and unlike the rankings and competitive-breakdown tools it is not scoped to one industry — there is no industry argument. occurrences = AI answers about the attribute citing this source (all time). retrievals = distinct chats the source was retrieved in. citation_rate = mean citations per retrieved chat — an average, NOT a percentage, can exceed 1, display as-is. Sort with order_by (default occurrences desc). Optionally filter to specific engine channels via model_channel_ids (see list_model_channels). Returns columnar JSON: {columns, rows, rowCount, totalCount}. rowCount is the rows in this page; totalCount is the total matching records ignoring limit/offset. Columns: url, title, domain, url_classification, domain_classification, occurrences, retrievals, citation_rate.
get_brand_perception_attribute_sources
How AI models describe the project's own brand: attributes (e.g. "Luxury", "Racing Heritage") with a prominence score. score is 0-100 — the attribute's average prominence per AI answer; higher means the attribute is mentioned earlier and more often. Display scores as-is; they are NOT ratios, never multiply by 100. members lists the attribute's terms: the raw phrasings from AI answers grouped under it. Data is a snapshot of the latest brand-perception run (no date range). An empty result means the first run has not completed yet. Optionally filter to specific engine channels via model_channel_ids (see list_model_channels). Returns columnar JSON: {columns, rows, rowCount, totalCount}. rowCount is the rows in this page; totalCount is the total matching records ignoring limit/offset. Columns: name, score, members.
get_brand_perception_brand_attributes
The pages behind one fact-checked claim, each with the role it earned. Pass the claim_id returned by get_brand_perception_fact_checking_verdicts; an unknown id returns an empty result. tier is at_claim for a page cited inside the passage the claim was mined from, elsewhere for a page cited elsewhere in the same answer, and retrieved for a page the answer retrieved and never cited; a page that earned different roles in different answers keeps the strongest one. Start from the at_claim pages, since those are the likeliest to have produced the claim. Data is aggregated across every answer that made the claim and has no date range; strongest tier first. Use this rather than get_chat when the question is where a claim came from, since get_chat returns one answer's citations with no tier. Returns columnar JSON with columns, rows, rowCount, and totalCount. Columns: url, title, tier.
get_brand_perception_claim_sources
The full competitive breakdown matrix: for every brand-perception attribute, the average prominence of each brand (the project's own brand and its competitors) across AI answers. score is 0-100 — higher means the brand tends to be mentioned earlier when AI talks about that attribute; display as-is, never multiply by 100. is_own marks the project's own brand. One row per attribute x brand cell; attributes are sorted by the own brand's score (strongest first) and brands by score within each attribute. limit/offset paginate ATTRIBUTES, not rows — each attribute contributes one row per brand, and totalCount is the total attribute count. Data is aggregated across the brand-perception runs of one industry and one target market (no date range) — pass industry to pick the industry; the target market is always that industry's most recently completed one and cannot be picked. The response reports the scope it used as industry and target_market, and lists the project's other industries under industries when it has more than one — read a different one by passing its name back as industry, and say which industry the numbers describe whenever that field is present. Optionally filter to specific engine channels via model_channel_ids (see list_model_channels). Returns columnar JSON: {columns, rows, rowCount, totalCount}. Columns: attribute, brand, score, is_own.
get_brand_perception_competitive_breakdown
The claims AI models make about the project's brand, each judged against one of the project's facts. One row per claim and fact: verdict is supported or contradicted (claims no fact covers are not returned), fact is the wording the claim was judged against, chats counts the distinct AI answers that made the claim, model_channel_ids lists the channels those answers came from (name the AI engine when you present them, such as ChatGPT or Perplexity, and never print the ids; channels reflect where the claim appeared historically and may include channels no longer active for the project), last_seen is the most recent day the claim appeared (ISO date). Data is aggregated across all fact-checked chats and has no date range; newest claims first. Use verdicts=["contradicted"] to find what AI gets wrong about the brand, fact_ids from list_facts to check one fact, and claim_ids to read one claim with every fact it was judged against. Two columns are opt-in, so name them in fields: prompts counts the distinct tracked prompts whose answers made the claim, and example_chat_id is the most recent answer that made it, which get_chat reads. get_brand_perception_claim_sources lists the pages behind one claim_id. Returns columnar JSON with columns, rows, rowCount, and totalCount. Default columns: claim_id, claim, fact_id, fact, verdict, chats, model_channel_ids, last_seen.
get_brand_perception_fact_checking_verdicts
The sources AI models retrieved when asked about one objection. Pass the objection name exactly as returned by get_brand_perception_objections; an unknown name returns an empty result. Data is aggregated across all objection runs and has no date range. citation_rate is an average, not a percentage. Returns columnar JSON with columns, rows, rowCount, and totalCount.
get_brand_perception_objection_sources
The recurring arguments AI models make against the project's brand when a buyer is deciding. score is average prominence per AI answer from 0 to 100; display it as-is. members contains the raw phrasings folded into each objection. Data is aggregated across all objection runs and has no date range. Returns columnar JSON with columns, rows, rowCount, and totalCount. Columns: name, score, members.
get_brand_perception_objections
Get a report on brand visibility, sentiment, and position across AI search engines. Results are aggregated for the entire date range by default. Use the "date", "week", or "month" dimension for time-bucketed breakdowns (daily, ISO week, or calendar month). When the range spans many days, prefer "week" or "month" over "date": coarser buckets return far fewer rows (180 days ≈ 26 weeks or 6 months vs. 180 daily rows), which avoids the row limit truncating the series and keeps the trend readable. Reach for "date" only when day-level granularity is essential and the range is short. Edge buckets may be partial: a range starting or ending mid-week/mid-month produces a first/last bucket that only aggregates the in-range days, so its values can look low — don't read that as a real dip. Dimensions multiply the row count: rows = entities × dimension value combinations (e.g. 2 brands broken down by "date" over 180 days = 360 rows). The default limit of 100 will silently truncate such queries — raise "limit" to the row count you actually need. If rowCount equals limit, results were truncated; narrow the request (fewer entities, a shorter date range, fewer dimensions) or page through with "offset". Returns columnar JSON: {columns, rows, rowCount, total}. Each row is an array of values matching column order. Columns: - brand_id — the brand ID - brand_name — the brand name - visibility: 0–1 ratio — fraction of AI responses that mention this brand. 0.45 means 45% of conversations. - mention_count: number of times the brand was mentioned - share_of_voice: 0–1 ratio — brand's fraction of total mentions across all tracked brands - sentiment: 0–100 scale — how positively AI platforms describe the brand (most brands score 65–85) - position: average ranking when the brand appears (lower is better, 1 = mentioned first) - Raw aggregation fields (for custom calculations): visibility_count, visibility_total, sentiment_sum, sentiment_count, position_sum, position_count When dimensions are selected, rows also include the relevant dimension columns: prompt_id, model_id, model_channel_id, tag_id, topic_id, chat_id, date, week, month, country_code. model_channel_id, tag_id and topic_id are each followed by a model_channel_name / tag_name / topic_name column with the human-readable name. Dimensions explained: - prompt_id: individual search queries/prompts - model_id: AI search engine (e.g. chatgpt-scraper, gpt-4o, gpt-4o-search, gpt-3.5-turbo, llama-sonar, perplexity-scraper, sonar, gemini-2.5-flash, gemini-3.1-flash-lite-search, gemini-scraper, google-ai-overview-scraper, google-ai-mode-scraper, llama-3.3-70b-instruct, deepseek-r1, deepseek-v4-pro, claude-3.5-haiku, claude-haiku-4.5, claude-sonnet-4, grok-scraper, microsoft-copilot-scraper, grok-4, grok-4.3, grok-4.6, qwen-3-6-plus, qwen-3-7-plus, amazon-rufus-scraper, mistral-small-4, mistral-medium-3-5, muse-spark-1.2) — deprecated, prefer model_channel_id - model_channel_id: stable engine channel (e.g. openai-0, openai-1, qwen-0, openai-2, perplexity-0, perplexity-1, google-0, google-1, google-2, google-3, google-4, anthropic-0, anthropic-1, deepseek-0, meta-0, meta-1, xai-0, xai-1, microsoft-0, amazon-0, mistral-0, mistral-1) — survives model upgrades - tag_id: custom user-defined tags - topic_id: topic groupings - date: daily bucket (YYYY-MM-DD) - week: ISO week bucket, value is the Monday start (YYYY-MM-DD) - month: calendar month bucket, value is the first of the month (YYYY-MM-DD) - country_code: country (ISO 3166-1 alpha-2, e.g. "US", "DE") - chat_id: individual AI chat/conversation ID Two filter inputs at different SQL stages — pick by intent: - filters (WHERE, pre-aggregation): shrinks BOTH numerator and denominator of ratio metrics. Putting brand_id here narrows everything to that brand — including share_of_voice's denominator — so SoV collapses to 1.0. - having (HAVING, post-aggregation): selects which aggregated rows are returned WITHOUT shrinking ratio-metric denominators. Use brand_id here for a single-brand report where SoV stays a real [0,1] fraction (X's share against competitors per dimension). Metric semantics: - visibility = visibility_count / visibility_total within each (brand × dimension) group. Per-row by construction; both filters and having behave intuitively. - share_of_voice = brand's mention_count / sum of mentions across all brands in the same (dimension) cell. Pre-aggregation filters narrow num+denom together; post-aggregation having does not. - When dimensions are requested, share_of_voice's denominator is per-dimension. Example: dimension prompt_id ⇒ share_of_voice for (brand X, prompt P) = X's mentions in P / all brands' mentions in P. Sort results with order_by: array of {field, direction} entries. Direction defaults to desc. Sortable fields: visibility, visibility_count, mention_count, sentiment, position, share_of_voice, date, week, month. Multiple entries create a multi-key sort. Sorting by a time field (date, week or month) requires the matching dimension to be selected.
get_brand_report
Peec AI ChatGPT Plugin FAQ
How the directory, categories and Discoverability Score work.
Read the methodologyHow do I improve Peec AI's ChatGPT Plugin discoverability?
The levers are the listing surface agents actually read: names, descriptions, keywords, tool metadata, and registry health. Which lever matters depends on where discovery breaks, which is what continuous measurement shows.
What are Peec AI alternatives on ChatGPT?
As of 2026-10-12, Peec AI competes with Actionbase, AEO/GEO by VibeSEO, Agent Ready, Agenticaso, AIclicks, AirOps, ALLMO, Amplifyr and 43 more in ChatGPT AI Search & LLM Visibility (AEO/GEO), ranked by public Discoverability Score.
Where is this profile measured?
This profile uses the geography attached to the latest public registry snapshot: US. Locale tags are intentionally omitted.