---
title: Advertising (Overview)
slug: experience/advertising-overview
docTags: 
createdAt: 2026-10-02T13:00:41.526Z
---

## Summary

Purple Experience displays ads through a **two-layer model**:

- **Ad slots** describe *what* each ad placement is and where its creative comes from. They are defined in ads.json and each slot picks a provider via providerConfig.type (for example, GPT, DIV, ADSPIRIT, or DEFAULT).
- **The ad platform plugin** is the SDK/provider integration that actually loads and serves the ads (Google Publisher Tag, AdSpirit, Audienzz, …). It is configured once per experience in experience.config.json under purple.ads. **Only one ad platform can be active at a time.**

Starting with **PXP 5.0.0**, ad platforms are managed by the **Purple Plugin System (PPS)**. Plugins are **consent-aware**: a plugin only loads after the user has granted consent through your Consent Management Platform (CMP), unless the provider declares that it manages consent itself. Google Publisher Tag was the first provider moved to the Plugin System; other providers are being migrated incrementally.

This page explains the structure. For step-by-step setup of a specific provider, follow the linked provider pages.

## How advertising works

### The two layers

| Layer                            | File                                | Answers                                                                | Example                                   |
| -------------------------------- | ----------------------------------- | ---------------------------------------------------------------------- | ----------------------------------------- |
| **Ad slot** (Layer A)            | ads.json → adSlots\[]               | "What is this placement, and how is its creative defined?"             | A GPT slot with an ad unit code and sizes |
| **Ad platform plugin** (Layer B) | experience.config.json → purple.ads | "Which ad SDK runs in this experience, and with what account/consent?" | The gpt plugin with your network code     |

A single app has **one** platform plugin (Layer B) but **many** ad slots (Layer A).

### Placing an ad in a view

An ad slot only renders when it is placed in a view. In views.json, add a content item of type ad that references a slot id from ads.json:

:::BlockQuote
\{
&#x20; "type": "ad",
&#x20; "adId": "homepage-leaderboard"
}
:::

The ad component looks up homepage-leaderboard in ads.json, reads its providerConfig, and renders it.

### What happens at runtime

1. The experience loads, and the configured platform plugin (purple.ads.\*) is initialized **through the Plugin System**.
2. Before a consent-dependent plugin loads, Purple checks the CMP. If consent is missing, the plugin does not load, and no ads are shown.
3. When an ad component becomes visible, it resolves its slot from ads.json and asks the active provider to render it.
4. Slots of type GPT, ADSPIRIT, and AUDIENZZ are served through the Plugin System. Slots of type TRAFFECTIVE, DIV, HTML, and DEFAULT (static) are rendered directly by the ad component.

## Ad providers at a glance

Each slot's providerConfig.type selects how the slot is rendered. Some providers also require a matching platform plugin under purple.ads.

| Provider             | Slot type   | Platform plugin (purple.ads) | Needs CMP consent to load | Integration path                                      | Details                                                                                    |
| -------------------- | ----------- | ---------------------------- | ------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| Google Publisher Tag | GPT         | gpt                          | Yes                       | Plugin System (PXP 5.0+)                              | [Google Publisher Tag (GPT) Ad Configuration Documentation](docId\:jm0bqlYKl1WL3ae8lzOsZ)  |
| AdSpirit             | ADSPIRIT    | adspirit                     | Manages consent itself    | Plugin System                                         | [AdSpirit Integration](docId\:H-wm0jXLVHeJmNBBZPSGX)                                       |
| Audienzz             | AUDIENZZ    | audienzz                     | Manages consent itself    | Plugin System                                         | [Audienzz Integration](docId\:XxAkB6rm_7eBfUQTMeZZF)                                       |
| Traffective          | TRAFFECTIVE | traffective                  | Yes                       | Component-level (Plugin System migration in progress) | [Traffective ads in  Experience](docId\:rZClsPkBDkyqXl8N8dKbQ)                             |
| DIV container        | DIV         | —                            | —                         | Component-level                                       | [DIV Ad Provider Implementation](docId\:heFuNwkWL11-VpWhif0Q9)                             |
| Static image         | DEFAULT     | —                            | —                         | Component-level                                       | [Static ads](docId\:YOvF3cLRWz4rbraS8CfCy)                                                 |
| HTML / iframe        | HTML        | —                            | —                         | Component-level                                       |                                                                                            |
| Size mapping         | SIZEMAPPING | —                            | —                         | Referenced by GPT slots                               | [GPT Size Mapping](docId\:jm0bqlYKl1WL3ae8lzOsZ)                                           |

