> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hightouch.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Exposure Log Matching output reference

> Find the tables, views, and columns Hightouch writes to your warehouse for matched exposure logs, and query them.

> [!NOTE]
>
> Exposure Log Matching is available to [Match Booster](https://docs.hightouch.com/match-booster/overview) customers and must be enabled by Hightouch. [Contact us](#pylon-chat) to turn it on.

## Overview

Hightouch writes matched exposure logs to your warehouse as one table per feed per UTC day. It also keeps one view per feed that combines the last 90 days. Each row is one impression or click.

## Where Hightouch writes logs

Exposure Log Matching writes to Snowflake, Databricks, Trino, and PostgreSQL sources with the [Lightning sync engine](https://docs.hightouch.com/syncs/lightning-sync-engine.md) enabled.

Hightouch writes matched logs to the Match Booster schema in your source warehouse. Unless you've configured a separate Match Booster schema, this is your planner schema: `hightouch_planner` by default, or your custom name if you've renamed it.

## Tables and views

For each feed, Hightouch writes a daily table for each UTC day of logs and maintains one view that combines those daily tables. Query the view. Use a daily table only when you need a single day.

| Object | Name | Contents |
| - | - | - |
| Daily table | `ht_model_<modelId>_exposure_logs_<feed>_file_<YYYYMMDD>_<pathSuffix>` | One UTC day of logs, one row per event |
| View (default) | `ht_model_<modelId>_exposure_logs_<feed>` | All daily tables from the last 90 days |
| Snapshot (alternative to the view) | `ht_model_<modelId>_exposure_logs_<feed>_snapshot` | The same rows as the view, stored as a table |

The parts of each name are:

* **`<modelId>`** — The ID of the model Hightouch matches logs to.
* **`<feed>`** — `impressions` or `clicks`.
* **`<YYYYMMDD>`** — The date of the ad platform's log file. It isn't each row's event time. To filter by event time, use the event time column in the rows.
* **`<pathSuffix>`** — A shortened, lowercase form of the log file's path. Hightouch cuts it so the full table name stays within 63 characters. It isn't an ID you can look up.

For example, model `123` produces these names for impressions:

* Daily table: `ht_model_123_exposure_logs_impressions_file_20260601_<pathSuffix>`
* View: `ht_model_123_exposure_logs_impressions`
* Snapshot: `ht_model_123_exposure_logs_impressions_snapshot`

### Choose a view or a snapshot

Hightouch uses a view by default. The view combines the daily tables from the last 90 days with `UNION ALL`, and Hightouch replaces it on each run. Any changes you make to the view are overwritten, so build your own views on top of it to add logic.

If your warehouse or tools can't read views, Hightouch can write a snapshot table instead. Hightouch keeps only one of the two up to date for each model. If you switch, the one you switch away from stays in your warehouse but stops updating. To switch, [contact us](#pylon-chat).

## Columns Hightouch adds

Hightouch adds two columns to every row. All other columns come from the ad platform unchanged, except for redacted identifiers. Your platform's page lists its columns.

| Column | Type | Description |
| - | - | - |
| **`ID`** | String | The SHA-256 hex digest of the primary key of the model record the row matched, such as a customer ID or household ID. Hightouch casts the key to text before hashing. Empty when the row didn't match. |
| **`IS_FIRST_PARTY_MATCH`** | Boolean | `TRUE` when the match used identifiers mapped in your model's Match Booster configuration. `FALSE` when the match used only the Match Booster identity graph. Empty when the row didn't match. |

When a row matches both ways, Hightouch uses the first-party match.

## How rows are handled

* **Every row is kept.** Hightouch writes every row the ad platform sends, matched or not.
* **Some identifiers are redacted.** Device ID and cookie values stay on rows that are unmatched or matched from your own data. Every other identifier value, including UID2s, is replaced with the word `REDACTED`. Your platform's page lists the exact columns.

## Delivery and history

* **Finished UTC days** — Each delivery covers one finished UTC day. Logs for a UTC day usually arrive the following UTC day. Clicks for a day arrive after that day's impressions.
* **Start date** — History starts on the date set during setup, which by default is the day Exposure Log Matching is enabled. Hightouch doesn't backfill logs from before that date.
* **Late logs** — If a day's logs arrive late, Hightouch picks up that day automatically for up to 7 days.
* **Failed days** — Hightouch retries a failed day once a day, up to five times. Hightouch doesn't notify you when a day fails, so if a day is missing from the view, [contact us](#pylon-chat).

## Retention

The view and snapshot cover up to 90 days of daily tables. For a new setup, they start with the first delivered day and grow as each day is delivered. On PostgreSQL and Trino, the view appears only after the first day is delivered.

Hightouch doesn't drop daily tables after 90 days. They stay in your warehouse until you delete them. To analyze more than 90 days at once, query the daily tables directly or copy them into your own table.

## Sample queries

These examples use Snowflake syntax, the default `hightouch_planner` schema, and the impressions view for model `123`. Replace the schema and model ID with yours, and replace placeholders in angle brackets with column names from your platform's page.

Column names are uppercase. Snowflake accepts them unquoted. On Databricks, PostgreSQL, and Trino, quote them: for example, `"ID"` in PostgreSQL and Trino, or `` `ID` `` in Databricks.

### Match rate

This query returns the share of impressions that matched a record in your model.

```sql theme={null}
SELECT
  COUNT(*) AS total_impressions,
  COUNT(ID) AS matched_impressions,
  COUNT(ID) * 1.0 / COUNT(*) AS match_rate
FROM hightouch_planner.ht_model_123_exposure_logs_impressions;
```

### Matches by source

This query compares matches made with your first-party identifiers to matches made with the Match Booster identity graph.

```sql theme={null}
SELECT
  IS_FIRST_PARTY_MATCH,
  COUNT(*) AS impressions
FROM hightouch_planner.ht_model_123_exposure_logs_impressions
WHERE ID IS NOT NULL
GROUP BY IS_FIRST_PARTY_MATCH;
```

### Reach and frequency by campaign

The same impression can occasionally appear on more than one row, so this query counts distinct impression IDs rather than rows.

```sql theme={null}
SELECT
  <campaign_column>,
  COUNT(DISTINCT ID) AS reach,
  COUNT(DISTINCT <impression_id_column>) * 1.0 / COUNT(DISTINCT ID) AS avg_frequency
FROM hightouch_planner.ht_model_123_exposure_logs_impressions
WHERE ID IS NOT NULL
GROUP BY <campaign_column>;
```

### Impressions by customer segment

This query joins the view to your customer table on the SHA-256 hex digest of its primary key. For hash expressions on other warehouses, see [Add a hashed primary key column](https://docs.hightouch.com/exposure-log-matching/setup.md#add-a-hashed-primary-key-column).

```sql theme={null}
SELECT
  c.ltv_tier,
  COUNT(DISTINCT e.<impression_id_column>) AS impressions,
  COUNT(DISTINCT e.ID) AS customers_reached
FROM hightouch_planner.ht_model_123_exposure_logs_impressions AS e
JOIN <your_customer_table> AS c
  ON e.ID = LOWER(SHA2(CAST(c.<primary_key> AS VARCHAR), 256))
GROUP BY c.ltv_tier;
```
