Technical reference

Data Structure for Visualization

Connect Tableau, Power BI, Looker, or another reporting tool to the versioned BI views provided by LocalScore360 without exposing private event rows.

Use the supported views as the reporting boundary

Routine BI credentials should receive SELECT access only to bi_anonymous_events_v1, bi_anonymous_goals_v1, bi_anonymous_daily_v1, bi_anonymous_daily_rollup_v1, bi_anonymous_coverage_v1, and, when needed, bi_anonymous_geo_events_v1, plus the declared bi_dim_* and bi_glossary_* metadata views needed for labels. Do not grant routine reporting users access to events, analytics_glossary, or other application tables.

Showing all 8 sections

Supported BI contract

bi_anonymous_events_v1

Anonymous only Hourly grain

Each row is one released hourly cell, grouped by every dimension listed below. The current UTC hour and cells below anonymous_min_cell_count are absent. event_hour is labelled in the installation reporting timezone, UTC unless that setting is changed. The default threshold is 5 events and the allowed range is 2–1000.

Columns exposed by bi_anonymous_events_v1
Column Logical type Meaning
website_token String Public website registration token identifying the site, not a visitor or session. Join bi_dim_website_token_v1 for the website name.
event_hour Datetime Completed hour in the installation reporting timezone, UTC unless reporting_timezone is changed and the views are regenerated. The current UTC hour is excluded. One stored UTC hour is one cell. Retained and archived anonymous counts are combined before disclosure checks.
event_name String Fixed safe event name supplied by the implementation. Undeclared names have no glossary row; use a left join and the code as fallback.
page_path Text Server-sanitized page pathname, without query strings or fragments. Paths can still be identifying in context.
referrer_channel Category Coarse source channel, not the original referrer URL. Codes: direct, internal, search, social, email, referral, unknown.
device_class Category Coarse device category derived from viewport width, with a server User-Agent fallback when no valid class is sent. Codes: mobile, tablet, desktop, bot, unknown.
viewport_bucket Category Coarse browser width category. Exact width is not an anonymous reporting dimension. Codes: small, medium, large, unknown.
event_count Integer Events in this hourly cell. Counts occurrences, not people. Cells below the minimum count are withheld, so totals undercount.
The row grain is the combination of the first seven columns. Sum event_count with SUM(...) when removing dimensions from a report. This totals already-released cells; it does not re-run suppression at the broader grain or recover hidden cells.

Conversion BI contract

bi_anonymous_goals_v1

Anonymous only Daily grain

Each row is one released daily goal cell. The view includes only anonymous events with an allowlisted goal retained in goal_event. The current UTC day and cells below anonymous_min_cell_count are absent. The default threshold is 5 goal occurrences and the allowed range is 2–1000.

Columns exposed by bi_anonymous_goals_v1
Column Logical type Meaning
website_token String Public website registration token identifying the site, not a visitor or session. Join bi_dim_website_token_v1 for the website name.
event_day UTC date Completed UTC calendar day. The current day is excluded; retained and archived anonymous counts are combined before disclosure checks.
goal_event String Configured goal code. Disabled definitions retain historical labels; deleted definitions have no glossary row.
event_count Integer Goal occurrences in this completed daily cell, not people or unique converters. Cells below the minimum event count are withheld, so totals undercount.
This view deliberately excludes event name, path, referrer, device, viewport, geography, and identifiers. Do not join it to the hourly or geography views: they have different grains and independent suppression. A configured goal can still be sensitive in context, and a generic rejection warning is an allowlist result—not sensitive-data detection.

Approved BI contract

bi_anonymous_daily_v1

Anonymous only Daily grain

Each row is one released daily cell by page group, referrer channel and device class. Grouping pages and dropping the hour and viewport releases far more of a low-traffic site's events than the hourly view. A cell is withheld below anonymous_min_cell_count, and also when the part of it the hourly view withholds would be smaller than that minimum, so comparing the two views never reveals a small count. Page groups are configured under Reporting → Page groups or as bi_page_groups in YAML.

