Skill: clawbus/clawbus-google-search-console (version 1.0.2)

--- name: Google Search Console description: > Google Search Console sitemap status skill for MyBrandMetrics. Use it to query connected Google Search Console sitemap data, submitted URL counts, indexed URL counts, sitemap warnings, sitemap errors, pending processing status, content type, and last downloaded time through the google_search_console_sitemaps source. compatibility: tools: - bash - python dependencies: - requests --- # Google Search Console Check Google Search Console sitemap status through the MyBrandMetrics API. Use this skill to review sitemap health for a connected Google Search Console property: submitted URL counts, indexed URL counts, warning counts, error counts, pending status, content type, and last downloaded time. Website: [https://www.clawbus.com/](https://www.clawbus.com/) MyBrandMetrics API: [https://mybrandmetrics.com/](https://mybrandmetrics.com/) ## Core Capabilities | Capability | Details | | --- | --- | | Google Search Console sitemap data | Query the `google_search_console_sitemaps` source through MyBrandMetrics. | | Sitemap status | List sitemap rows for a connected Search Console property. | | Submitted and indexed URLs | Compare `contents_submitted` and `contents_indexed` for sitemap health. | | Warnings and errors | Review sitemap warning and error counts. | | Pending processing | Check whether a sitemap row is still pending. | | Last downloaded time | See when Google last downloaded each sitemap. | | Filtered queries | Use metrics, dimensions, filters, and row limits for narrower reports. | ## Setup Flow 1. Open [https://mybrandmetrics.com/](https://mybrandmetrics.com/) and sign in with Google. 2. In MyBrandMetrics, open **Data sources**. 3. Connect Google Search Console as a data source. 4. Wait until the Google Search Console connection is ready. 5. In [https://mybrandmetrics.com/](https://mybrandmetrics.com/), get the MyBrandMetrics API key. 6. Install the `clawbus-google-search-console` skill. 7. Start a Google Search Console sitemap status workflow with natural-language instructions. ## Workflow Use natural-language prompts after the skill is installed. Include: - the Google Search Console connection ID, such as `sc-domain:example.com`; - whether to list all sitemap rows or focus on a specific sitemap issue; - the metrics to review, such as warnings, errors, submitted URLs, indexed URLs, and sitemap count; - the dimensions to group by, such as site URL, sitemap path, content type, last downloaded time, and pending status; - any filters or row limit needed for the analysis. Example: ```text Check the Google Search Console sitemap status for sc-domain:example.com and summarize warnings, errors, submitted URLs, and indexed URLs. ``` ## Search-Friendly Workflows Common Google Search Console sitemap workflows include: - list Google Search Console sitemap status rows; - check sitemap warnings and errors; - compare submitted URLs and indexed URLs; - find pending sitemap records; - review sitemap content type and last downloaded time; - summarize sitemap health for a connected Search Console property. ## Use The Script Directly Use `scripts/searchconsole.py`. List sitemap status: ```bash python3 scripts/searchconsole.py \ --api-key "YOUR_API_KEY" \ --connection-id "sc-domain:example.com" \ --limit 200 ``` Use custom metrics and dimensions: ```bash python3 scripts/searchconsole.py \ --api-key "YOUR_API_KEY" \ --connection-id "sc-domain:example.com" \ --metrics "warnings,errors,contents_submitted,contents_indexed" \ --dimensions "site_url,sitemap_path,content_type,last_downloaded,is_pending" \ --limit 100 ``` Use an environment variable instead of passing the API key in the command: ```bash export MYBRANDMETRICS_API_KEY="YOUR_API_KEY" python3 scripts/searchconsole.py \ --connection-id "sc-domain:example.com" \ --limit 200 ``` ## Parameters | Parameter | Required | Purpose | | --- | --- | --- | | `--api-key` | Yes, unless `MYBRANDMETRICS_API_KEY` is set | MyBrandMetrics API key. | | `--connection-id` | Yes | Google Search Console property connection ID, such as `sc-domain:example.com`. | | `--account-id` | No | Account ID. Defaults to the connection ID when omitted. | | `--metrics` | No | Comma-separated sitemap metrics. | | `--dimensions` | No | Comma-separated sitemap dimensions. | | `--filter` | No | Filter in `field:operator:value` format. Repeat for multiple filters. | | `--limit` | No | Maximum rows to return. Default is `200`. | | `--compact` | No | Print compact JSON instead of indented JSON. | ## Available Metrics And Dimensions Default metrics: - `warnings` - `errors` - `contents_submitted` - `contents_indexed` - `sitemaps_count` Default dimensions: - `site_url` - `sitemap_path` - `content_type` - `last_downloaded` - `is_pending` Google Search Console data can lag by several days, so new sitemap submissions or recent indexing changes may not appear immediately.

path: references/configuration.md
content: # Configuration

Read this file when authentication, connection setup, or property formatting is
unclear.

