---
title: "Capping matrix"
description: "The complete capping enum — 18 types, 5 subjects, 7 period types — which of them a user can actually reach, and the permission that gates each one."
type: "reference"
audience: [network-manager]
keywords: [capping matrix, capping types, capping subject, period type, flat, DSP capping, request capping, no-click, reference]
ui_path: "Account → Advertisers → campaign → Frequency Capping"
---

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

# Capping matrix

The value lists behind frequency capping, in full, plus which of their values a user can
actually reach. For the walkthrough — how a cap counts, when its window rolls over, what Flat
does — see [Set up frequency capping](https://epom.com/ad-server/docs/guides/delivery/frequency-capping.md).

## The enum has 18 values; the product offers 12 of them

The capping type list has **18** values. A value is one *kind* of cap fixed to one *entity level*,
so the same kind appears up to four times. Of the 18, **12 are reachable** in the product and
**6 are not** — the three Request values, whose permissions are granted to no role, and the three
DSP values, which every write path refuses. That is the 1 + 4 + 4 + 3 the combo feeds return.

| Value | Kind | Level | Prefix | Reachable? |
|---|---|---|---|:---:|
| `ADVERTISER_FREQUENCY` | Frequency | Advertiser | `af` | ✔ |
| `CAMPAIGN_FREQUENCY` | Frequency | Campaign | `c` | ✔ |
| `CAMPAIGN_CLICKS` | Click | Campaign | `cc` | ✔ |
| `CAMPAIGN_ACTIONS` | Action | Campaign | `ca` | ✔ |
| `CAMPAIGN_NO_CLICK` | No-Click | Campaign | `cnc` | ✔ |
| `CAMPAIGN_REQUEST` | Request | Campaign | `cr` | — no role can hold the permission |
| `BANNER_FREQUENCY` | Frequency | Banner | `b` | ✔ |
| `BANNER_CLICKS` | Click | Banner | `bc` | ✔ |
| `BANNER_ACTIONS` | Action | Banner | `ba` | ✔ |
| `BANNER_NO_CLICK` | No-Click | Banner | `bnc` | ✔ |
| `BANNER_REQUEST` | Request | Banner | `br` | — no role can hold the permission |
| `PLACEMENT_FREQUENCY` | Frequency | Placement | `pfc` | ✔ |
| `PLACEMENT_CLICKS` | Click | Placement | `pcc` | ✔ |
| `PLACEMENT_ACTIONS` | Action | Placement | `pac` | ✔ |
| `PLACEMENT_REQUEST` | Request | Placement | `pr` | — no role can hold the permission |
| `CAMPAIGN_DSP_FREQUENCY` | DSP frequency, 1 day | Campaign | `cd` | — refused on every path |
| `CAMPAIGN_DSP_FREQUENCY_MONTH` | DSP frequency, 1 month | Campaign | `cdm` | — refused on every path |
| `CAMPAIGN_DSP_RECENCY` | DSP recency | Campaign | `cdr` | — refused on every path |

The prefix is not decoration: it is the name of the browser cookie the counter lives in, and
the first half of the composite row id (`{id}:{TYPE}`) the delete call takes.

### What each level serves into the Capping type list

This is what the four combo endpoints actually return, after permission filtering, on a
network whose roles have never been hand-edited.

| Kind | Advertiser | Campaign | Banner | Placement |
|---|:---:|:---:|:---:|:---:|
| Frequency | ✔ | ✔ | ✔ | ✔ |
| Action | — | ✔ | ✔ | ✔ |
| Click | — | ✔ | ✔ | ✔ |
| No-Click | — | ✔ | ✔ | — *(no such value exists)* |
| Request | — | *(exists, never granted)* | *(exists, never granted)* | *(exists, never granted)* |

So the lists come out at **1 type for an advertiser, 4 for a campaign, 4 for a banner, 3 for a
placement** — and in that order: Frequency, Action, Click, No-Click. The advertiser level is
deliberately minimal: one impression cap that everything beneath it shares.

> **Corner case — Request capping is unreachable, not merely ungranted.** Its two permissions
> (*Request Capping* and *Inventory Request Capping*) exist as permission definitions, but the
> migration that created them inserted only the two identities. It never created the role
> entries or the grants that a permission needs to be holdable, and neither the seed nor any later
> script grants them, so no role holds either one. Until Epom inserts those rows by hand,
> no role can see Request capping in any list.

> **Corner case — the three DSP types are refused everywhere.** The campaign list drops them
> unconditionally, with no permission that restores them, and the shared validator answers
> *Access denied* for **add, update and delete** alike, through the REST API too. Ad serving
> ignores them. If a row of one of these types is already on a campaign, it can be
> listed and cannot be removed through any supported call.

## Which permission gates which type

Each kind of cap has its own permission on the role: *Frequency Capping*, *Click Capping*,
*Action Capping* and *Request Capping*. No-Click has none of its own and follows *Frequency
Capping*. The DSP types are never listed and always refused.

Placement caps are the exception: the Capping type list asks for the demand-side permission, but
saving asks for its **Inventory** twin (*Inventory Frequency Capping* and so on). A publisher role
with only the inventory permissions therefore gets an empty list, and a role with only the demand
permissions gets a list it cannot save from. Ask for both when placement capping is needed.

The card itself also needs *Manage Capping & Limitations* (demand) or *Manage Inventory Capping*
(supply), enabled or read-only.

## Two names for the same row

A cap is labelled one way in the Add dialog and another in the grid's Type column.

| Capping type list | Grid Type column |
|---|---|
| Frequency Capping | By impressions |
| Action Capping | By conversions |
| Click Capping | By clicks |
| Request Capping | By requests |
| No-Click Capping | No-Click Capping — the one kind with no short label |

> **Note:** *No-Click Capping* stays in English in every interface language, in both the dialog
> and the grid.

## Subjects

Five values, from `GET /capping-subject-types.do` — note the root path, not `/account`. The
subject is set **per cap row**, not once for the entity, and it is fixed in the order
below.

| Subject | Id | Label | Counter lives in | Available when |
|---|---|---|---|---|
| `USER_COOKIE` | 1 | User (cookie-based) | a cookie on the ad-serving domain | nothing — this is the default for a new row |
| `USER_SERVER_SIDE` | 4 | User (server-side storage) | the network's server-side capping store, keyed by the resolved visitor id | server-side capping storage enabled |
| `USER_MIXED` | 5 | User (cookie-based + server-side storage) | the cookie where a cookie is possible, the store where it is not | server-side capping storage enabled |
| `IP` | 2 | IP | the store, keyed by the client IP | server-side storage and IP capping are enabled for the network, and your role allows IP capping |
| `LES_IP` | 3 | L.E.S. IP | the store, keyed by the last external source IP — the address seen before proxies | server-side storage and L.E.S. IP capping are enabled, and your role allows L.E.S. IP capping |

The server-side counter is keyed by the visitor id the ad server resolves for the request. In the
default (mixed) identity mode that is, in this order: an explicit user id parameter, the Epom UUID cookie, the device advertising ID (`ifa`) —
which is what separates the viewers behind an SSAI stitcher on apps and connected TV — and last a
fingerprint of IP, user-agent and language. A placeholder or all-zero advertising ID counts as no
ID.

The endpoint filters only on the two permissions; the network switches are checked by the card.
The **Subject** column and its selector appear only when server-side storage is on **and** at
least one of the two IP subjects is both granted to you and enabled on the network. When the
column is hidden, existing rows keep and still enforce whatever subject they were saved with.

### When a cookie counter cannot be used

A request is treated as unable to keep a capping cookie when **any** of these holds:

- the ad tag reported private browsing (`im=1`);
- the browser is **Safari, Mobile Safari, Firefox, Firefox Mobile, Firefox Minimo, Brave or
  DuckDuckGo**;
- the operating system is **iOS, iPadOS or Apple TV**;
- neither the browser nor the OS could be identified at all.

For a `USER_MIXED` row that flips the counter to server-side storage for that request. For a
plain `USER_COOKIE` row there is no fallback, so the cap simply under-counts that traffic.

The tag's `cookie-policy` value overrides all of this: `1` turns off cookies **and** server-side
capping, `2` turns off cookies but keeps server-side capping, `3` drops only the user-ID cookie.
A network's GDPR no-consent restriction maps onto the same values. See
[Frequency cap not working](https://epom.com/ad-server/docs/guides/delivery/frequency-capping.md#frequency-cap-not-working-the-ad-shows-on-every-page-load).

> **Corner case — No-Click capping is cookie-only.** The two No-Click values have no
> server-side counterpart at all: the mapper that writes counters to the store has no entry for
> them and skips them silently. A No-Click row with subject *User (server-side storage)* is
> never counted and never fires, and a *mixed* one stops working for exactly the visitors who
> cannot keep cookies. Leave No-Click on the plain cookie subject.

## Period types

Seven values, from `GET /time-period-types.do`, in this order.

| Period type | Id | Label |
|---|---|---|
| `SECOND` | 6 | Second(s) |
| `MINUTE` | 0 | Minute(s) |
| `HOUR` | 1 | Hour(s) |
| `DAY` | 2 | Day(s) |
| `WEEK` | 3 | Week(s) |
| `MONTH` | 4 | Month(s) |
| `YEAR` | 5 | Year(s) |

The window is `Period` × `Period type`, measured from the first counted event for that visitor
and that cap. **Month and year are calendar lengths, not fixed 30- and 365-day blocks:** the ad
server computes the window length by adding the period to a calendar date. It does that once,
when the cap is loaded into the serving cache, so a one-month window loaded during February is
28 days long for as long as that cache entry lives.

## Field ranges and defaults

| Field | Add-dialog default | Add-dialog input allows | Server enforces |
|---|---|---|---|
| Capping type | first type in the list | — | must match the entity's level, or the save is refused as *Capping type is incompatible with entity* |
| Subject | *Please select…* — saved as User (cookie-based) | the permitted subjects | the *Capping IP Subject* permission for `IP` |
| Amount | `0` | 0 – 100 000 | **0 – 8 388 607** |
| Period | `1` | 0 – 100 000 | **1 – 255** |
| Period type | Day(s) | the seven above | the seven above |
| Flat | off | on / off | — |

The two ranges disagree on purpose in neither direction — the form is simply looser than the
validator. A period of `0` or of `300` is accepted by the input and refused on save. An
**Amount of 0 does not restrict anything**: the ad server skips any cap whose amount is 0.

The entity's own default period type is `HOUR`; the Add dialog overrides it to `Day(s)` before
you see it, so an `HOUR` row can only arrive through the API.

## The DSP rows, for reading existing data

These cannot be created (see the corner case above), but a campaign may already carry one.
Their field locks are:

| Value | Pinned | Editable in the grid |
|---|---|---|
| `CAMPAIGN_DSP_FREQUENCY` | Period = 1, Period type = Day, Flat off | Amount only |
| `CAMPAIGN_DSP_FREQUENCY_MONTH` | Period = 1, Period type = Month, Flat off | nothing is locked — the grid has no rule for this value |
| `CAMPAIGN_DSP_RECENCY` | Amount = 1, Flat off, Period type = Minute | Period only, 1 – 60 |

Any edit is refused by the server regardless, so the unlocked month variant is a cosmetic
inconsistency rather than a way in.

## REST API surface

| Level | Create | List | Per-kind set / update / remove |
|---|---|---|---|
| Advertiser | `POST /rest-api/advertiser/capping/{advertiserId}.do` | `GET` on the same path | — |
| Campaign | `POST /rest-api/campaign/capping/{campaignId}.do` | `GET` on the same path, plus `GET /rest-api/campaign/capping/bulk.do` | frequency, click, action, no-click |
| Banner | `POST /rest-api/banner/capping/{bannerId}.do` | `GET` on the same path | frequency, click, action, no-click |
| Placement | `POST /rest-api/placement/capping/{placementId}.do` | `GET` on the same path | — |

Any cap row, at any level, can also be changed or removed by its composite id (`{id}:{TYPE}`)
through `POST /rest-api/capping/{cappingId}.do` and `POST /rest-api/capping/delete.do`.

> **Corner case:** the spec lists **all 18** values in the `type` enum of all four create
> endpoints, including the ones that belong to a different level. The description narrows it
> correctly, and the server rejects a mismatch cleanly — so do not read that list as the values a
> given endpoint accepts.

## Related

- [Set up frequency capping](https://epom.com/ad-server/docs/guides/delivery/frequency-capping.md)
- [Limits](https://epom.com/ad-server/docs/guides/delivery/limits.md)
- [Delivery controls overview](https://epom.com/ad-server/docs/guides/delivery.md)
- [Platform limits](https://epom.com/ad-server/docs/reference/platform-limits.md)