Columns exposed by bi_anonymous_daily_v1
Column Logical type Meaning
website_token String Public website registration token identifying the site, not a visitor or session. Join bi_dim_website_token_v1 for the website name.
event_day Date Completed day in the installation reporting timezone, UTC unless reporting_timezone is changed and the views are regenerated. The current day in that timezone is excluded. Retained and archived anonymous counts are combined before disclosure checks.
event_name String Fixed safe event name supplied by the implementation. Undeclared names have no glossary row; use a left join and the code as fallback.
page_group Text Label from the first matching bi_page_groups rule, or the sanitized page path when no rule matches. Labels never start with /, so a value starting with / is a path.
referrer_channel Category Coarse source channel, not the original referrer URL. Codes: direct, internal, search, social, email, referral, unknown.
device_class Category Coarse device category derived from viewport width, with a server User-Agent fallback when no valid class is sent. Codes: mobile, tablet, desktop, bot, unknown.
event_count Integer Events in this completed daily cell, not people. Cells below the minimum count are withheld, and so are cells whose withheld hourly part would be smaller than the minimum, so subtracting hourly cells never reveals a small count. Totals can undercount.

Approved BI contract

bi_anonymous_daily_rollup_v1

Anonymous only Daily grain

The daily cells, with the ones too small to release rolled up into coarser rows instead of dropped: devices pooled first, then channels, then pages, then everything for the event and day. A pooled value is (other), meaning the part not shown in more detailed rows. Every row reaches anonymous_min_cell_count and follows the same rule as the daily view against the hourly view, and each event is in at most one row, so daily totals add up. The full-detail rows are exactly the daily view's rows.

Columns exposed by bi_anonymous_daily_rollup_v1
Column Logical type Meaning
website_token String Public website registration token identifying the site, not a visitor or session. Join bi_dim_website_token_v1 for the website name.
event_day Date Completed day in the installation reporting timezone, UTC unless reporting_timezone is changed and the views are regenerated. The current day in that timezone is excluded. Retained and archived anonymous counts are combined before disclosure checks.
event_name String Fixed safe event name supplied by the implementation. Every row keeps its event name.
page_group Text Page group label or sanitized path, or (other) for pages pooled because their own rows were too small. (other) means the pages not shown in more detailed rows.
referrer_channel Category Coarse source channel, or (other) for channels pooled in this row. Codes: direct, internal, search, social, email, referral, unknown.
device_class Category Coarse device category, or (other) for devices pooled in this row. Codes: mobile, tablet, desktop, bot, unknown.
event_count Integer Events in this row, not people. Each event is in at most one row, so totals add up; only a remainder still below the minimum after pooling is left out.
detail_level Category Which dimensions are known: page_channel_device (full detail, same as bi_anonymous_daily_v1), page_channel, page, channel, or day (only the event name).

Approved BI contract

bi_anonymous_coverage_v1

Anonymous only Daily grain

How much of each completed day's anonymous traffic each event view releases, per website, as a band rather than a number, so a report can say how complete it is without revealing the day's total. Days with fewer events than anonymous_min_cell_count have no rows.

Columns exposed by bi_anonymous_coverage_v1
Column Logical type Meaning
website_token String Public website registration token identifying the site, not a visitor or session. Join bi_dim_website_token_v1 for the website name.
event_day Date Completed day in the installation reporting timezone, the same day as the event views, with at least the minimum number of anonymous events. UTC unless reporting_timezone is changed and the views are regenerated. Days below the minimum have no rows.
view_name String The event view this row describes: bi_anonymous_events_v1, bi_anonymous_daily_v1 or bi_anonymous_daily_rollup_v1.
coverage_band Category Share of the day's anonymous events the view releases, as a band: 90-100, 50-90, 10-50 or 0-10 percent. A band, not a number, so the day's total and withheld remainder stay hidden.

Optional BI contract

bi_anonymous_geo_events_v1

Anonymous only Daily grain

Each row is one released daily geography cell. The current UTC day and cells below anonymous_geo_min_cell_count are not shown individually; their counts may be released only in a qualifying other pool. The default threshold is 25 events and the allowed range is 10–1000.

Columns exposed by bi_anonymous_geo_events_v1
Column Logical type Meaning
website_token String Public website registration token identifying the site, not a visitor or session. Join bi_dim_website_token_v1 for the website name.
event_day UTC date Completed UTC calendar day. The current day is excluded; retained and archived anonymous counts are combined before disclosure checks.
event_name String Fixed safe event name supplied by the implementation. Undeclared names have no glossary row; use a left join and the code as fallback.
geo_area Category Coarse approximate network-exit area. Geographic BI pools small cells into other and applies secondary suppression; totals may undercount.
event_count Integer Events in this completed daily geographic cell, not people. Small cells are pooled into other; secondary suppression protects withheld cells. Totals can undercount and thresholds do not guarantee legal anonymity.
This view deliberately excludes path, referrer, device, viewport, and identifiers. Do not join it to the hourly view: the views have different grains and independent suppression. Low-volume areas may be combined into an other pool, including one otherwise-visible area when secondary suppression is needed. Events without a retained geography value are excluded, so geography totals will not match the hourly view.

