Skill: psyduckler/aeo-analytics-free (version 1.0.0)

--- name: aeo-analytics-free description: > Track AI visibility — measure whether a brand is mentioned and cited by AI assistants (Gemini, ChatGPT, Perplexity) for target prompts. Runs scans, tracks mention/citation rates over time, detects trends, and identifies opportunities. Uses Gemini API free tier (with grounding) as primary method, web search as fallback. Use when a user wants to: check if AI models mention their brand, track AI citation changes over time, measure AEO content effectiveness, monitor competitor AI visibility, or audit their brand's presence in AI-generated answers. Pairs with aeo-prompt-research-free (identifies prompts) and aeo-content-free (creates/refreshes content). This skill closes the loop by measuring results. --- # AEO Analytics (Free) > **Source:** [github.com/psyduckler/aeo-skills](https://github.com/psyduckler/aeo-skills/tree/main/aeo-analytics-free) > **Part of:** [AEO Skills Suite](https://github.com/psyduckler/aeo-skills) — [Prompt Research](https://github.com/psyduckler/aeo-skills/tree/main/aeo-prompt-research-free) → [Content](https://github.com/psyduckler/aeo-skills/tree/main/aeo-content-free) → Analytics Track whether AI assistants mention and cite your brand — and how that changes over time. ## Requirements - **Primary:** Gemini API key (free from aistudio.google.com) — enables grounding with source data - **Fallback:** `web_search` only — weaker signal but zero API keys needed - `web_fetch` — optional, for deeper analysis of cited pages ## Input - **Domain** (required) — the brand's website (e.g., `tabiji.ai`) - **Brand names** (required) — names to search for in responses (e.g., `["tabiji", "tabiji.ai"]`) - **Prompts** (required for first scan) — list of target prompts to track. Can come from `aeo-prompt-research-free` output. - **Data file path** (optional) — where to store scan history. Default: `aeo-analytics/<domain>.json` ## Commands The skill supports three commands: ### `scan` — Run a new visibility scan Execute all tracked prompts against the AI model and record results. ### `report` — Generate a visibility report Analyze accumulated scan data and produce a formatted report. ### `add-prompts` / `remove-prompts` — Manage tracked prompts Add or remove prompts from the tracking list. --- ## Scan Workflow ### Step 1: Load or Initialize Data Check if a data file exists for this domain. If yes, load it. If no, create a new one. See `references/data-schema.md` for the full JSON schema. ### Step 2: Run Prompts For each tracked prompt: **Method A — Gemini API with grounding (preferred):** See `references/gemini-grounding.md` for API details. 1. Send prompt to Gemini API with `googleSearch` tool enabled 2. From the response, extract: - **Response text** — the AI's answer - **Grounding chunks** — the web sources cited (URLs + titles) - **Web search queries** — what the AI searched for 3. Analyze the response: - **Mentioned?** — Search response text for brand names (case-insensitive, word-boundary match) - **Mention excerpt** — Extract the sentence(s) containing the brand name - **Cited?** — Check if brand's domain appears in any grounding chunk URI - **Cited URLs** — List the specific brand URLs cited - **Sentiment** — Classify the mention context as positive/neutral/negative - **Competitors** — Extract other brand names and domains from response + citations **Method B — Web search fallback (if no Gemini API key):** 1. `web_search` the exact prompt text 2. Check if brand's domain appears in search results 3. Record as "web-proxy" method (less direct than grounding) ### Step 3: Save Results Append the scan results to the data file. Never overwrite previous scans — history is the whole point. ### Step 4: Quick Summary After scanning, output a brief summary: - Prompts scanned - Current mention rate and citation rate - Change vs. last scan (if applicable) - Any notable changes (new mentions, lost citations) --- ## Report Workflow ### Per-Prompt Detail For each tracked prompt, show: ``` 1. "[prompt text]" Scans: [total] (since [first scan date]) Mentioned: [count]/[total] ([%]) — [trend arrow] [trend description] Cited: [count]/[total] ([%]) Latest: [✅/❌ Mentioned] + [✅/❌ Cited] Sentiment: [positive/neutral/negative] Competitors mentioned: [list] ``` If mentioned in latest scan, include the mention excerpt. If not mentioned, note which sources were cited instead and rate the opportunity (HIGH/MEDIUM/LOW). ### Summary Section ``` VISIBILITY SCORE Brand mentioned: [X]/[total] prompts ([%]) in latest scan Brand cited: [X]/[total] prompts ([%]) in latest scan TRENDS (last [N] days, [N] scans) Mention rate: [%] → [trend] Citation rate: [%] → [trend] Most improved: [prompt] ([old rate] → [new rate]) Most volatile: [prompt] (mentioned [X]/[N] scans) Consistently absent: [list of prompts never mentioned] COMPETITOR SHARE OF VOICE [Competitor 1] — mentioned in [X]/[total] prompts [Competitor 2] — mentioned in [X]/[total] prompts [Brand] — mentioned in [X]/[total] prompts NEXT ACTIONS → [Prioritized recommendations based on gaps and trends] ``` ### Recommendations Logic - **High opportunity:** Prompt has 0% mention rate + no strong owner in citations → create content - **Close to winning:** Prompt has mentions but no citations → refresh content for citation-worthiness - **Volatile:** Mention rate between 20-60% → content exists but needs strengthening - **Won:** Mention rate >80% + citation rate >50% → maintain, monitor for decay --- ## Data Management - Data file location: `aeo-analytics/<domain>.json` - Schema: see `references/data-schema.md` - Each scan appends to the `scans` array — never delete history - Prompts can be added/removed without affecting historical data - When adding new prompts, they start with 0 scans (no backfill) ## Tips - Run scans at consistent intervals (weekly or biweekly) for meaningful trend data - After publishing new AEO content, wait 2-4 weeks for indexing before expecting changes - Gemini's grounding results can vary run-to-run — that's normal. Aggregate data over multiple scans is more reliable than any single result - Track 10-20 prompts max for a focused view. Too many dilutes the signal - This skill completes the AEO loop: Research (aeo-prompt-research-free) → Create/Refresh (aeo-content-free) → Measure (this skill) → repeat

