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

# OpenAI Ads as a data source

> Bring data from OpenAI Ads to your Lakehouse.

OpenAI Ads is OpenAI's advertising platform. Ads appear inside ChatGPT conversations, in clearly labeled cards below the assistant's answer, and are managed in OpenAI Ads Manager — which is why the platform is often referred to as ChatGPT Ads. The connector reads OpenAI's Advertiser API to extract the structure of your ad account — campaigns, ad groups, ads, custom audiences and conversion settings — together with the daily delivery reporting behind it: impressions, clicks, spend, click-through rate, cost per click, cost per thousand impressions and attributed conversions.

Reporting is aggregated by design. OpenAI exposes performance at the account, campaign, ad group and ad level, and optionally broken down by country, device or catalog product. Individual ChatGPT conversations and personal user data are never available.

## Configuring OpenAI Ads as a Source

In the [Sources](https://app.nekt.ai/sources) tab, click on the "Add source" button located on the top right of your screen. Then, select the OpenAI Ads option from the list of connectors.

Click **Next** and you'll be prompted to add your access.

### 1. Add account access

OpenAI Ads authenticates with a static **API key**, sent as a bearer token. Each key is scoped to a single ad account.

<Steps>
  <Step title="Open Ads Manager">
    Sign in at [ads.openai.com](https://ads.openai.com) with the ad account you want to extract data from.
  </Step>

  <Step title="Go to Settings">
    Open the **Settings** tab.
  </Step>

  <Step title="Issue an API key">
    Create a new API key and copy the value.
  </Step>
</Steps>

<Note>
  This is not the same credential as an OpenAI API key from `platform.openai.com`. The Ads API uses its own key, issued from Ads Manager.
</Note>

The following configurations are available:

* **API Key**: the key you copied from Ads Manager.

* **Start Date**: the earliest date from which reporting records will be synced. Leave it empty to sync the last year, which covers the entire history of any ad account. The API does not serve data older than five years.

* **Lookback Days**: (Default: 7 days) how many days before the last synced day each run re-reads. Delivery metrics and attributed conversions keep being adjusted for a few days after the fact, so the lookback ensures recent days stay correct.

<Note>
  Because a key is tied to one ad account, an advertiser managing several accounts needs one Nekt source per account.
</Note>

Once you're done, click **Next**.

### 2. Select streams

Choose which data streams you want to sync. For faster extractions, select only the streams that are relevant to your analysis. You can select entire groups of streams or pick specific ones.

> Tip: The stream can be found more easily by typing its name.

Select the streams and click **Next**.

### 3. Configure data streams

Customize how you want your data to appear in your catalog. Select the desired layer where the data will be placed, a folder to organize it inside the layer, a name for each table (which will effectively contain the fetched data) and the type of sync.

* **Layer**: choose between the existing layers on your catalog. This is where you will find your new extracted tables as the extraction runs successfully.
* **Folder**: a folder can be created inside the selected layer to group all tables being created from this new data source.
* **Table name**: we suggest a name, but feel free to customize it. You have the option to add a **prefix** to all tables at once and make this process faster!
* **Sync Type**: you can choose between INCREMENTAL and FULL\_TABLE.
  * Incremental: every time the extraction happens, we'll get only the new data - which is good if, for example, you want to keep every record ever fetched.
  * Full table: every time the extraction happens, we'll get the current state of the data - which is good if, for example, you don't want to have deleted data in your catalog.

Once you are done configuring, click **Next**.

### 4. Configure data source

Describe your data source for easy identification within your organization, not exceeding 140 characters.

To define your [Trigger](https://docs.nekt.com/runs/scheduling-and-triggers), consider how often you want data to be extracted from this source. Daily is usually enough, since reporting is bucketed by day.

Optionally, you can define some additional settings:

* Configure Delta Log Retention and determine for how long we should store old states of this table as it gets updated. Read more about this resource [here](https://docs.nekt.com/get-started/core-concepts/resource-control).
* Determine when to execute an **Additional [Full Sync](https://docs.nekt.com/get-started/core-concepts/types-of-sync#additional-full-sync)**. This will complement the incremental data extractions, ensuring that your data is completely synchronized with your source every once in a while.

Once you are ready, click **Next** to finalize the setup.

### 5. Check your new source

You can view your new source on the [Sources](https://app.nekt.ai/sources) page. If needed, manually trigger the source extraction by clicking on the arrow button. Once executed, your data will appear in your Catalog.

<Warning>For you to be able to see it on your [Catalog](https://app.nekt.ai/catalog), you need at least one successful source run.</Warning>

# Streams and Fields

## Available streams

The table below lists every stream, its **slug** (the exact identifier to pass when creating the source via API) and a short description. Streams marked *optional* are only served to ad accounts OpenAI has enabled the corresponding feature for — when it is not enabled, the stream is skipped with a warning in the run log and the rest of the extraction continues normally.

| Stream                       | Slug                           | Description                                                                                 |
| ---------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------- |
| Ad Account                   | `ad_account`                   | The ad account the API key belongs to, with its currency, time zone and review state.       |
| Campaigns                    | `campaigns`                    | Campaigns and their budgets, bidding type and targeting.                                    |
| Ad Groups                    | `ad_groups`                    | Ad groups within each campaign.                                                             |
| Ads                          | `ads`                          | Individual ads, with the creative that runs in ChatGPT.                                     |
| Custom Audiences             | `custom_audiences`             | *Optional.* Uploaded customer lists available for targeting.                                |
| Conversion Event Settings    | `conversion_event_settings`    | *Optional.* Conversion events configured for the account and their attribution windows.     |
| Ad Account Insights          | `ad_account_insights`          | Daily delivery totals for the whole account.                                                |
| Campaign Insights            | `campaign_insights`            | Daily delivery metrics per campaign.                                                        |
| Ad Group Insights            | `ad_group_insights`            | Daily delivery metrics per ad group.                                                        |
| Ad Insights                  | `ad_insights`                  | Daily delivery metrics per ad.                                                              |
| Campaign Insights by Country | `campaign_insights_by_country` | *Optional.* Daily campaign metrics broken down by country.                                  |
| Campaign Insights by Device  | `campaign_insights_by_device`  | *Optional.* Daily campaign metrics broken down by device type.                              |
| Campaign Insights by Product | `campaign_insights_by_product` | *Optional.* Daily campaign metrics broken down by catalog item, for product-feed campaigns. |
| Campaign Conversion Insights | `campaign_conversion_insights` | *Optional.* Attributed conversions per campaign per day.                                    |

## Fields by stream

Below you'll find all available data streams from OpenAI Ads and their corresponding fields:

<AccordionGroup>
  <Accordion title="Ad Account">
    The single ad account the API key is scoped to (`GET /ad_account`). One row, carrying the account's currency, time zone and review state.

    Primary key: `id`

    | Field                                 | Type   | Description                                                                                                               |
    | :------------------------------------ | :----- | :------------------------------------------------------------------------------------------------------------------------ |
    | `id`                                  | String | Unique identifier of the ad account the API key is scoped to.                                                             |
    | `name`                                | String | Display name of the ad account, as shown in Ads Manager.                                                                  |
    | `url`                                 | String | Advertiser website associated with the ad account. OpenAI crawls it to build and review ad creatives.                     |
    | `preview_url`                         | String | URL used to preview how the account's ads render in ChatGPT.                                                              |
    | `status`                              | String | Current state of the ad account (for example active or paused). A paused account serves no ads.                           |
    | `timezone`                            | String | IANA time zone of the ad account. Reporting day boundaries and date ranges are interpreted in this time zone.             |
    | `currency_code`                       | String | ISO currency code every spend and bid amount on the account is denominated in.                                            |
    | `review_status`                       | String | Outcome of OpenAI's review of the account: in\_review, approved or rejected. Ads only serve once the account is approved. |
    | `review_reason`                       | String | Reason code explaining a rejected or pending review, such as crawl\_failed, robots\_txt or missing\_favicon.              |
    | `account_integrity_review_status`     | String | Outcome of the separate advertising-policy integrity review of the account: in\_review, approved or rejected.             |
    | `account_integrity_review_reason`     | String | Reason code explaining the integrity review outcome.                                                                      |
    | `account_integrity_decision`          | String | Decision recorded by the integrity review, when OpenAI exposes the detailed breakdown.                                    |
    | `account_integrity_details_reason`    | String | Free-text explanation attached to the integrity review decision.                                                          |
    | `account_integrity_status_updated_at` | String | When the integrity review status was last changed.                                                                        |
  </Accordion>

  <Accordion title="Campaigns">
    Campaigns in the ad account (`GET /campaigns`), with their budgets, bidding type and targeting.

    Primary key: `id`

    | Field                                | Type     | Description                                                                                                                    |
    | :----------------------------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------- |
    | `id`                                 | String   | Unique identifier of the campaign.                                                                                             |
    | `name`                               | String   | Name given to the campaign in Ads Manager.                                                                                     |
    | `description`                        | String   | Free-text description of the campaign.                                                                                         |
    | `status`                             | String   | Current state of the campaign: active, paused or archived. A campaign must be active for its ads to serve.                     |
    | `mode`                               | String   | Delivery mode of the campaign, when OpenAI sets one.                                                                           |
    | `bidding_type`                       | String   | How the campaign bids — for example clicks, or conversions for a conversion-optimized campaign.                                |
    | `conversion_event_setting_ids`       | Array    | Identifiers of the conversion event settings the campaign optimizes toward. Populated only for conversion-optimized campaigns. |
    | `budget_lifetime_spend_limit_micros` | Integer  | Total amount the campaign may ever spend, in micros of the account currency (1,000,000 micros = 1 unit of currency).           |
    | `budget_daily_spend_limit_micros`    | Integer  | Maximum amount the campaign may spend per day, in micros of the account currency.                                              |
    | `targeting`                          | String   | Targeting configuration of the campaign — included and excluded custom audiences plus geographic locations (JSON object).      |
    | `start_time`                         | Datetime | When the campaign starts delivering. Empty means it starts as soon as it is approved and activated.                            |
    | `end_time`                           | Datetime | When the campaign stops delivering. Empty means it runs until paused or its budget is exhausted.                               |
    | `created_at`                         | Datetime | When the campaign was created.                                                                                                 |
    | `updated_at`                         | Datetime | When the campaign was last modified.                                                                                           |
  </Accordion>

  <Accordion title="Ad Groups">
    Ad groups within each campaign (`GET /ad_groups`). Read one campaign at a time, so every row carries its `campaign_id`.

    Primary key: `id`

    | Field                                     | Type     | Description                                                                                                               |
    | :---------------------------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------ |
    | `id`                                      | String   | Unique identifier of the ad group.                                                                                        |
    | `campaign_id`                             | String   | Identifier of the campaign this ad group belongs to.                                                                      |
    | `name`                                    | String   | Name given to the ad group in Ads Manager.                                                                                |
    | `description`                             | String   | Free-text description of the ad group.                                                                                    |
    | `status`                                  | String   | Current state of the ad group: active, paused or archived. Ads only serve while their ad group is active.                 |
    | `context_hints`                           | Array    | Conversation topics that tell OpenAI when this ad group is relevant, used to match ads to what the user is asking about.  |
    | `product_set`                             | String   | For product-feed ad groups, the merchant feed and the filters that select which catalog products may serve (JSON object). |
    | `bidding_billing_event_type`              | String   | Event the ad group is billed on, for example a click.                                                                     |
    | `bidding_max_bid_micros`                  | Integer  | Maximum bid per billable event, in micros of the account currency (1,000,000 micros = 1 unit of currency).                |
    | `bidding_custom_audience_bid_multipliers` | String   | Per-audience bid adjustments applied on top of the maximum bid (JSON array of objects).                                   |
    | `created_at`                              | Datetime | When the ad group was created.                                                                                            |
    | `updated_at`                              | Datetime | When the ad group was last modified.                                                                                      |
  </Accordion>

  <Accordion title="Ads">
    Individual ads within each ad group (`GET /ads`), with the creative flattened into columns and the review outcome.

    Primary key: `id`

    | Field                 | Type     | Description                                                                                                                   |
    | :-------------------- | :------- | :---------------------------------------------------------------------------------------------------------------------------- |
    | `id`                  | String   | Unique identifier of the ad.                                                                                                  |
    | `ad_group_id`         | String   | Identifier of the ad group this ad belongs to.                                                                                |
    | `campaign_id`         | String   | Identifier of the campaign this ad belongs to.                                                                                |
    | `name`                | String   | Internal name of the ad in Ads Manager. Not shown to users.                                                                   |
    | `status`              | String   | Current state of the ad: active, paused or archived.                                                                          |
    | `review_status`       | String   | Outcome of OpenAI's creative review: in\_review, approved or rejected. An ad only serves once approved.                       |
    | `review_reason`       | String   | Reason code explaining a rejected or pending review, such as crawl\_failed, robots\_txt or unsupported\_content\_type.        |
    | `creative_type`       | String   | Creative format: chat\_card for a static creative, or product\_ad\_template for an ad generated from a merchant product feed. |
    | `creative_title`      | String   | Headline shown on the ad card in ChatGPT.                                                                                     |
    | `creative_body`       | String   | Body copy shown on the ad card in ChatGPT.                                                                                    |
    | `creative_price`      | String   | Price displayed on the ad card, when the creative shows one.                                                                  |
    | `creative_file_id`    | String   | Identifier of the uploaded image file used by the creative.                                                                   |
    | `creative_image_url`  | String   | URL of the image rendered on the ad card.                                                                                     |
    | `creative_target_url` | String   | Landing page the ad sends the user to when clicked.                                                                           |
    | `created_at`          | Datetime | When the ad was created.                                                                                                      |
    | `updated_at`          | Datetime | When the ad was last modified.                                                                                                |
  </Accordion>

  <Accordion title="Custom Audiences">
    Customer lists uploaded for targeting (`GET /custom_audiences`). Requires custom audiences to be enabled on the ad account. Match counts are returned as coarse ranges — OpenAI never exposes exact figures or member identifiers.

    Primary key: `id`

    | Field                             | Type     | Description                                                                                                                          |
    | :-------------------------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------- |
    | `id`                              | String   | Unique identifier of the custom audience.                                                                                            |
    | `name`                            | String   | Name given to the custom audience in Ads Manager.                                                                                    |
    | `description`                     | String   | Free-text description of the custom audience.                                                                                        |
    | `status`                          | String   | Current state of the audience — whether it is still processing an upload, ready to target, or archived.                              |
    | `hash_spec_version`               | String   | Version of the hashing specification used to upload the audience's identifiers.                                                      |
    | `uploaded_identifier_count_range` | String   | Coarse range for how many identifiers were uploaded. OpenAI returns a bucketed range rather than an exact count.                     |
    | `matched_identifier_count_range`  | String   | Coarse range for how many uploaded identifiers were matched to ChatGPT users, which determines how large the targetable audience is. |
    | `invalid_identifier_count_range`  | String   | Coarse range for how many uploaded identifiers were rejected as malformed or incorrectly hashed.                                     |
    | `created_at`                      | Datetime | When the custom audience was created.                                                                                                |
    | `updated_at`                      | Datetime | When the custom audience was last modified.                                                                                          |
  </Accordion>

  <Accordion title="Conversion Event Settings">
    Conversion events configured for the account (`GET /conversions/event_settings`). Requires conversion management to be enabled on the ad account. This is the table that explains how the conversion numbers were attributed.

    Primary key: `id`

    | Field                     | Type    | Description                                                                                                                                                               |
    | :------------------------ | :------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
    | `id`                      | String  | Unique identifier of the conversion event setting.                                                                                                                        |
    | `ad_account_id`           | String  | Identifier of the ad account the setting belongs to.                                                                                                                      |
    | `name`                    | String  | Name given to the conversion event setting in Ads Manager.                                                                                                                |
    | `event_type`              | String  | Standard conversion event being counted, such as a purchase, lead or sign-up.                                                                                             |
    | `custom_event_name`       | String  | Name of the custom event being counted, when the setting tracks a custom event instead of a standard one.                                                                 |
    | `attribution_window_days` | Integer | Number of days after an ad click during which a conversion is still credited to the ad. This window defines the click-through conversion counts reported for the account. |
    | `source_ids`              | Array   | Identifiers of the measurement sources (pixels or server-side keys) that feed this conversion event.                                                                      |
    | `sources`                 | String  | Measurement sources feeding this event, with their names (JSON array of objects).                                                                                         |
    | `campaigns`               | String  | Campaigns optimizing toward this conversion event, with their names (JSON array of objects).                                                                              |
    | `archived`                | Boolean | Whether the setting has been archived and no longer counts new conversions.                                                                                               |
    | `version`                 | Integer | Revision number of the setting, incremented each time it is changed.                                                                                                      |
  </Accordion>

  <Accordion title="Ad Account Insights">
    Daily delivery totals for the whole ad account.

    Primary key: `id`

    Replication key: `start_time` (incremental)

    | Field                        | Type     | Description                                                                                                                                 |
    | :--------------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------ |
    | `id`                         | String   | Identifier of this report row, combining the time bucket with the entity it measures. Unique within the report and used as the primary key. |
    | `start_time`                 | Datetime | Start of the reporting period this row covers, used as the incremental replication key.                                                     |
    | `end_time`                   | Datetime | End of the reporting period this row covers.                                                                                                |
    | `readable_time`              | String   | The reporting period as a calendar label in the ad account's time zone, for example 2026-04-25 for a daily row.                             |
    | `timezone`                   | String   | IANA time zone the reporting period was bucketed in, taken from the ad account.                                                             |
    | `ad_account_id`              | String   | Identifier of the ad account these totals belong to.                                                                                        |
    | `ad_account_name`            | String   | Display name of the ad account.                                                                                                             |
    | `ad_account_url`             | String   | Advertiser website associated with the ad account.                                                                                          |
    | `ad_account_budget_lifetime` | Number   | Lifetime spend limit configured on the ad account, in the account currency.                                                                 |
    | `ad_account_budget_daily`    | Number   | Daily spend limit configured on the ad account, in the account currency.                                                                    |
    | `impressions`                | Integer  | Number of times the account's ads was shown to a user in ChatGPT during the period.                                                         |
    | `clicks`                     | Integer  | Number of clicks the account's ads received during the period.                                                                              |
    | `spend`                      | Number   | Amount spent on the account's ads during the period, in the ad account currency.                                                            |
    | `ctr`                        | Number   | Click-through rate of the account's ads for the period — clicks divided by impressions.                                                     |
    | `cpc`                        | Number   | Average cost per click of the account's ads for the period, in the ad account currency.                                                     |
    | `cpm`                        | Number   | Average cost per thousand impressions of the account's ads for the period, in the ad account currency.                                      |
  </Accordion>

  <Accordion title="Campaign Insights">
    Daily delivery metrics per campaign — the main reporting table.

    Primary key: `id`

    Replication key: `start_time` (incremental)

    | Field                      | Type     | Description                                                                                                                                 |
    | :------------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------ |
    | `id`                       | String   | Identifier of this report row, combining the time bucket with the entity it measures. Unique within the report and used as the primary key. |
    | `start_time`               | Datetime | Start of the reporting period this row covers, used as the incremental replication key.                                                     |
    | `end_time`                 | Datetime | End of the reporting period this row covers.                                                                                                |
    | `readable_time`            | String   | The reporting period as a calendar label in the ad account's time zone, for example 2026-04-25 for a daily row.                             |
    | `timezone`                 | String   | IANA time zone the reporting period was bucketed in, taken from the ad account.                                                             |
    | `campaign_id`              | String   | Identifier of the campaign this row measures. Join to the campaigns stream for its full configuration.                                      |
    | `campaign_name`            | String   | Name of the campaign at the time the report was read.                                                                                       |
    | `campaign_description`     | String   | Description of the campaign at the time the report was read.                                                                                |
    | `campaign_status`          | String   | Current state of the campaign: active, paused or archived. This is the state now, not the state during the reporting period.                |
    | `campaign_start_time`      | String   | Configured start of the campaign's delivery, as returned by the reporting API.                                                              |
    | `campaign_end_time`        | String   | Configured end of the campaign's delivery, as returned by the reporting API.                                                                |
    | `campaign_budget_lifetime` | Number   | Lifetime spend limit of the campaign, in the account currency.                                                                              |
    | `campaign_budget_daily`    | Number   | Daily spend limit of the campaign, in the account currency.                                                                                 |
    | `impressions`              | Integer  | Number of times the campaign was shown to a user in ChatGPT during the period.                                                              |
    | `clicks`                   | Integer  | Number of clicks the campaign received during the period.                                                                                   |
    | `spend`                    | Number   | Amount spent on the campaign during the period, in the ad account currency.                                                                 |
    | `ctr`                      | Number   | Click-through rate of the campaign for the period — clicks divided by impressions.                                                          |
    | `cpc`                      | Number   | Average cost per click of the campaign for the period, in the ad account currency.                                                          |
    | `cpm`                      | Number   | Average cost per thousand impressions of the campaign for the period, in the ad account currency.                                           |
  </Accordion>

  <Accordion title="Ad Group Insights">
    Daily delivery metrics per ad group.

    Primary key: `id`

    Replication key: `start_time` (incremental)

    | Field                  | Type     | Description                                                                                                                                 |
    | :--------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------ |
    | `id`                   | String   | Identifier of this report row, combining the time bucket with the entity it measures. Unique within the report and used as the primary key. |
    | `start_time`           | Datetime | Start of the reporting period this row covers, used as the incremental replication key.                                                     |
    | `end_time`             | Datetime | End of the reporting period this row covers.                                                                                                |
    | `readable_time`        | String   | The reporting period as a calendar label in the ad account's time zone, for example 2026-04-25 for a daily row.                             |
    | `timezone`             | String   | IANA time zone the reporting period was bucketed in, taken from the ad account.                                                             |
    | `campaign_id`          | String   | Identifier of the campaign the ad group belongs to.                                                                                         |
    | `ad_group_id`          | String   | Identifier of the ad group this row measures. Join to the ad groups stream for its full configuration.                                      |
    | `ad_group_name`        | String   | Name of the ad group at the time the report was read.                                                                                       |
    | `ad_group_description` | String   | Description of the ad group at the time the report was read.                                                                                |
    | `ad_group_status`      | String   | Current state of the ad group: active, paused or archived.                                                                                  |
    | `impressions`          | Integer  | Number of times the ad group was shown to a user in ChatGPT during the period.                                                              |
    | `clicks`               | Integer  | Number of clicks the ad group received during the period.                                                                                   |
    | `spend`                | Number   | Amount spent on the ad group during the period, in the ad account currency.                                                                 |
    | `ctr`                  | Number   | Click-through rate of the ad group for the period — clicks divided by impressions.                                                          |
    | `cpc`                  | Number   | Average cost per click of the ad group for the period, in the ad account currency.                                                          |
    | `cpm`                  | Number   | Average cost per thousand impressions of the ad group for the period, in the ad account currency.                                           |
  </Accordion>

  <Accordion title="Ad Insights">
    Daily delivery metrics per ad, including the creative text that ran.

    Primary key: `id`

    Replication key: `start_time` (incremental)

    | Field              | Type     | Description                                                                                                                                 |
    | :----------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------ |
    | `id`               | String   | Identifier of this report row, combining the time bucket with the entity it measures. Unique within the report and used as the primary key. |
    | `start_time`       | Datetime | Start of the reporting period this row covers, used as the incremental replication key.                                                     |
    | `end_time`         | Datetime | End of the reporting period this row covers.                                                                                                |
    | `readable_time`    | String   | The reporting period as a calendar label in the ad account's time zone, for example 2026-04-25 for a daily row.                             |
    | `timezone`         | String   | IANA time zone the reporting period was bucketed in, taken from the ad account.                                                             |
    | `campaign_id`      | String   | Identifier of the campaign the ad belongs to.                                                                                               |
    | `ad_group_id`      | String   | Identifier of the ad group the ad belongs to.                                                                                               |
    | `ad_id`            | String   | Identifier of the ad this row measures. Join to the ads stream for its full creative.                                                       |
    | `ad_name`          | String   | Internal name of the ad in Ads Manager.                                                                                                     |
    | `ad_title`         | String   | Headline shown on the ad card in ChatGPT.                                                                                                   |
    | `ad_copy`          | String   | Body copy shown on the ad card in ChatGPT.                                                                                                  |
    | `ad_link`          | String   | Landing page the ad sends the user to when clicked.                                                                                         |
    | `ad_status`        | String   | Current state of the ad: active, paused or archived.                                                                                        |
    | `ad_review_status` | String   | Outcome of OpenAI's creative review: in\_review, approved or rejected.                                                                      |
    | `impressions`      | Integer  | Number of times the ad was shown to a user in ChatGPT during the period.                                                                    |
    | `clicks`           | Integer  | Number of clicks the ad received during the period.                                                                                         |
    | `spend`            | Number   | Amount spent on the ad during the period, in the ad account currency.                                                                       |
    | `ctr`              | Number   | Click-through rate of the ad for the period — clicks divided by impressions.                                                                |
    | `cpc`              | Number   | Average cost per click of the ad for the period, in the ad account currency.                                                                |
    | `cpm`              | Number   | Average cost per thousand impressions of the ad for the period, in the ad account currency.                                                 |
  </Accordion>

  <Accordion title="Campaign Insights by Country">
    Daily campaign metrics broken down by the user's country. Requires segmented insights to be enabled on the ad account.

    Primary key: `id`

    Replication key: `start_time` (incremental)

    | Field                 | Type     | Description                                                                                                                                 |
    | :-------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------ |
    | `id`                  | String   | Identifier of this report row, combining the time bucket with the entity it measures. Unique within the report and used as the primary key. |
    | `start_time`          | Datetime | Start of the reporting period this row covers, used as the incremental replication key.                                                     |
    | `end_time`            | Datetime | End of the reporting period this row covers.                                                                                                |
    | `readable_time`       | String   | The reporting period as a calendar label in the ad account's time zone, for example 2026-04-25 for a daily row.                             |
    | `timezone`            | String   | IANA time zone the reporting period was bucketed in, taken from the ad account.                                                             |
    | `campaign_id`         | String   | Identifier of the campaign this row measures. Join to the campaigns stream for its full configuration.                                      |
    | `campaign_name`       | String   | Name of the campaign at the time the report was read.                                                                                       |
    | `country_name`        | String   | Country the impressions and clicks in this row came from.                                                                                   |
    | `impressions`         | Integer  | Number of times the campaign was shown to a user in ChatGPT during the period.                                                              |
    | `clicks`              | Integer  | Number of clicks the campaign received during the period.                                                                                   |
    | `spend`               | Number   | Amount spent on the campaign during the period, in the ad account currency.                                                                 |
    | `ctr`                 | Number   | Click-through rate of the campaign for the period — clicks divided by impressions.                                                          |
    | `cpc`                 | Number   | Average cost per click of the campaign for the period, in the ad account currency.                                                          |
    | `cpm`                 | Number   | Average cost per thousand impressions of the campaign for the period, in the ad account currency.                                           |
    | `country_impressions` | Integer  | Number of times this campaign and country combination was shown to a user in ChatGPT during the period.                                     |
    | `country_clicks`      | Integer  | Number of clicks this campaign and country combination received during the period.                                                          |
    | `country_spend`       | Number   | Amount spent on this campaign and country combination during the period, in the ad account currency.                                        |
    | `country_ctr`         | Number   | Click-through rate of this campaign and country combination for the period — clicks divided by impressions.                                 |
    | `country_cpc`         | Number   | Average cost per click of this campaign and country combination for the period, in the ad account currency.                                 |
    | `country_cpm`         | Number   | Average cost per thousand impressions of this campaign and country combination for the period, in the ad account currency.                  |
  </Accordion>

  <Accordion title="Campaign Insights by Device">
    Daily campaign metrics broken down by device type. Requires segmented insights to be enabled on the ad account.

    Primary key: `id`

    Replication key: `start_time` (incremental)

    | Field                | Type     | Description                                                                                                                                 |
    | :------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------ |
    | `id`                 | String   | Identifier of this report row, combining the time bucket with the entity it measures. Unique within the report and used as the primary key. |
    | `start_time`         | Datetime | Start of the reporting period this row covers, used as the incremental replication key.                                                     |
    | `end_time`           | Datetime | End of the reporting period this row covers.                                                                                                |
    | `readable_time`      | String   | The reporting period as a calendar label in the ad account's time zone, for example 2026-04-25 for a daily row.                             |
    | `timezone`           | String   | IANA time zone the reporting period was bucketed in, taken from the ad account.                                                             |
    | `campaign_id`        | String   | Identifier of the campaign this row measures. Join to the campaigns stream for its full configuration.                                      |
    | `campaign_name`      | String   | Name of the campaign at the time the report was read.                                                                                       |
    | `device_type`        | String   | Type of device the impressions and clicks in this row came from, for example mobile or desktop.                                             |
    | `impressions`        | Integer  | Number of times the campaign was shown to a user in ChatGPT during the period.                                                              |
    | `clicks`             | Integer  | Number of clicks the campaign received during the period.                                                                                   |
    | `spend`              | Number   | Amount spent on the campaign during the period, in the ad account currency.                                                                 |
    | `ctr`                | Number   | Click-through rate of the campaign for the period — clicks divided by impressions.                                                          |
    | `cpc`                | Number   | Average cost per click of the campaign for the period, in the ad account currency.                                                          |
    | `cpm`                | Number   | Average cost per thousand impressions of the campaign for the period, in the ad account currency.                                           |
    | `device_impressions` | Integer  | Number of times this campaign and device combination was shown to a user in ChatGPT during the period.                                      |
    | `device_clicks`      | Integer  | Number of clicks this campaign and device combination received during the period.                                                           |
    | `device_spend`       | Number   | Amount spent on this campaign and device combination during the period, in the ad account currency.                                         |
    | `device_ctr`         | Number   | Click-through rate of this campaign and device combination for the period — clicks divided by impressions.                                  |
    | `device_cpc`         | Number   | Average cost per click of this campaign and device combination for the period, in the ad account currency.                                  |
    | `device_cpm`         | Number   | Average cost per thousand impressions of this campaign and device combination for the period, in the ad account currency.                   |
  </Accordion>

  <Accordion title="Campaign Insights by Product">
    Daily campaign metrics broken down by catalog item, for product-feed campaigns. Requires segmented insights to be enabled on the ad account.

    Primary key: `id`

    Replication key: `start_time` (incremental)

    | Field                  | Type     | Description                                                                                                                                 |
    | :--------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------ |
    | `id`                   | String   | Identifier of this report row, combining the time bucket with the entity it measures. Unique within the report and used as the primary key. |
    | `start_time`           | Datetime | Start of the reporting period this row covers, used as the incremental replication key.                                                     |
    | `end_time`             | Datetime | End of the reporting period this row covers.                                                                                                |
    | `readable_time`        | String   | The reporting period as a calendar label in the ad account's time zone, for example 2026-04-25 for a daily row.                             |
    | `timezone`             | String   | IANA time zone the reporting period was bucketed in, taken from the ad account.                                                             |
    | `campaign_id`          | String   | Identifier of the campaign this row measures. Join to the campaigns stream for its full configuration.                                      |
    | `campaign_name`        | String   | Name of the campaign at the time the report was read.                                                                                       |
    | `product_feed_id`      | String   | Identifier of the merchant product feed the item belongs to.                                                                                |
    | `item_id`              | String   | Identifier of the catalog item (the SKU) this row measures, as supplied in the product feed.                                                |
    | `product_title`        | String   | Product title from the merchant feed.                                                                                                       |
    | `product_description`  | String   | Product description from the merchant feed.                                                                                                 |
    | `product_body`         | String   | Body copy generated for the product ad from the feed entry.                                                                                 |
    | `product_brand`        | String   | Brand of the product, as supplied in the merchant feed.                                                                                     |
    | `product_seller_name`  | String   | Seller offering the product, as supplied in the merchant feed.                                                                              |
    | `product_price`        | String   | Product price as supplied in the merchant feed, including its currency formatting.                                                          |
    | `product_availability` | String   | Stock availability of the product from the merchant feed. Out of stock items stop being eligible to serve.                                  |
    | `product_target_url`   | String   | Product landing page the ad sends the user to.                                                                                              |
    | `product_image_url`    | String   | Product image rendered on the ad card.                                                                                                      |
    | `impressions`          | Integer  | Number of times the campaign was shown to a user in ChatGPT during the period.                                                              |
    | `clicks`               | Integer  | Number of clicks the campaign received during the period.                                                                                   |
    | `spend`                | Number   | Amount spent on the campaign during the period, in the ad account currency.                                                                 |
    | `ctr`                  | Number   | Click-through rate of the campaign for the period — clicks divided by impressions.                                                          |
    | `cpc`                  | Number   | Average cost per click of the campaign for the period, in the ad account currency.                                                          |
    | `cpm`                  | Number   | Average cost per thousand impressions of the campaign for the period, in the ad account currency.                                           |
    | `product_impressions`  | Integer  | Number of times this campaign and product combination was shown to a user in ChatGPT during the period.                                     |
    | `product_clicks`       | Integer  | Number of clicks this campaign and product combination received during the period.                                                          |
    | `product_spend`        | Number   | Amount spent on this campaign and product combination during the period, in the ad account currency.                                        |
    | `product_ctr`          | Number   | Click-through rate of this campaign and product combination for the period — clicks divided by impressions.                                 |
    | `product_cpc`          | Number   | Average cost per click of this campaign and product combination for the period, in the ad account currency.                                 |
    | `product_cpm`          | Number   | Average cost per thousand impressions of this campaign and product combination for the period, in the ad account currency.                  |
  </Accordion>

  <Accordion title="Campaign Conversion Insights">
    Attributed conversions per campaign per day. Requires conversion tracking to be enabled on the ad account.

    Primary key: `date`, `campaign_id`

    Replication key: `date` (incremental)

    | Field                       | Type    | Description                                                                                                                                                                       |
    | :-------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `date`                      | Date    | Day the conversions are reported for, in the ad account's time zone. Used as the incremental replication key.                                                                     |
    | `campaign_id`               | String  | Identifier of the campaign the conversions are attributed to. Join to the campaigns stream for its full configuration.                                                            |
    | `conversions`               | Integer | Conversions credited to the campaign on this day. Always equal to click\_through\_conversions — view-through conversions are reported separately and are not added to this total. |
    | `click_through_conversions` | Integer | Conversions that happened after a click on the ad, credited within the click attribution window configured on the account's conversion event setting.                             |
    | `view_through_conversions`  | Integer | Conversions that happened after an ad impression without a click, within a fixed one-day window. Reporting only — these are not used for bidding, billing or cost-per-action.     |
  </Accordion>
</AccordionGroup>

# Data Model

The account structure is a strict hierarchy, and every reporting row carries the ids of its ancestors, so the reporting tables join directly onto the structure tables:

```
ad_account
└── campaigns
    └── ad_groups
        └── ads
```

| To answer                                  | Use                                                                  |
| :----------------------------------------- | :------------------------------------------------------------------- |
| How much did we spend yesterday?           | `ad_account_insights`                                                |
| Which campaign performs best?              | `campaign_insights`                                                  |
| Which creative gets clicked?               | `ad_insights` (carries `ad_title` and `ad_copy`)                     |
| Which countries or devices convert?        | `campaign_insights_by_country`, `campaign_insights_by_device`        |
| Which catalog items sell?                  | `campaign_insights_by_product`                                       |
| How many conversions did a campaign drive? | `campaign_conversion_insights`                                       |
| Why is an ad not serving?                  | `ads.review_status` and `ads.review_reason`, plus `campaigns.status` |

For an ad to be shown, the ad, its ad group and its campaign all have to be active, and the ad has to be approved — check `review_status` before investigating delivery.

# Implementation Notes

### Daily buckets and incremental replication

All reporting streams are bucketed by day and replicate incrementally on `start_time` (on `date` for conversions). Day boundaries follow the ad account's time zone, reported in the `timezone` column.

Each run re-reads the number of days set in **Lookback Days** before the last synced day, because OpenAI restates delivery metrics for a few days after the fact and conversions keep being attributed for the length of the attribution window. Re-read rows replace the previous version rather than duplicating it.

### Currency and micro amounts

Spend, cost per click and cost per thousand impressions are reported in the account currency, available in `ad_account.currency_code`. Budget and bid limits are returned in **micros**: divide by 1,000,000 to get the amount in the account currency.

### Metrics on segmented streams

A segmented row carries two sets of metrics: the campaign-level group (`impressions`, `clicks`, `spend`, and so on) and the segment-level group (`country_impressions`, `device_clicks`, `product_spend`, and so on). Both are extracted because which group holds the value for the individual cell depends on the grouping order the API applies. Use the segment-prefixed columns for the breakdown itself, and the unprefixed ones for the campaign total the row belongs to.

### Conversions

`conversions` is always equal to `click_through_conversions`. View-through conversions — those that follow an impression without a click, within a fixed one-day window — are reported separately in `view_through_conversions` and are **not** included in the total. They are reporting only: cost per action, bidding and billing all remain click-through based.

### Nested fields

Fields with an unpredictable or repeating structure are extracted as JSON strings: `campaigns.targeting`, `ad_groups.product_set`, `ad_groups.bidding_custom_audience_bid_multipliers`, `conversion_event_settings.sources` and `conversion_event_settings.campaigns`. Small, stable objects are flattened into scalar columns instead, such as the campaign budget (`budget_lifetime_spend_limit_micros`), the ad creative (`creative_title`, `creative_body`) and review outcomes (`review_status`, `review_reason`).

### Rate limits

The Advertiser API allows 600 requests per minute per endpoint and 1,200 per minute per ad account. The connector stays well within both: the four delivery reports share a single endpoint and page through up to 2,000 rows per request, so a full day of reporting at every grain costs a handful of requests. If a rate limit is ever reached, the connector waits and retries, and the run log notes that the extraction is taking longer.

### Privacy

The API exposes aggregated performance only. Individual ChatGPT conversations, prompts and personal user data are not available through it. Custom audience match counts are returned as coarse ranges, and uploaded member identifiers can never be read back.