:::hint{type="info"}
SIZEMAPPING is not a visible ad. It is a reusable size-mapping definition that a GPT slot references by id through its sizeMapping field.
:::

## Configuration overview

There are two configuration files. Keep provider-specific detail on the provider pages. The snippets below show only the minimal shape.

### 1. The ad configuratin in experience.config.json

Configured under purple.ads. Only one platform is active per experience. Each platform entry accepts a configuration block and an optional consent block.

:::BlockQuote
\{
&#x20; "purple": \{
&#x20;   "ads": \{
&#x20;     "gpt": \{
&#x20;       "configuration": \{
&#x20;         "networkCode": "12345678"
&#x20;       },
&#x20;       "consent": \{
&#x20;         "vendorId": "755",
&#x20;         "iabVendorId": "755"
&#x20;       }
&#x20;     }
&#x20;   }
&#x20; }
}
:::

| Block         | Purpose                                                                                                                                                              |
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| configuration | Provider-specific platform settings (network code, script URLs, etc.). See the provider page.                                                                        |
| consent       | CMP mapping for this provider: vendorId (your CMP's vendor ID for the provider) and iabVendorId (the IAB TCF vendor ID). Used to decide whether the plugin may load. |

:::hint{type="warning"}
If **no CMP is configured** (`purple.consentManagement` is absent), the `consent` block has no effect and consent-gated plugins like GPT load unconditionally — **ads will appear without any consent check**. Make sure a CMP is configured in production.
:::

### 2. The ad slots in ads.json

A top-level object with an adSlots array. Every slot has an id and a providerConfig whose type selects the provider.

:::BlockQuote
\{
&#x20; "adSlots": \[
&#x20;   \{
&#x20;     "id": "homepage-leaderboard",
&#x20;     "providerConfig": \{
&#x20;       "type": "GPT",
&#x20;       "networkCode": "12345678",
&#x20;       "adUnitCode": "/1234567/Homepage\_Leaderboard",
&#x20;       "sizes": \[\[728, 90], \[320, 50]]
&#x20;     }
&#x20;   },
&#x20;   \{
&#x20;     "id": "sidebar-oekotest",
&#x20;     "providerConfig": \{
&#x20;       "type": "DIV",
&#x20;       "attributes": \{
&#x20;         "id": "ad-slot",
&#x20;         "data-zone": "123"
&#x20;       }
&#x20;     }
&#x20;   }
&#x20; ]
}
:::

Common slot fields:

| Field          | Type   | Required | Description                                                                                                                         |
| -------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| id             | string | Yes      | Unique slot id. Referenced from views (adId) and from the Ad Data Source (idPattern).                                               |
| providerConfig | object | Yes      | Provider-specific configuration. providerConfig.type selects the provider; the remaining fields depend on it (see provider pages).  |
| condition      | object | No       | A standard storefront condition that enables/disables the slot at runtime (e.g. by device). See \[TODO: insert link to Conditions]. |

### 3. Placement — views.json

Add an ad content item referencing the slot id (see "Placing an ad in a view" above). Use a condition to serve different slots per device.

### Rendering a list of ads

To render a component whose sole purpose is to show ads (a banner list, an ad swiper), use the **Ad Data Source** (type: "ad", filtered by idPattern).

To interleave ads *between* content items, use the **ad insertion** property on a content data source instead.

For more details, see:

- [Ad Data Source](docId\:g-WZf7NExBjc35Wj8WcmC)&#x20;
- [Embedded ads in Experience](docId\:fBXEGKJkrGezHEwjHksd1)&#x20;

## Consent (CMP)

Ads must respect the user's consent choices. How consent is handled depends on the provider:

- **Consent-gated providers** (e.g. **GPT**): the platform plugin loads **only after** the CMP reports consent for the configured vendor. Set both consent.vendorId and consent.iabVendorId correctly — if either does not match what your CMP reports, the plugin will not load even after the user accepts cookies, and no ads appear.
- **Self-managed providers** (e.g. **AdSpirit**, **Audienzz**): the provider reads consent on its own side, so a consent block is not required for the plugin to load.

The IAB TCF vendor ID for Google is typically 755; always confirm the value in your CMP's vendor list. Global CMP configuration lives under purple.consentManagement.

For more details, see [Consent Manager](docId:8bzzqxDXp7zrSR5rYQL7r)&#x20;

## Developer hooks

For advanced control, implement storefrontHooks. These hooks apply primarily to Plugin System providers (GPT):

| Hook              | Signature                                   | Description                                                                                                                    |
| ----------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| onAdInit          | () => void                                  | Called after the ad platform script has loaded.                                                                                |
| isAdRefreshPaused | () => boolean                               | Return true to pause auto-refresh for all slots.                                                                               |
| beforeRenderAd    | (\{ id, slot, config, refresh }) => boolean | Called before each ad renders or refreshes. Return false to skip it; refresh is true on refresh cycles.                        |
| isAdDisabled      | (id) => boolean                             | Called when an ad component is created. Return true to prevent the slot from initializing at all (e.g. per device/resolution). |

onNavigationStable is also useful for refreshing ads after route changes.

## Migrating from the old format

Before PXP 5.0, ads.json was a **flat array** and each ad carried its creative fields (such as image and target) **directly**, with no providerConfig and no type.

The current format wraps every ad in an adSlots array with a typed providerConfig.

**Old format:**

:::BlockQuote
\[
&#x20; \{
&#x20;   "id": "promo",
&#x20;   "image": "assets/ads/promo.png",
&#x20;   "target": "https\://example.com"
&#x20; }
]
:::

**New format:**

:::BlockQuote
\{
&#x20; "adSlots": \[
&#x20;   \{
&#x20;     "id": "promo",
&#x20;     "providerConfig": \{
&#x20;       "type": "DEFAULT",
&#x20;       "image": "assets/ads/promo.png",
&#x20;       "target": "https\://example.com"
&#x20;     }
&#x20;   }
&#x20; ]
}
:::

Legacy ads without a providerConfig are no longer supported. The ad component logs a warning asking you to migrate.

Static image ads map to providerConfig.type: "DEFAULT".

## FAQ

**Can I use more than one ad platform in a single experience?**

No. Only one platform plugin under purple.ads is active at a time. You can, however, mix component-level slot types (DIV, HTML, static DEFAULT) alongside the active platform.

**Why do no ads show even though the user accepted the consent banner?**

For consent-gated providers, check that consent.vendorId and consent.iabVendorId match exactly what your CMP reports. A mismatch is treated as "no consent", so the plugin never loads.

**Where do I put my provider account settings?**

Platform-wide settings (network code, script URLs) go in experience.config.json under purple.ads.\<provider>.configuration.

Per-placement settings (ad unit code, sizes, targeting) go in each slot's providerConfig in ads.json.

**Is Traffective on the Plugin System?**

Not yet. Traffective is currently rendered at the component level; its migration to the Plugin System is in progress. Follow the Traffective page for the current setup.

**How do I show different ads on mobile vs. desktop?**

Add a condition on the placement in views.json (or on the slot/data source) based on $context.device\_type.

Avoid CSS display: none hiding, which still loads the ad.

**What is the difference between the Ad Data Source and embedded/ad-insertion?**

The Ad Data Source feeds a component that renders *only* ads.

Ad insertion interleaves ads *between* content items in another data source.

Don't combine both on the same component.

## Related Topics

- [Google Publisher Tag (GPT) Ad Configuration Documentation](docId\:jm0bqlYKl1WL3ae8lzOsZ)&#x20;
- [AdSpirit Integration](docId\:H-wm0jXLVHeJmNBBZPSGX)&#x20;
- [Traffective ads in  Experience](docId\:rZClsPkBDkyqXl8N8dKbQ)&#x20;
- [DIV Ad Provider Implementation](docId\:heFuNwkWL11-VpWhif0Q9)&#x20;
- [Static ads](docId\:YOvF3cLRWz4rbraS8CfCy)&#x20;
- [Embedded ads in Experience](docId\:fBXEGKJkrGezHEwjHksd1)&#x20;
- [Ad Data Source](docId\:g-WZf7NExBjc35Wj8WcmC)&#x20;
- [Consent Management App & Web](docId\:iUbZRguxkik85qJAPwXIE)&#x20;
