{"id":80336,"plugin_id":"plugin_asdk_app_6ad86cac95c08191b4689c05f3f1761f","kind":"skill","collection_source":"plugin_package","comparison_source":null,"observed_at":"2026-11-04T06:14:37.375Z","digest":"77553268cc9aa5fda795713cd7c8ec4326c76294a3cd860381d03040049166e9","against":null,"payload":{"description":"Use when the user asks how their own tracked browser extension is doing on ExtensionDash, such as users, ratings, keyword positions over a period, which keywords improved or dropped, which competitors are overtaking them, or what to investigate first. Requires an ExtensionDash account connection. Uses list_extensions, get_extension, get_metrics_history, list_keywords, get_keyword_ranks, list_competitors, get_keyword_serp and list_scrape_runs.","included_files":[{"relative_path":"references/connecting-an-account.md","size_in_bytes":2492}],"name":"review-performance","skill_md_contents":"---\nname: review-performance\ndescription: Use when the user asks how their own tracked browser extension is doing on ExtensionDash, such as users, ratings, keyword positions over a period, which keywords improved or dropped, which competitors are overtaking them, or what to investigate first. Requires an ExtensionDash account connection. Uses list_extensions, get_extension, get_metrics_history, list_keywords, get_keyword_ranks, list_competitors, get_keyword_serp and list_scrape_runs.\n---\n\n# Review performance\n\nExplain how the user's tracked extensions moved, using only what ExtensionDash\nhas recorded. Every tool used here is read-only.\n\n## Prerequisite: an account connection\n\nThese tools need an account. If a call answers that \"this connection has no\naccount\", stop and follow [connecting an account](references/connecting-an-account.md).\nNever ask the user to paste a token into the chat.\n\n## Workflow\n\n1. **Resolve the extension.** Call `list_extensions`. Use its `id` as\n   `extension_id` everywhere else.\n   - If the user named an extension, match it against `name`. If more than\n     one matches, or none does, list what exists and ask.\n   - If the user has exactly one extension, use it and say so.\n   - `list_extensions` also gives each listing's latest `users_count`,\n     `users_rounded`, `users_delta_7d`, `rating_average`, `ratings_count`\n     and `last_scraped_at`. That is enough for \"how is it doing right now\".\n2. **Fix the comparison period.** Use the user's period if they gave one,\n   or 7 days by default. State the exact dates.\n   - `improvement_7d` and `users_delta_7d` are fixed 7-day comparisons.\n   - For any other period, pass `days` to the history tools and compare\n     the first and last observed dates yourself.\n3. **Users and ratings.** Call `get_metrics_history` with `days` (and\n   `store` when one store is in question). Each metric is a map of ISO\n   date to value.\n   - Compare the earliest and latest dates actually present, and name\n     them. An empty map means nothing was measured in range. It is not\n     zero.\n   - If `users_rounded_in_range` is true, the store published rounded\n     counts, so small moves may be rounding.\n   - With `include_competitors: true` or a `competitors` list, rivals'\n     series arrive too. Competitors are sampled every few days, so compare\n     them against the user's numbers on dates present in both, never by\n     position in the map.\n4. **Keyword positions.** Call `list_keywords` for the current state, and\n   `get_keyword_ranks` with `days` for movement over the period. Narrow\n   with `term`, `store` or `locale` as needed.\n5. **Competition.**\n   - Call `list_competitors` with `include_observed: true`.\n     - `competitors` is the roster the user tracks.\n     - `candidates` are other listings seen in the user's recorded\n       results, ranked by how often they beat the user.\n     - Use `ahead_of_us_on`, `terms_seen`, `terms_tracked`,\n       `average_position` and `best_position` as the evidence for\n       \"who is overtaking me\".\n   - For one term, call `get_keyword_serp` with `store`, `term` and\n     `locale`. It returns the recorded page with `mine`/`competitor` flags\n     and `moved_up_by`. Pass `window: true` for just the leaders and the\n     user's neighbourhood.\n6. **Separate collection problems from performance.** If numbers are\n   missing, stale, or a term looks stuck, call `list_scrape_runs` with\n   `extension_id` (and `status: \"failure\"` if useful).\n   - A failed fetch is a data-collection problem, not a ranking drop.\n     Report it separately.\n   - `expected_failure: true`, for example a delisted listing, is not\n     signal.\n7. **Report** in the format below.\n\n## Reading rankings correctly\n\nEach keyword row and rank point is one (term, store, locale) result. Keep\nstores and locales apart. \"ad blocker\" in Chrome/en, Firefox/en and\nChrome/de are three separate results; never average them.\n\nKeyword rows fall into three states. Keep them distinct:\n\n| State | How it looks | Say |\n| --- | --- | --- |\n| Never scanned | `status: \"pending\"`, no `captured_on` | \"No result yet; the first fetch has not landed.\" |\n| Scanned and found | `position` is a number | \"#7 of the 50 results scanned on 2026-10-17.\" |\n| Scanned but absent | `status: \"scanned\"`, `position: null` | \"Not in the top 13 results scanned.\" |\n\nRules for positions:\n\n- **Always give the depth.** Report every position with `depth_scanned`,\n  because #1 of 6 and #1 of 50 are different results.\n- **Shallow scans.** `shallow: true` means the store returned fewer results\n  than the usual scan depth.\n- **Absent is not a rank.** Never turn \"not found within N\" into a rank\n  such as N+1 or 51.\n- **Stale positions.** A `pending` row may still carry an old position from\n  earlier tracking. Check `captured_on` before quoting it.\n- **Direction of movement.**\n  - `improvement_7d` and `moved_up_by` are positive when the extension\n    moved up the page.\n  - `improvement_7d` is null when there is no 7-day baseline, or when the\n    extension is absent now. Call that \"insufficient history\", not \"no\n    change\".\n- **Search volume.** `search_volume` is Google web-search demand (Google\n  Ads), not searches inside the store. It is the same for both stores.\n  Null means unknown, not zero.\n\n## Reading user counts correctly\n\n- **Units differ by store.** Chrome users are a rounded store figure.\n  Firefox users are AMO's daily-average users. Never add them together,\n  rank them against each other, or call them equivalent.\n- **Rounding.** `users_rounded: true` means the store rounded the number.\n  A move across a rounding boundary (for example 9,000 to 10,000) is not a\n  measured gain of 1,000.\n- **Rating precision.** Ratings come with their review counts. A 5.0 from\n  one review is not evidence of quality.\n\n## Causation\n\nReport what changed and when. Listing edits, new keywords, or a competitor's\nupdate may coincide with a move. Present those as hypotheses to check, never\nas the cause, unless the data directly shows it.\n\n## Output\n\n1. **Period.** Exact dates, the stores and locales covered.\n2. **Key changes.** The 3–6 biggest movements: users, ratings and keyword\n   positions (with depth), each with its numbers.\n3. **Competition.** Who is ahead of the user on the most terms, with the\n   evidence fields.\n4. **Data limitations.** Missing baselines, pending terms, shallow scans,\n   rounded counts, failed fetches.\n5. **What to investigate first.** A prioritized list of 2–4 concrete\n   checks, each tied to evidence above. Suggest tracking changes as an\n   offer, never as an action already taken.\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}