Data Model Overview
VisibilityIQ uses an observation model architecture. Raw data from external sources (GSC, GA4, CrUX, Bing, and the platform data index) is never stored directly in the database or exposed to the scoring and audit layers. Instead, it’s normalized into typed observation models that have stable schemas regardless of which connector provided the data.
Why observations
Section titled “Why observations”Different data sources report the same concept differently:
- “Clicks” in GSC vs “sessions” in GA4 vs “visits” in Bing Webmaster are all measures of traffic but they’re not the same thing
- Google, Bing, and the platform data index all have some version of “index status” but they report it with different codes, at different granularities, and on different schedules
The observation model gives audit checks, the scoring engine, and the API a stable contract to code against, regardless of where the data came from or how the upstream connector changed its format.
Observation types
Section titled “Observation types”| Model | What it captures |
|---|---|
PageObservation | Crawl and page-level findings (status, metadata, links, headers) |
CanonicalObservation | Canonical status from external sources (GSC selected canonical vs declared) |
PerformanceObservation | CWV and speed metrics (LCP, INP, CLS, TTFB, FCP) |
TrafficObservation | Clicks, impressions, sessions, revenue per URL |
IndexationObservation | Index status, coverage signals, URL inspection data |
AIVisibilityObservation | AI Overview citations, AI bot access status |
Schema stability guarantee
Section titled “Schema stability guarantee”Observation type schemas are versioned and backward-compatible. When a connector changes its output format (e.g., GA4 changes a field name), the connector’s normalization layer absorbs the change. Observation consumers (audit checks, scoring, API) never see the raw connector format.
Raw data storage
Section titled “Raw data storage”Raw API responses from connectors are stored in R2 (object storage), not D1. D1 holds only the normalized observations. This means:
- D1 stays lean (normalized fields, no multi-kilobyte JSON blobs)
- Raw data is available for debugging but doesn’t affect query performance
- R2 retention is limited (configurable, default 30 days) — raw data is not meant for long-term archival
Accessing observations via API
Section titled “Accessing observations via API”The public API exposes observation data through typed endpoints:
GET /v1/projects/:id/pages/:url/observationsGET /v1/projects/:id/performanceGET /v1/projects/:id/trafficGET /v1/projects/:id/indexationEach response follows the typed schema for that observation type. See the individual observation type docs for the full field listing.