---
title: "Raw event export files"
description: "Every folder, file and column of the raw event export to your own S3, Google Cloud Storage or SFTP storage, plus the daily lookup files and empty-hour files."
type: "reference"
audience: [network-manager]
keywords: [raw event export, raw data, log-level data, data feed, S3, Google Cloud Storage, SFTP, Parquet, Athena, Spark, columns, schema, transaction id, match tables, lookup file, ISCI, empty file, hive partitions]
ui_path: "No console page: Epom support sets the export up"
---

Fetch the complete documentation index at: https://epom.com/ad-server/docs/llms.txt. Use this file to discover all available pages before exploring further. Append .md to any documentation page URL to get its markdown version.

# Raw event export files

The [raw event export](https://epom.com/ad-server/docs/concepts/analytics-pipelines-explained.md#raw-event-files-in-your-own-storage-s3-google-cloud-storage-sftp)
delivers the ad server's event logs to your own storage, hour by hour. This page lists what lands
there, so a data team can load the files without asking what a folder or a column means.

## Who this is for

Whoever loads the files into a warehouse or query tool. There is no console page for the export:
Epom support sets it up, and you need access to the storage, not a permission in the console.

## Folders and file names

```text
<root>/stream=<name>-<id>/t=<event>/dt=<YYYY-MM-DD>/h=<H>/<YYYY-MM-DD-HH>-<server>.parquet.gz
```

| Part | Meaning |
|---|---|
| `<root>` | The folder agreed when the export was set up |
| `stream=` | The name of this export, fixed for your network |
| `t=` | The event type, see [Event types](#event-types) |
| `dt=`, `h=` | Day and hour **in UTC**, whatever time zone your reports use. `h=` has no leading zero: `h=3` |
| `<server>` | The number of the ad server that wrote the file |

`stream=`, `t=`, `dt=` and `h=` are standard Hive-style partition folders, which query engines can
read as columns. There is **one file per ad server, per hour, per event type**, so to read an hour
read the whole `h=` folder.

Files are ordinary Parquet with gzip compression inside, despite the `.gz` at the end of the name.
Treat them as Parquet: a tool that guesses the format from the extension may need telling.

## Event types

| `t=` | What one row is |
|---|---|
| `adRequests` | An ad request |
| `adRequestsRepeated` | A repeated ad request, the one counted as **Repeated** in reports |
| `noImpressions` | A request answered without an ad |
| `impressions` | An impression |
| `passback` | A passback |
| `clicks` | A click |
| `actions` | A conversion, or a VAST playback event tracked as a system action |
| `actionsExpired` | A conversion that matched an event older than its attribution window |
| `piggyback` | A piggyback pixel the ad server fired, with [its own columns](#piggyback-columns) |

A network can have some of these turned off, in which case that folder never appears.

## Columns

Every event type except `piggyback` has these columns. Columns are only ever added at the end, so
files from before a column existed lack it: read them with schema merging on.

### Time and identity

| Column | Type | Meaning |
|---|---|---|
| `date` | long | **Event time, in milliseconds since the Unix epoch.** It has no time zone problem, so use it for time, not the folder |
| `transactionId` | long | Ties together one ad serve: its request, impression, clicks and conversions |
| `epomUUID` | string | User ID. Empty where GDPR keeps it off the record |
| `ifa` | string | Advertising ID, under the same GDPR rule |
| `duration`, `eventType` | long, int | Not used: always `0` and `1`. The `t=` folder is the event type |

### Entities

The rows carry **IDs, not names**. See [Daily lookup files](#daily-lookup-files).

| Column | Type | Meaning |
|---|---|---|
| `placementId`, `zoneId`, `siteId` | long | The inventory. `0` when the request named no known placement |
| `bannerId`, `campaignId`, `advertiserId` | long | The demand. `0` when no creative is involved |
| `actionId` | long | The conversion action or VAST event. `0` outside `actions` and `actionsExpired` |
| `channel` | string | The channel |
| `placementType` | long | Numeric ID of the [placement type](https://epom.com/ad-server/docs/reference/placement-types.md) |
| `placementWidth`, `placementHeight` | long | Placement size |
| `placementLabels`, `bannerLabels` | array of long | Label IDs |

### Money

| Column | Type | Meaning |
|---|---|---|
| `gross` | double | What this event charged the advertiser, in the network currency |
| `net` | double | What this event earned the publisher, in the network currency |

Sum the column to get a total. Neither includes a share of the ad server fee, as in the
[log reports](https://epom.com/ad-server/docs/concepts/analytics-pipelines-explained.md).

### Where the viewer is

| Column | Type | Meaning |
|---|---|---|
| `ip` | string | Viewer IP, masked where GDPR requires it |
| `remoteIp`, `xforwardedFor` | string | The connecting address and the forwarding chain, masked the same way |
| `country` | string | Two-letter code, `-` when unknown. Great Britain is `UK`, not `GB` |
| `location` | string | `region - city` |
| `carrier`, `connectionType`, `proxy` | string | Mobile carrier, connection type, proxy type |
| `timeZone` | float | The browser's UTC offset in hours |
| `timeZoneName`, `browserCountry` | string | The browser's IANA zone, and the country that zone points to |
| `language`, `acceptLanguage` | string | Browser language and the `Accept-Language` header |

`timeZoneName` and `language` are sent with the ad request, so they are often empty on impressions
and clicks.

### Device

| Column | Type | Meaning |
|---|---|---|
| `userAgent` | string | User agent, replaced with a placeholder where GDPR requires it |
| `browser`, `browserVersion`, `os`, `osVersion` | string | `browserVersion` is the major version only |
| `deviceFormat`, `deviceVendor`, `deviceModel`, `deviceModelCode` | string | Device as detected |
| `deviceReleaseYear`, `deviceRAM` | int | `0` or empty when unknown |
| `priceBand` | string | Device price band |
| `browserRank`, `hardwareRank`, `platformRank` | int | Device-quality rankings |
| `screenWidth`, `screenHeight` | int | Screen size |
| `isWebApp`, `isIncognitoMode` | boolean | Empty when unknown |

### Where the request came from

| Column | Type | Meaning |
|---|---|---|
| `origin` | string | **Top Domain**: the page the ad was served on |
| `referer` | string | The domain the event's own request came from, which can be a player or an ad frame |
| `hdrOrigin`, `hdrReferer`, `hdrXReferer` | string | The headers that event arrived with |
| `appPackage` | string | App package name |
| `requestUrl` | string | The full request URL. Empty unless Epom support has turned it on for your network |
| `customParameters`, `cookies` | map | Custom parameters and cookies of the request, minus any your network excludes from logging |
| `trafficSource` | string | `HEADER_BIDDING` for traffic answered by the header-bidding endpoint, otherwise empty |

### Quality and outcome

| Column | Type | Meaning |
|---|---|---|
| `isFraud` | boolean | The ad server flagged this event as fraud |
| `invalid` | boolean | The hit failed validation and did not count. These rows exist only where your network keeps invalid records |
| `rejectReason` | string | Why tracking validation flagged the hit. A check in monitoring mode flags a hit that still counts |
| `riskScore`, `riskLevel`, `riskCategory` | double, string | Traffic-quality scoring |
| `responseCode` | int | HTTP status returned to this hit |
| `responseType` | int | On ad requests: `0` ad markup, `1` default code, `2` empty, `3` VPAID. `4` to `6` are internal variants |
| `attributionType` | int | On conversions: `0` unspecified, `1` post-click, `2` post-view, `3` post-click expired, `4` post-view expired, `5` system |
| `attributedEventDate` | long | On conversions: the time of the click or impression it was attributed to, in epoch milliseconds |

`fraudMetric`, `rejectedByForensiq` and `piggybacks` are in the schema but always empty.

### Piggyback columns

`t=piggyback` has its own short schema: `date`, `transactionId`, `placementId`, `bannerId`,
`actionId`, `country`, `channel`, `url` (the pixel fired) and `responseCode` (what it answered).

## Daily lookup files

Epom support can also switch on daily ID-to-name files, the equivalent of match tables in Google Ad
Manager Data Transfer. They sit under their own top-level folder, so nothing reading the `stream=`
folders meets a different schema:

```text
<root>/match=<name>-<id>/t=<table>/dt=<YYYY-MM-DD>/<table>-<YYYY-MM-DD>.parquet.gz
```

| `t=` | Columns | Join on |
|---|---|---|
| `banners` | `bannerId`, `bannerName`, `universalAdId` (the ISCI or Ad-ID code), `universalAdIdRegistry`, `campaignId`, `campaignName`, `advertiserId`, `advertiserName`, `deleted` | `bannerId` |
| `placements` | `placementId`, `placementName`, `zoneId`, `zoneName`, `siteId`, `siteName`, `deleted` | `placementId` |
| `actions` | `actionId`, `actionName`, `vastEvent` (the event name the player fires, such as `firstQuartile`, empty for an ordinary conversion), `deleted` | `actionId` |

Each file is a snapshot of the whole network taken once a day, shortly after midnight UTC. Deleted
entities stay in because older events still point at them.

> **Corner case:** a creative created after today's file was written appears in tomorrow's. For a
> row of today that finds no name, look in the next day's file.

## Empty-hour files

Epom support can also switch on a file for an hour with nothing to report. Each ad server then
writes, for every event type it had no events of in the hour that just closed, a valid Parquet file
with no rows:

```text
.../h=14/2026-11-08-14-5.empty.parquet.gz
```

With this on, an hour reads like this:

| In the `h=` folder for a server | Meaning |
|---|---|
| A `.parquet.gz` file | Events, normally |
| A `.empty.parquet.gz` file | That server was up for the whole hour and had no events of this type |
| Neither | **A problem:** the server was down for some or all of the hour, or could not deliver. Ask Epom support |

Reading the folder as usual is safe, because an empty file adds no rows.

> **Corner case:** a late real file arrives under its normal name beside the empty one. Nothing is
> overwritten, and reading both gives the right rows. If a server stalled and wrote that hour's events
> later, the hour can show an empty file while its events sit in a later file: `date` still tells them apart.

## Corner cases & gotchas

> **Corner case:** an event can land in the file of the next hour, because a file holds what the
> server wrote to disk during that hour, not what happened during it. If the server stalled, the gap
> can be longer. Use `date` for time and the folders only to find files.

> **Corner case:** folder days are UTC and report days are your report's zone, so a day's files never
> line up exactly with a report's day. Filter on `date` to compare.

> **Corner case:** a row holds no ISCI or Ad-ID code even though the log reports show one. Reports
> look it up from the creative when you run them. Join the `banners` lookup file to get it.

## Related

- [Raw event files in your own storage](https://epom.com/ad-server/docs/concepts/analytics-pipelines-explained.md#raw-event-files-in-your-own-storage-s3-google-cloud-storage-sftp)
- [Report types](https://epom.com/ad-server/docs/guides/analytics/report-types.md)
- [Analytics metrics reference](https://epom.com/ad-server/docs/reference/metrics.md)