## Authentication

The bundled script accepts a MyBrandMetrics API key in either form:

- `--api-key "YOUR_API_KEY"`
- `MYBRANDMETRICS_API_KEY="YOUR_API_KEY"`

Prefer environment variables for routine use. Do not store real keys in this
repository.

## Connection ID

The script requires a Google Search Console connection ID configured in
MyBrandMetrics. Common examples:

- Domain property: `sc-domain:example.com`
- URL-prefix style connection: `https://www.example.com/`

Use the exact identifier configured in MyBrandMetrics. If a query returns no
rows, first verify that the connection ID matches the connected Search Console
property.

## Python Dependencies

The script needs Python 3 and `requests`:

```bash
python3 -m pip install requests
```

Install dependencies only when the user asks to run the query in the current
environment.

## Common Failures

- Missing API key: set `MYBRANDMETRICS_API_KEY` or pass `--api-key`.
- HTTP 401 or 403: the API key is missing, invalid, or not authorized for the
  connected Search Console account.
- Empty rows: the connection ID, filters, sitemap data, or MyBrandMetrics
  connection may not match the requested site.
- Rate limiting: retry later or reduce request volume.

## Security Rules

- Never commit API keys, access tokens, service account files, private keys, or
  OAuth credentials.
- Avoid printing keys in terminal logs.
- Redact credentials before sharing command output or screenshots.


path: references/dimensions.md
content: # Dimensions and Metrics

Read this file when choosing dimensions, metrics, or filters for the
`google_search_console_sitemaps` source.

## Source Key

| Source key | Description |
|---|---|
| `google_search_console_sitemaps` | Sitemap status and health data from Google Search Console |

## Default Dimensions

| Dimension | Description |
|---|---|
| `site_url` | Search Console site URL or property identifier |
| `sitemap_path` | Full sitemap URL or sitemap path |
| `content_type` | Sitemap content type, such as `web`, `image`, or `video` |
| `last_downloaded` | Last time Google downloaded the sitemap |
| `is_pending` | Whether sitemap processing is still pending |

## Default Metrics

| Metric | Description |
|---|---|
| `warnings` | Number of sitemap warnings |
| `errors` | Number of sitemap errors |
| `contents_submitted` | Number of submitted URLs |
| `contents_indexed` | Number of indexed URLs |
| `sitemaps_count` | Number of sitemap files represented in the row |

## Filter Format

The script accepts repeatable filters in this shape:

```text
field:operator:value
```

Example:

```bash
--filter "content_type:equals:web"
```

Use filters only when the user asks for a narrower report or when the full result
set is too noisy.


path: references/query-patterns.md
content: # Query Patterns

Read this file when the user needs concrete command examples for Google Search
Console sitemap queries through MyBrandMetrics.

## Default Sitemap Status

```bash
python3 google-search-console/scripts/searchconsole.py \
  --connection-id "sc-domain:example.com" \
  --limit 200
```

## Select Specific Metrics

```bash
python3 google-search-console/scripts/searchconsole.py \
  --connection-id "sc-domain:example.com" \
  --metrics "warnings,errors,contents_submitted,contents_indexed" \
  --limit 200
```

## Select Specific Dimensions

```bash
python3 google-search-console/scripts/searchconsole.py \
  --connection-id "sc-domain:example.com" \
  --dimensions "site_url,sitemap_path,last_downloaded,is_pending" \
  --limit 200
```

## Filter Results

Filters use `field:operator:value` format and can be repeated.

```bash
python3 google-search-console/scripts/searchconsole.py \
  --connection-id "sc-domain:example.com" \
  --filter "content_type:equals:web" \
  --limit 100
```

## Compact JSON

```bash
python3 google-search-console/scripts/searchconsole.py \
  --connection-id "sc-domain:example.com" \
  --compact
```

## Analysis Tips

- Flag any sitemap where `contents_indexed` is `0`.
- Flag non-zero `errors` or `warnings`.
- Treat `is_pending` as a sign that Google has not finished processing the
  sitemap.
- Remember that GSC data can lag by several days.


path: scripts/searchconsole.py
content: #!/usr/bin/env python3
"""Query Google Search Console sitemap status through MyBrandMetrics."""

import argparse
import json
import os
import re
import sys
import time

import requests


BASE_URL = "https://api.mybrandmetrics.com/explorer/query"
DEFAULT_TIMEOUT = 30