path: references/data-schema.md
content: # AEO Analytics Data Schema

## Storage File

All scan data is stored in a single JSON file per domain. Default location: `aeo-analytics/<domain>.json`

The file accumulates results across scans — each run appends, never overwrites.

## Schema

```json
{
  "domain": "tabiji.ai",
  "brandNames": ["tabiji", "tabiji.ai"],
  "created": "2026-01-15T00:00:00Z",
  "prompts": [
    {
      "id": "p1",
      "text": "What's the best AI travel planner that gives real local recommendations?",
      "category": "best-of",
      "added": "2026-01-15T00:00:00Z"
    }
  ],
  "scans": [
    {
      "id": "s1",
      "timestamp": "2026-02-11T20:00:00Z",
      "model": "gemini-2.0-flash",
      "method": "grounding",
      "results": [
        {
          "promptId": "p1",
          "mentioned": true,
          "mentionExcerpt": "tabiji.ai uses Reddit posts and travel forums to source recommendations",
          "cited": true,
          "citedUrls": ["https://tabiji.ai/blog/why-generic-ai-travel"],
          "sentiment": "positive",
          "competitorsMentioned": ["Wanderlog", "Wonderplan", "ChatGPT"],
          "competitorsCited": ["wanderlog.com", "wonderplan.ai"],
          "responseExcerpt": "Several AI travel planners go beyond generic suggestions..."
        }
      ]
    }
  ]
}
```

## Field Definitions

### Prompt Object
- `id` — Unique identifier (p1, p2, etc.)
- `text` — The exact prompt to send to the AI model
- `category` — Prompt type: best-of, how-to, comparison, evaluation, problem-aware, industry
- `added` — When this prompt was added to tracking

