{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/cavuno-com/json-schema/cavuno-com-search-console-comparison-response-schema.json",
  "title": "SearchConsoleComparisonResponse",
  "x-generated": "2026-11-04",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/cavuno-com-openapi.json#/components/schemas/SearchConsoleComparisonResponse",
  "type": "object",
  "properties": {
    "object": {
      "type": "string",
      "enum": [
        "search_console_comparison"
      ]
    },
    "range": {
      "type": "object",
      "properties": {
        "startDate": {
          "type": "string"
        },
        "endDate": {
          "type": "string"
        }
      },
      "required": [
        "startDate",
        "endDate"
      ],
      "description": "Effective requested period, moved back to end on dataThrough when needed."
    },
    "comparisonRange": {
      "type": "object",
      "properties": {
        "startDate": {
          "type": "string"
        },
        "endDate": {
          "type": "string"
        }
      },
      "required": [
        "startDate",
        "endDate"
      ]
    },
    "dataThrough": {
      "type": [
        "string",
        "null"
      ],
      "description": "Latest finalized day with data in the last 10 days, or null when none was found."
    },
    "truncated": {
      "type": "object",
      "properties": {
        "current": {
          "type": "boolean"
        },
        "comparison": {
          "type": "boolean"
        }
      },
      "required": [
        "current",
        "comparison"
      ],
      "description": "True when that period reached Google’s 25,000-row limit, so some rows are missing."
    },
    "summary": {
      "type": "object",
      "properties": {
        "totals": {
          "type": "object",
          "properties": {
            "clicks": {
              "type": "number"
            },
            "impressions": {
              "type": "number"
            },
            "ctr": {
              "type": [
                "number",
                "null"
              ],
              "description": "0–1 fraction."
            },
            "position": {
              "type": [
                "number",
                "null"
              ]
            }
          },
          "required": [
            "clicks",
            "impressions",
            "ctr",
            "position"
          ]
        },
        "comparisonTotals": {
          "type": "object",
          "properties": {
            "clicks": {
              "type": "number"
            },
            "impressions": {
              "type": "number"
            },
            "ctr": {
              "type": [
                "number",
                "null"
              ],
              "description": "0–1 fraction."
            },
            "position": {
              "type": [
                "number",
                "null"
              ]
            }
          },
          "required": [
            "clicks",
            "impressions",
            "ctr",
            "position"
          ]
        },
        "changes": {
          "type": "object",
          "properties": {
            "clicksChange": {
              "type": "number"
            },
            "impressionsChange": {
              "type": "number"
            },
            "ctrChange": {
              "type": [
                "number",
                "null"
              ]
            },
            "positionChange": {
              "type": [
                "number",
                "null"
              ]
            },
            "clicksChangePercent": {
              "type": [
                "number",
                "null"
              ]
            },
            "impressionsChangePercent": {
              "type": [
                "number",
                "null"
              ]
            }
          },
          "required": [
            "clicksChange",
            "impressionsChange",
            "ctrChange",
            "positionChange",
            "clicksChangePercent",
            "impressionsChangePercent"
          ]
        },
        "positionBuckets": {
          "type": "object",
          "properties": {
            "top1": {
              "type": "integer"
            },
            "top2to3": {
              "type": "integer"
            },
            "top4to10": {
              "type": "integer"
            },
            "top11to20": {
              "type": "integer"
            },
            "beyond20": {
              "type": "integer"
            }
          },
          "required": [
            "top1",
            "top2to3",
            "top4to10",
            "top11to20",
            "beyond20"
          ],
          "description": "Row counts by rounded current average position."
        },
        "counts": {
          "type": "object",
          "properties": {
            "new": {
              "type": "integer"
            },
            "lost": {
              "type": "integer"
            },
            "up": {
              "type": "integer"
            },
            "down": {
              "type": "integer"
            }
          },
          "required": [
            "new",
            "lost",
            "up",
            "down"
          ]
        },
        "hiddenClicks": {
          "type": "number",
          "description": "Requested-period clicks not attributed to any returned row, such as anonymized queries."
        }
      },
      "required": [
        "totals",
        "comparisonTotals",
        "changes",
        "positionBuckets",
        "counts",
        "hiddenClicks"
      ],
      "description": "Totals are ungrouped period totals. Buckets and counts cover every joined row before filters and paging."
    },
    "totalRows": {
      "type": "integer",
      "description": "Rows matching filters, before limit and offset."
    },
    "rows": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "Present when groupBy is query or query_page."
          },
          "page": {
            "type": "string",
            "description": "Present when groupBy is page or query_page."
          },
          "clicks": {
            "type": "number"
          },
          "impressions": {
            "type": "number"
          },
          "ctr": {
            "type": [
              "number",
              "null"
            ],
            "description": "0–1 fraction; null without impressions."
          },
          "position": {
            "type": [
              "number",
              "null"
            ]
          },
          "previousClicks": {
            "type": "number"
          },
          "previousImpressions": {
            "type": "number"
          },
          "previousCtr": {
            "type": [
              "number",
              "null"
            ]
          },
          "previousPosition": {
            "type": [
              "number",
              "null"
            ]
          },
          "clicksChange": {
            "type": "number"
          },
          "impressionsChange": {
            "type": "number"
          },
          "ctrChange": {
            "type": [
              "number",
              "null"
            ]
          },
          "positionChange": {
            "type": [
              "number",
              "null"
            ],
            "description": "previousPosition minus position: positive means the row moved up."
          },
          "clicksChangePercent": {
            "type": [
              "number",
              "null"
            ],
            "description": "Percentage change; null when previousClicks is 0."
          },
          "impressionsChangePercent": {
            "type": [
              "number",
              "null"
            ],
            "description": "Percentage change; null when previousImpressions is 0."
          },
          "isNew": {
            "type": "boolean",
            "description": "No row in the comparison period."
          },
          "isLost": {
            "type": "boolean",
            "description": "No row in the requested period."
          },
          "isUp": {
            "type": "boolean",
            "description": "Position improved by at least 0.1 (not new or lost)."
          },
          "isDown": {
            "type": "boolean",
            "description": "Position worsened by at least 0.1 (not new or lost)."
          }
        },
        "required": [
          "clicks",
          "impressions",
          "ctr",
          "position",
          "previousClicks",
          "previousImpressions",
          "previousCtr",
          "previousPosition",
          "clicksChange",
          "impressionsChange",
          "ctrChange",
          "positionChange",
          "clicksChangePercent",
          "impressionsChangePercent",
          "isNew",
          "isLost",
          "isUp",
          "isDown"
        ]
      }
    },
    "cavuno": {
      "type": "object",
      "properties": {
        "coverage": {
          "type": "object",
          "properties": {
            "mode": {
              "type": "string",
              "enum": [
                "board_hosts",
                "whole_property"
              ]
            },
            "hostnames": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          "required": [
            "mode",
            "hostnames"
          ]
        },
        "dataState": {
          "type": "string",
          "enum": [
            "final"
          ]
        },
        "dataTimezone": {
          "type": "string",
          "enum": [
            "America/Los_Angeles"
          ]
        }
      },
      "required": [
        "coverage",
        "dataState",
        "dataTimezone"
      ]
    }
  },
  "required": [
    "object",
    "range",
    "comparisonRange",
    "dataThrough",
    "truncated",
    "summary",
    "totalRows",
    "rows",
    "cavuno"
  ]
}