class SearchConsoleClient:
    """Small client for MyBrandMetrics Google Search Console sitemap queries."""

    def __init__(self, api_key: str, connection_id: str, account_id: str | None = None):
        if not api_key:
            raise ValueError("API key is required")
        if not connection_id:
            raise ValueError("Connection ID is required")

        self.[REDACTED_SECRET]
        self.connection_id = connection_id
        self.account_id = account_id or connection_id

    def headers(self) -> dict[str, str]:
        return {
            "X-API_KEY": self.api_key,
            "Content-Type": "application/json",
        }

    def query(
        self,
        source_key: str,
        metrics: list[str] | None = None,
        dimensions: list[str] | None = None,
        filters: list[dict] | None = None,
        limit: int = 200,
        retry_count: int = 3,
    ) -> dict:
        body = {
            "source_key": source_key,
            "connection_id": self.connection_id,
            "account_id": self.account_id,
            "limit": limit,
        }
        if metrics:
            body["metrics"] = metrics
        if dimensions:
            body["dimensions"] = dimensions
        if filters:
            body["filters"] = filters

        for attempt in range(retry_count):
            try:
                response = requests.post(
                    BASE_URL,
                    headers=self.headers(),
                    json=body,
                    timeout=DEFAULT_TIMEOUT,
                )
                if response.status_code == 429 or response.status_code >= 503:
                    wait_seconds = 2**attempt
                    print(
                        f"Received {response.status_code}; retrying in {wait_seconds}s "
                        f"({attempt + 1}/{retry_count})",
                        file=sys.stderr,
                    )
                    time.sleep(wait_seconds)
                    continue

                response.raise_for_status()
                return response.json()
            except requests.exceptions.RequestException as exc:
                if attempt == retry_count - 1:
                    raise
                wait_seconds = 2**attempt
                print(
                    f"Request failed: {exc}; retrying in {wait_seconds}s "
                    f"({attempt + 1}/{retry_count})",
                    file=sys.stderr,
                )
                time.sleep(wait_seconds)

        raise RuntimeError("Request failed after retries")

    def list_sitemaps(
        self,
        metrics: list[str] | None = None,
        dimensions: list[str] | None = None,
        filters: list[dict] | None = None,
        limit: int = 200,
    ) -> dict:
        metrics = metrics or [
            "warnings",
            "errors",
            "contents_submitted",
            "contents_indexed",
            "sitemaps_count",
        ]
        dimensions = dimensions or [
            "site_url",
            "sitemap_path",
            "content_type",
            "last_downloaded",
            "is_pending",
        ]
        return self.query(
            "google_search_console_sitemaps",
            metrics=metrics,
            dimensions=dimensions,
            filters=filters,
            limit=limit,
        )


def split_csv(value: str | None) -> list[str] | None:
    if not value:
        return None
    return [item.strip() for item in value.split(",") if item.strip()]


def parse_filters(raw_filters: list[str] | None) -> list[dict] | None:
    if not raw_filters:
        return None

    filters = []
    for raw_filter in raw_filters:
        match = re.match(r"([^:]+):([^:]+):(.+)", raw_filter)
        if not match:
            raise ValueError(
                f"Invalid filter format: {raw_filter}. Use field:operator:value."
            )
        filters.append(
            {
                "field": match.group(1),
                "operator": match.group(2),
                "value": match.group(3),
            }
        )
    return filters


def main() -> None:
    parser = argparse.ArgumentParser(
        description="Query Google Search Console sitemap status through MyBrandMetrics."
    )
    parser.add_argument("--api-key", help="MyBrandMetrics API key")
    parser.add_argument(
        "--connection-id",
        required=True,
        help="Google Search Console connection ID, such as sc-domain:example.com",
    )
    parser.add_argument(
        "--account-id",
        help="Account ID. Defaults to the connection ID when omitted.",
    )
    parser.add_argument(
        "--metrics",
        help="Comma-separated metrics. Defaults to sitemap health metrics.",
    )
    parser.add_argument(
        "--dimensions",
        help="Comma-separated dimensions. Defaults to sitemap identity dimensions.",
    )
    parser.add_argument("--limit", type=int, default=200, help="Maximum rows to return")
    parser.add_argument(
        "--filter",
        action="append",
        dest="filters",
        help="Repeatable filter in field:operator:value format",
    )
    parser.add_argument(
        "--compact",
        action="store_true",
        help="Print compact JSON instead of indented JSON",
    )
    args = parser.parse_args()

    [REDACTED_SECRET] or os.environ.get("MYBRANDMETRICS_API_KEY")
    if not [REDACTED_SECRET]
            "Error: provide --api-key or set MYBRANDMETRICS_API_KEY.",
            file=sys.stderr,
        )
        sys.exit(1)

    try:
        filters = parse_filters(args.filters)
    except ValueError as exc:
        print(f"Error: {exc}", file=sys.stderr)
        sys.exit(1)

    client = SearchConsoleClient(
        [REDACTED_SECRET],
        connection_id=args.connection_id,
        account_id=args.account_id,
    )
    result = client.list_sitemaps(
        metrics=split_csv(args.metrics),
        dimensions=split_csv(args.dimensions),
        filters=filters,
        limit=args.limit,
    )

    indent = None if args.compact else 2
    print(json.dumps(result, indent=indent, sort_keys=True))


if __name__ == "__main__":
    main()


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