### Scan Object
- `id` — Unique scan identifier (s1, s2, etc.)
- `timestamp` — ISO 8601 timestamp of when scan was run
- `model` — Which AI model was used (e.g., "gemini-2.0-flash")
- `method` — How the scan was performed: "grounding" (Gemini API), "web-proxy" (web search), "manual"

### Result Object (per prompt per scan)
- `promptId` — References the prompt
- `mentioned` — Boolean: was the brand name found in the response text?
- `mentionExcerpt` — The sentence(s) where the brand was mentioned (null if not mentioned)
- `cited` — Boolean: was the brand's domain in the grounding sources / citations?
- `citedUrls` — Array of the brand's URLs that were cited (empty array if not cited)
- `sentiment` — "positive", "neutral", or "negative" (null if not mentioned)
- `competitorsMentioned` — Array of competitor brand names in the response
- `competitorsCited` — Array of competitor domains in the citations
- `responseExcerpt` — Brief excerpt of the AI's response (first 200 chars or the relevant paragraph)

## Computed Metrics (derived at report time, not stored)

- **Mention rate** — `mentioned scans / total scans` per prompt
- **Citation rate** — `cited scans / total scans` per prompt
- **Overall visibility** — `prompts with ≥1 mention in latest scan / total prompts`
- **Trend** — Compare latest N scans vs. previous N scans
- **Volatility** — Standard deviation of mention rate across scans per prompt
- **Competitor share of voice** — How often each competitor appears across all prompts


path: references/gemini-grounding.md
content: # Using Gemini API with Grounding for AEO Analytics

## Overview

Gemini's API supports "grounding with Google Search" — when enabled, the model searches the web before answering and exposes the sources it used. This is the most direct free signal for AI visibility.

## Setup

1. Get a free API key from https://aistudio.google.com/apikey
2. Store it as environment variable `GEMINI_API_KEY` or in the agent's keychain

## API Call (grounding enabled)

```bash
curl -s "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${GEMINI_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [{"parts": [{"text": "What is the best AI travel planner that gives real local recommendations?"}]}],
    "tools": [{"googleSearch": {}}]
  }'
```

## Response Structure (relevant fields)

```json
{
  "candidates": [{
    "content": {
      "parts": [{"text": "The AI's response text..."}]
    },
    "groundingMetadata": {
      "searchEntryPoint": {
        "renderedContent": "<HTML snippet>"
      },
      "groundingChunks": [
        {
          "web": {
            "uri": "https://example.com/page",
            "title": "Page Title"
          }
        }
      ],
      "groundingSupports": [
        {
          "segment": {
            "startIndex": 0,
            "endIndex": 150,
            "text": "The specific text supported by this source"
          },
          "groundingChunkIndices": [0],
          "confidenceScores": [0.95]
        }
      ],
      "webSearchQueries": [
        "best AI travel planner local recommendations"
      ]
    }
  }]
}
```

## How to Extract Visibility Data

1. **Brand mentioned?** — Search `candidates[0].content.parts[0].text` for brand names (case-insensitive)
2. **Brand cited?** — Search `groundingChunks[].web.uri` for the brand's domain
3. **Competitors cited?** — Extract all domains from `groundingChunks` that aren't the target brand
4. **What AI searched for** — `webSearchQueries` shows how the AI interpreted the prompt
5. **Confidence** — `groundingSupports[].confidenceScores` shows how confident the AI is in each citation

## Free Tier Limits

- Gemini 2.0 Flash: 15 RPM, 1,500 RPD, 1M TPM
- Gemini 1.5 Flash: 15 RPM, 1,500 RPD

For a typical scan of 10-20 prompts, you'll use ~20 requests — well within free limits. You could run 75 scans per day and stay free.

## Fallback: Web Search Proxy

If no Gemini API key is available, use `web_search` as a proxy:
1. Search the exact prompt text
2. Check if brand's domain appears in results
3. Less direct than Gemini grounding but requires zero API keys

This method detects traditional search visibility, not AI citation specifically. Use it as a supplement, not a replacement.


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)