Metadata reference

BI labels and definitions

8 dimension views

Join declared metadata to reporting codes to display labels such as Tablet or Germany. These views contain configuration and built-in definitions, never observed traffic or counts. Administrators publish them with app:analytics:glossary:sync after migrations or metadata changes, or save through Reporting → BI glossary.

Approved glossary view contracts
ViewJoin key and purpose
bi_dim_event_name_v1event_name; declared event labels.
bi_dim_goal_event_v1goal_event; configured goal labels.
bi_dim_referrer_channel_v1referrer_channel; all built-in channel codes.
bi_dim_device_class_v1device_class; all five device codes.
bi_dim_viewport_bucket_v1viewport_bucket; all viewport codes.
bi_dim_geo_area_v1geo_area; all continents and countries, plus geo_level.
bi_dim_website_token_v1website_token; registered website names and domains, plus declared labels.
bi_glossary_values_v1Filter to one dimension and locale, then join code to the fact's code column.
bi_glossary_columns_v1Filter by object_name and locale for column labels and definitions.

The six dimension views have one row per code in the deployment's default locale, with prefixed fields such as device_class_label and device_class_sort. Relate each one many-to-one to the matching fact column and display the label. For translated labels, filter bi_glossary_values_v1 to one dimension and one published locale before joining; joining all locales multiplies fact rows.

Use a left join and keep the original code when a label is missing: undeclared event names, deleted goals, and the synthetic country:other/continent:other pools have no dimension row.

SELECT f.event_day, f.goal_event,
       COALESCE(d.goal_event_label, f.goal_event) AS goal_label,
       f.event_count
FROM bi_anonymous_goals_v1 f
LEFT JOIN bi_dim_goal_event_v1 d ON d.goal_event = f.goal_event;
Labels, descriptions, and declared codes are published to routine BI readers; keep them free of personal or identifying text. Declaring values for consent-gated properties publishes those codes even when their event values remain private. Glossary joins do not restore withheld cells: sums by group still undercount. Column descriptions for private custom views do not grant access to those facts. Keep the hourly, goal, and geography facts separate.

Extended schema

Custom reporting views

3 custom views

Administrators define JSON properties and SQL column names in Data model; saving the model updates these views for reporting on retained raw events:

  • analytics_custom_events_v1: all event names in both privacy modes.
  • analytics_custom_pageviews_v1: page views only.
  • analytics_custom_goals_v1: events with a retained goal.

Modeled scalar properties become text columns, and numeric properties can also get a number column for calculations. By default the views also have org_internal_traffic (true for your team’s marked browsers) and page_sequence (page depth, while it is on). Missing values, JSON null, arrays, and objects produce SQL null. These views expose individual rows without suppression and need separately approved raw-data access. They include raw rows already marked as archived while those rows remain retained; archive aggregate cells do not contain the custom properties.

The bi_anonymous_* views keep their existing dimensions and disclosure thresholds. Deleting raw events removes their custom properties from reporting, even when archived counts remain available.

Underlying schema

Private source tables

Internal tables
These tables explain how the views are built; they are not the routine BI contract. The private events table contains individual rows and may contain enhanced identifiers or properties. Even anonymous-mode rows can remain personal data in context.

events

This is the unified event store. Logical types are shown because the exact physical SQL type varies across PostgreSQL, MySQL, MariaDB, SQL Server, and SQLite.

Logical columns in the private events table
Column Logical type Mode and purpose
idIntegerGenerated primary key for an individual event row.
website_tokenString (191)Required site key for both modes.
event_nameString (191)Required event name; defaults to view.
urlTextRequired stored page path. Exposed as page_path by the hourly view.
referrerNullable textStored referrer channel; exposed as referrer_channel.
privacy_modeString (20)LocalScore360 writes anonymous or enhanced; defaults to anonymous.
device_classString (20)Coarse device category for both modes.
viewport_bucketString (20)Coarse viewport category for both modes.
geo_areaNullable string (16)LocalScore360 writes only canonical continent:XX or country:XX values; synthetic other values exist only in the geography view.
generalized_user_agentNullable string (191)Enhanced only; forced to null in anonymous mode.
screen_widthNullable integerEnhanced only; forced to null in anonymous mode.
visitor_idNullable string (191)Enhanced only; forced to null in anonymous mode.
session_idNullable string (191)Enhanced only; forced to null in anonymous mode.
consent_stateNullable string (20)granted for enhanced rows; null in anonymous mode.
custom_dataNullable JSONScalar event properties and org_internal_traffic, true or false on every standard-profile event. Anonymous mode retains only explicitly configured consent-free properties and that flag. The bi_anonymous_* views and archives omit this JSON.
goal_eventNullable string (191)Enabled allowlisted goal code; present in anonymous mode only when its definition permits anonymous use.
created_atUTC datetimeUTC hour boundary for anonymous rows; exact server event time for enhanced rows.
archived_atNullable UTC datetimeSet when maintenance has counted the row into the archive tables. The row stays until retention deletes it.

