> For the complete documentation index, see [llms.txt](https://docs.coupler.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.coupler.io/sources/category/ppc/stackadapt.md).

# StackAdapt

Connect StackAdapt to Coupler.io to export advertiser, campaign group, campaign, ad, and country performance — setup, data reference, troubleshooting, and FAQ in one place.

StackAdapt is a self-serve programmatic advertising platform (DSP). It buys native, display, video, connected TV (CTV), audio, and digital out-of-home inventory from one account. Its account structure has four levels: **advertiser → campaign group → campaign → ad**. Agencies typically run one advertiser per client.

Connecting StackAdapt to Coupler.io pulls delivery reporting into your own spreadsheets, warehouse, or BI tool on a schedule, so programmatic sits next to your search and social channels instead of being exported from StackAdapt by hand.

**Why connect StackAdapt to Coupler.io?**

* Report on StackAdapt alongside Google Ads, Facebook Ads, LinkedIn Ads, and other channels in one blended dataset
* Pick the reporting level you need — advertiser, campaign group, campaign, or ad — or break campaigns down by country
* Pull several advertisers in one source, so an agency can cover multiple clients in a single data flow
* Export to AI tools, Google Sheets, Excel, BigQuery, Data Studio, or other supported destinations
* Keep reports current with scheduled refreshes instead of manual CSV downloads

## Prerequisites

Before you start, make sure you have:

* A StackAdapt account with access to at least one advertiser
* A StackAdapt **GraphQL API key**

{% hint style="warning" %}
**The legacy StackAdapt REST API key does not work.** StackAdapt replaced its REST API with GraphQL, so you need a GraphQL key. These keys are usually issued by your StackAdapt account manager rather than generated in the StackAdapt interface. Request one before you start.
{% endhint %}

{% hint style="info" %}
The key determines which advertisers you can choose in Coupler.io. Every StackAdapt report is advertiser-scoped, so the key must have access to at least one advertiser.
{% endhint %}

## Quick start

{% hint style="success" %}
Start with **Campaign performance** at **Daily** granularity. It's the default report type and the grain most reports are built on. The daily split is also what lets scheduled runs fetch only recent days instead of re-pulling the whole range.
{% endhint %}

## How to connect

{% stepper %}
{% step %}
**Get your API key.** Ask your StackAdapt account manager for a GraphQL API key. Copy it and store it securely.
{% endstep %}

{% step %}
**Create a new data flow in Coupler.io.** Search for and select **StackAdapt** as your source.
{% endstep %}

{% step %}
**Click Connect.** Optionally, share the account with your team. Then set the **Environment** to **Production** and paste the key into the **API key** field. To test with mocked data, select **Sandbox** instead, but the key must be issued for the Sandbox environment. The key and the environment must match.
{% endstep %}

{% step %}
**Choose a report type.** Select one of the five options in **Report type** — for example, **Campaign performance**. See [Data Overview](#data-overview) for what each one returns.
{% endstep %}

{% step %}
**Select advertisers.** In **Advertisers**, choose one or more advertisers to export. At least one is required, and you only get data for the advertisers you select.
{% endstep %}

{% step %}
**Set the report period and granularity.** Use the date pickers to set the start and end dates, then set **Split data by period**.
{% endstep %}

{% step %}
**Choose a destination.** Select where the data should land — Google Sheets, Excel, BigQuery, Data Studio, or an AI destination like ChatGPT, Claude, or Gemini.
{% endstep %}

{% step %}
**Run the data flow.** Click **Run** for a manual sync, then set a schedule so the report refreshes on its own.
{% endstep %}
{% endstepper %}

## Configuration options

### Report type

| Report type                     | What it contains                                                                                                       |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Advertiser performance          | One row per advertiser per period                                                                                      |
| Campaign group performance      | One row per campaign group per period. A campaign group is StackAdapt's equivalent of an insertion order in other DSPs |
| Campaign performance            | One row per campaign per period (default)                                                                              |
| Ad performance                  | One row per ad per period                                                                                              |
| Campaign performance by country | One row per campaign and country, and per day when split by Daily                                                      |

See [Data overview](#data-overview) to check which fields and metrics each report type returns.

### Advertisers

Every report is scoped to the advertisers you select. The list is loaded from your StackAdapt account, and each advertiser's name is shown in the dropdown. Select at least one.

Coupler.io always sends your explicit selection to StackAdapt. It never pulls "everything the key can see", so an advertiser you didn't select doesn't appear in the output. Archived advertisers are still listed.

### Report period

Set **Start date** and **End date** with the date pickers. Both dates are inclusive. Delivery data is reported in the StackAdapt account's timezone, and `granularity_start_time` carries that timezone's offset.

Daily, Weekly, and Monthly splits sync incrementally. Because StackAdapt attributes conversions after the fact, Coupler.io re-fetches the trailing 35 days on every run, so recent conversion counts get updated. Total re-fetches the whole range every time.

### Split data by period

| Option  | What you get                           | Available for                                            |
| ------- | -------------------------------------- | -------------------------------------------------------- |
| Total   | One row per entity for the whole range | All report types                                         |
| Daily   | One row per entity per day             | All report types                                         |
| Weekly  | One row per entity per week            | Advertiser, Campaign group, Campaign, and Ad performance |
| Monthly | One row per entity per month           | Advertiser, Campaign group, Campaign, and Ad performance |

{% hint style="warning" %}
**Campaign performance by country supports only Total and Daily.** For weekly or monthly country totals, pull Daily and aggregate in the dataset step with the Aggregate transformation, or in your destination. To request Monthly support, post on [feedback.coupler.io](https://feedback.coupler.io).
{% endhint %}

### Location detail for the country report

Campaign performance by country can optionally break results down further than country — by region, city, ZIP code, DMA, or US congressional district. Each extra level multiplies the number of rows, so add only the ones you need.

## Data Overview

StackAdapt in Coupler.io is organized as five report types. You pick one per source, choose the advertisers, set a date range, and choose how the data is bucketed by time. Fields, grain, and row count follow from those choices.

### Field reference

#### Delivery reports

Advertiser, Campaign group, Campaign, and Ad performance return the same metric columns. Only the entity columns differ.

| Report type                | Entity columns                                                   |
| -------------------------- | ---------------------------------------------------------------- |
| Advertiser performance     | `advertiser_id`, `advertiser_name`                               |
| Campaign group performance | `advertiser_id`, `campaign_group_id`, `campaign_group_name`      |
| Campaign performance       | `advertiser_id`, `campaign_id`, `campaign_name`, `campaign_type` |
| Ad performance             | `advertiser_id`, `ad_id`, `ad_name`, `ad_type`                   |

`campaign_type` and `ad_type` name the channel of the campaign or ad, for example `NativeCampaign` or `NativeAd`.

After the entity columns come the period columns, then the metrics:

| Column                   | Description                                                      |
| ------------------------ | ---------------------------------------------------------------- |
| `granularity_start_time` | Start of the period bucket, with the account's timezone offset   |
| `granularity_end_time`   | End of the period bucket                                         |
| `granularity_type`       | The split you selected: `TOTAL`, `DAILY`, `WEEKLY`, or `MONTHLY` |

#### Delivery metrics

| Group              | Columns                                                                                                                                                                                                                                                |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Volume             | `impressions_bigint`, `unique_impressions_bigint`, `measured_impressions_bigint`, `viewed_measured_impressions_bigint`, `clicks_bigint`, `engagements_bigint`, `page_starts_bigint`, `frequency`                                                       |
| Cost and revenue   | `cost`, `revenue`, `profit`, `conversion_revenue`, `ecpm`, `ecpc`, `ecpa`, `ecpcl`, `ecpe`, `ecpi`, `ecpv`, `rcpm`, `rcpc`, `rcpa`, `rcpcl`, `rcpcv`, `rcpe`, `unique_ecpa`, `roas`                                                                    |
| Rates              | `ctr`, `cvr`, `click_conversion_rate`, `impression_conversion_rate`, `engagement_rate`, `view_rate`, `video_completion_rate`, `audio_completion_rate`                                                                                                  |
| Conversions        | `conversions`, `click_conversions`, `impression_conversions`, `cookie_conversions`, `ip_conversions`, `secondary_conversions`, `click_secondary_conversions`, `impression_secondary_conversions`, `unique_conversions`, plus a `*_bigint` twin of each |
| Video              | `video_starts_bigint`, `video_q1_playbacks_bigint`, `video_q2_playbacks_bigint`, `video_q3_playbacks_bigint`, `video_completions_bigint`                                                                                                               |
| Audio              | `audio_starts_bigint`, `audio_q1_playbacks_bigint`, `audio_q2_playbacks_bigint`, `audio_q3_playbacks_bigint`, `audio_completions_bigint`                                                                                                               |
| Attention and time | `atos`, `atos_units`, `total_time`, `page_time_units`, `companion_banner_viewed`                                                                                                                                                                       |
| Google Analytics 4 | `ga4_sessions`, `ga4_engaged_sessions`, `ga4_total_users`, `ga4_bounce_rate`, `ga4_average_session_duration`                                                                                                                                           |
| App installs       | `app_install`, `mmp_install`, `mmp_cpi`, `mmp_conversions_bigint`, `skan_install`, `skan_cpi`, `skan_conversions_bigint`                                                                                                                               |
| Fees and margins   | `ad_serving`, `targeting`, `viewability_fee`, `enterprise_features`, `margins`, `ssp_revenue`, `cpd_media_cost`, `tp_cpc_cost`, `tp_cpm_cost`                                                                                                          |

#### Campaign performance by country

| Column                                          | Description                                                                                                              |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `advertiser_id`, `advertiser_name`              | The advertiser                                                                                                           |
| `date`                                          | Day of the row. Present only when **Split data by period** is Daily                                                      |
| `country_code`, `country_name`                  | Country (for example `US` and `United States`)                                                                           |
| `region_code`, `region_name`                    | Present when you select **Region**                                                                                       |
| `city`                                          | Present when you select **City**                                                                                         |
| `dma`, `dma_name`                               | Present when you select **DMA** (US only)                                                                                |
| `congressional_district`                        | Present when you select **Congressional district** (US only)                                                             |
| `zip_code`                                      | Present when you select **ZIP code**                                                                                     |
| `campaign_id`, `campaign_name`, `campaign_type` | The campaign                                                                                                             |
| `campaign_group_id`, `campaign_group_name`      | The campaign's group                                                                                                     |
| Metrics                                         | `impressions`, `clicks`, `cost`, `conversions`, `ctr`, `ecpm`, `ecpc`, `ecpa`, `roas`, video and audio metrics, and more |

The country report uses a different metric set from the delivery reports. Counters such as `impressions`, `clicks`, `engagements`, and the video and audio counts are plain numbers, without the `_bigint` suffix. It also adds `views`, `doohPlays` (as `dooh_plays`), `average_impression_time`, and the share-of-total columns described below.

### Common field combinations

| Goal                               | Report type                     | Split data by period | Fields to use                                                                                                 |
| ---------------------------------- | ------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------- |
| Monthly client report              | Campaign performance            | Monthly              | `cost`, `impressions_bigint`, `clicks_bigint`, `conversions`, by `campaign_name` and `granularity_start_time` |
| Portfolio view across clients      | Advertiser performance          | Total or Monthly     | `cost` and `conversions` by `advertiser_name`                                                                 |
| Pacing against the insertion order | Campaign group performance      | Daily                | `cost` by `campaign_group_name` and `granularity_start_time`                                                  |
| Find the creatives that convert    | Ad performance                  | Total                | `conversions` and `cost`, by `ad_name`                                                                        |
| Regional reporting                 | Campaign performance by country | Total or Daily       | `cost` and `conversions` by `country_name` and the location level you selected                                |

### Use cases by role

{% tabs %}
{% tab title="Marketers" %}

* Pull Campaign performance daily into Google Sheets and build a live StackAdapt dashboard in Data Studio
* Append StackAdapt with Google Ads and Facebook Ads in one data flow for a single cross-channel table
* Use Ad performance to compare creatives side by side
* Send campaign performance to ChatGPT or Claude for a written weekly summary
  {% endtab %}

{% tab title="Agencies" %}

* Select several client advertisers in one source and report on them in a single table
* Use Advertiser performance for a roll-up across all clients
* Use Campaign group performance to check pacing against each insertion order
* Add StackAdapt as the programmatic tab of a client report that already refreshes from other channels
  {% endtab %}

{% tab title="Performance analysts" %}

* Load Campaign performance and other ad sources as separate sources in the same data flow, then recalculate CPA from summed `cost` and `conversions`
* Use Campaign performance by country, with region, city, ZIP code, DMA, or congressional district, to find geographies that underperform the campaign average
* Use Ad performance at Daily granularity to measure creative decay across a flight
  {% endtab %}
  {% endtabs %}

## Common Issues

### Connection issues

<details>

<summary>The connection fails with an authentication error</summary>

Check the following:

* **The key is a legacy REST key.** Only GraphQL API keys work. Ask your StackAdapt account manager for a GraphQL key.
* **The environment doesn't match the key.** A key issued for Production won't work against Sandbox, and the other way around. Check **Environment** in the connection settings.
* **The key was pasted with a leading or trailing space, or truncated on copy.** Paste it directly rather than retyping it.
* **The key was revoked or replaced** in StackAdapt, or your access was removed.

Update the key in the source settings and reconnect.

</details>

<details>

<summary>I can't find a way to generate an API key in StackAdapt</summary>

GraphQL API keys are typically issued by your StackAdapt account manager rather than generated in the StackAdapt interface. Contact them and ask for a GraphQL API key for the environment you're connecting.

</details>

### Missing data

<details>

<summary>An advertiser is missing from the Advertisers list</summary>

The list shows the advertisers your API key can access. If an advertiser you expect isn't there, ask your StackAdapt account manager to confirm the key has access to it.

</details>

<details>

<summary>A campaign is missing from the report</summary>

Delivery reports contain rows only for entities that delivered in the selected period. A paused campaign, or one that didn't spend in the range, produces no rows. The country report also drops campaigns with no data in the period. This is expected.

Also check that the campaign's advertiser is selected in the **Advertisers** field.

</details>

<details>

<summary>Some metric columns are empty</summary>

Two groups of columns are empty for many accounts:

* **GA4, SKAdNetwork, MMP, and app-install metrics** are populated only when those integrations are configured on the StackAdapt side.
* **Platform fee and cost-breakdown fields** are empty for most self-serve accounts.

Empty values here are not a Coupler.io error. If you use the **Sandbox** environment, expect many metrics to be empty or mocked.

</details>

### Data discrepancies

<details>

<summary>Numbers don't match what I see in StackAdapt</summary>

Work through these in order:

* **Timezone.** Delivery granularity is reported in the StackAdapt account's timezone, so a day's boundaries follow that clock.
* **Advertiser selection.** Only the advertisers selected in the source are included. Compare with the same advertisers in StackAdapt.
* **Grain.** Advertiser totals won't match a campaign-level view, and the country report splits a campaign across many rows. Compare like with like.
* **Summed ratio metrics.** If CTR, CPC, or CPM looks wrong, check whether your dashboard sums or averages them. Recalculate them from totals — see [Delivery reports](#delivery-reports).
* **Filtered share-of-total percentages.** Percentage-of-total fields in the country report only add up to 100% across the full, unfiltered report.

</details>

## FAQ

<details>

<summary>How do I get a StackAdapt API key?</summary>

Ask your StackAdapt account manager for a GraphQL API key. It's typically issued by StackAdapt rather than generated in the interface. The older REST API key does not work.

</details>

<details>

<summary>Can I pull more than one advertiser in a single source?</summary>

Yes. Select as many advertisers as you need in the **Advertisers** field. Each output row identifies its advertiser by `advertiser_id` and `advertiser_name`, so you can tell clients apart in the destination.

</details>

<details>

<summary>How is billing calculated for the StackAdapt source?</summary>

StackAdapt is billed per advertiser. Each advertiser you select in a source counts as one account. For plan limits and pricing, see the [Coupler.io pricing page](https://www.coupler.io/pricing).

</details>

<details>

<summary>What's the difference between Production and Sandbox?</summary>

Production connects to your real StackAdapt data. Sandbox connects to StackAdapt's test environment, which has sample campaigns and mocked statistics. Use Sandbox only for testing.

</details>

<details>

<summary>Can I get more than one report type in a single table?</summary>

Not from one source — a source returns one report type. But you can load them side by side from one data flow.

Add each report type as a separate source in the same data flow and load each to its own table or sheet in the destination. Joining or appending different report types in the dataset step is not recommended. There is no need for separate data flows.

</details>

<details>

<summary>What is a campaign group?</summary>

A campaign group sits between the advertiser and its campaigns in StackAdapt. It's the equivalent of an insertion order or line item in other DSPs, and it's where budgets are typically set. Use Campaign group performance to track pacing at that level.

</details>

<details>

<summary>Can I get breakdowns by device, audience, or publisher domain?</summary>

Not currently. The source covers the four delivery levels plus the country report, with optional region, city, ZIP code, DMA, and US congressional district detail. To request more breakdowns, post on [feedback.coupler.io](https://feedback.coupler.io).

</details>

<details>

<summary>Can I average the CTR or CPC columns in my dashboard?</summary>

No. They're ratios, so they can't be summed and shouldn't be averaged. Recalculate them at whatever level you're reporting: `CTR = SUM(clicks) / SUM(impressions)`, `CPC = SUM(cost) / SUM(clicks)`, `CPM = SUM(cost) / SUM(impressions) * 1000`.

</details>

<details>

<summary>What timezone is the data in?</summary>

Delivery data is reported in the StackAdapt account's timezone.

</details>

<details>

<summary>Can I combine StackAdapt with Google Ads or Facebook Ads?</summary>

Yes. Add them as additional sources in the same data flow and use **Append** to stack them into one cross-channel table, mapping the shared columns — date, campaign name, impressions, clicks, cost — onto each other. Convert StackAdapt's impressions and clicks to numbers first, and recalculate ratio metrics after appending.

</details>

<details>

<summary>Can I send StackAdapt data to an AI tool?</summary>

Yes. Coupler.io supports AI destinations including ChatGPT, Claude, Gemini, Cursor, Perplexity, and OpenClaw, so you can route performance data straight into one for campaign summaries or optimization suggestions. The connection is read-only: Coupler.io exports StackAdapt data, and it doesn't change your campaigns.

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.coupler.io/sources/category/ppc/stackadapt.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