BI disclosure thresholds

Deployment configuration keys in config/aggregate*.yaml supply the disclosure thresholds used by the three BI views.

Configuration keys for BI disclosure thresholds
Configuration key Logical type Meaning
anonymous_min_cell_countIntegerHourly event and daily goal threshold; default 5, allowed range 2–1000.
anonymous_geo_min_cell_countIntegerDaily geography threshold; default 25, allowed range 10–1000.

Saving BI disclosure settings rewrites configuration and regenerates the BI views. Environment overrides still take precedence.

There is no relational websites table. Website names, domains, and tokens live in config/websites.yaml. If reports need friendly names, maintain a controlled token-to-name mapping in the visualization layer or in a separately governed reporting dataset.

Recipes & Patterns

Safe query patterns

SQL recipes

Replace the example token with a parameter supplied by your BI tool. These queries select explicit columns and label results as released counts because enhanced events and unreleased counts are absent. Goal results are occurrence counts rather than unique converters, and geography counts may instead contribute to a released other pool.

Released page views by hour

SELECT
    event_hour,
    page_path,
    SUM(event_count) AS released_page_view_count
FROM bi_anonymous_events_v1
WHERE website_token = 'replace-with-site-token'
  AND event_name = 'view'
GROUP BY event_hour, page_path
ORDER BY event_hour, page_path;

Released goals by day

SELECT
    event_day,
    goal_event,
    event_count AS released_goal_occurrence_count
FROM bi_anonymous_goals_v1
WHERE website_token = 'replace-with-site-token'
ORDER BY event_day, goal_event;

Released page views by area

SELECT
    event_day,
    geo_area,
    SUM(event_count) AS released_page_view_count
FROM bi_anonymous_geo_events_v1
WHERE website_token = 'replace-with-site-token'
  AND event_name = 'view'
GROUP BY event_day, geo_area
ORDER BY event_day, geo_area;
Use SUM(event_count), not COUNT(*). Counting rows counts released grouped cells rather than the events represented by those cells.

Production checklist

Connection checklist

Setup guide

PostgreSQL, MySQL, MariaDB, or SQL Server

  • Create a dedicated database principal; never reuse the application's credentials.
  • Grant only the minimal connection/schema access required plus SELECT on the approved view or views needed; do not grant source-table SELECT. Grant statements for each database (opens in a new tab).
  • Use TLS and restrict the principal to the BI service's expected network location.
  • Review and reapply view grants after upgrades because migrations may recreate the views.
  • A shared view exposes every website token in it; BI filters are not tenant isolation.

SQLite

  • SQLite has no database users or object-level view grants.
  • A read-only database file still allows access to the private events table.
  • Have a trusted process export explicit columns from the approved views.
  • Protect exported files and use a server database when direct BI access is required.

To keep BI tools off the application database, including with SQLite, the dashboard's Sync page copies reporting views to a separate reporting database or to Google BigQuery on a schedule.


Model and refresh settings

  • Configure event_hour as the reporting timezone, UTC unless that setting is changed; the physical timestamp may not carry a timezone marker. Goal and geography days stay UTC.
  • Connector-specific physical types vary; model event_day as a date and event_count as a whole number.
  • Expect new hourly event data only after an hour completes, and goal and geography data only after a UTC day completes.
  • Treat missing cells as withheld or unavailable, not as confirmed zero traffic.
  • Remember that event_count counts event or goal occurrences, not visitors, unique people, or unique converters.
  • Review stored BI extracts separately; later threshold changes do not remove earlier exports.
Suppression reduces disclosure risk but does not establish k-anonymity or guarantee that released data is legally anonymous. Apply appropriate retention, access controls, and review to the visualization tool and its extracts.