---
title: "Why a conversion did not count"
description: "Read the XD-reason header (or the pixel's debug=1 JSON) to see why a pixel or server-to-server conversion was not counted, what each reason code means, and why repeated test conversions vanish."
type: "troubleshooting"
audience: [network-manager]
keywords: [XD-reason, XD-attribution, XD-warning, reason code, debug, debug=1, pixel not counting, conversion not counted, postback not counted, troubleshooting, expired, no-cookie, no-match, already-tracked, key-unknown, action-data-missing, duplicate conversion, test conversion, 404 on /at]
ui_path: "Account → Advertisers → campaign → Conversion actions → Conversion tracking code"
---

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.

# Why a conversion did not count

A conversion pixel or postback that “did nothing” almost always says why on its response. This
page lists the reason codes the ad server returns, how to read them, and why repeated test
conversions can vanish. To set up the tracking in the first place, see
[Get the pixel and S2S tracking code](https://epom.com/ad-server/docs/guides/conversions/s2s-and-pixels.md); to run a test conversion, see
[Test a conversion](https://epom.com/ad-server/docs/guides/conversions/s2s-and-pixels.md#test-a-conversion).

## Who this is for

Anyone integrating or testing conversion tracking — network managers and the advertiser’s own
developers. Reading the response needs no permission in Epom: it is whatever your browser, your
server or `curl` receives from the ad server.

## Read why a conversion did not count

The pixel always answers `200 OK` with a 1×1 GIF, so nothing in the picture tells you whether
the conversion landed. The outcome is on the response instead, in an `XD-reason` header —
present on every conversion response, success included, from the cookie pixels
(`/action.gif`, `/action.js`) and from the server-to-server endpoint (`/at`) alike.
On the image pixel you can also add `debug=1` to the URL and get the outcome as a small JSON
body instead of the image (any non-empty value works; the JS pixel and the S2S endpoints do not
serve it):

```bash
curl -s 'https://ads.example.com/action.gif?key=<key>&debug=1'
{"reason":"no-cookie","counted":false,"description":"No click or view cookie reached the ad server - the browser dropped it, or this user never saw the ad."}
```

`counted` is `true` only when the conversion was added to the advertiser's totals — which is
`ok` and nothing else. The codes you meet while integrating:

| `XD-reason` | What happened |
| --- | --- |
| `ok` | Counted. |
| `expired` | A click or view matched but fell outside the action's attribution window. Recorded as a diagnostic, not counted. |
| `no-cookie` | No click or view cookie arrived — wrong browser, cookies cleared, or a consent tool dropped it. |
| `no-match` | Cookies arrived, but none of them belongs to a creative of this campaign — or of any campaign sharing its conversion-tracking alias. Usually the tag sits on a page reached without seeing the ad. |
| `already-tracked` | The same click or view already produced this conversion; the repeat is deduplicated. On the pixel the check is server-side as well as cookie-side, so it holds even when the visitor's browser could not store the tracking cookie. Clicking the ad again starts a new chance to convert. On a postback the same reason means something narrower — see the corner case on repeats below. |
| `window-disabled` | That event type has a zero-length window on this action, so it never converts. |
| `cookie-data-missing` | A cookie matched, but it carried no ad data to build the conversion from. |
| `key-unknown` | The `key=` value does not resolve to a conversion action. `key=` is the *pixel* parameter, so this is a stale or mistyped copy of a pixel code block — a postback never sends it. |
| `action-data-missing` | The request named no conversion the ad server could read — no `subId`, no key + click-id pair, or a value in one of them it could not decode. Almost always a truncated postback URL, or a placeholder that resolved to nothing so the parameter arrived empty; a double-encoded click id does it too. Check what your server actually sent, not what the template says. |

The rest all say the same thing in different words — the entity named by the cookie or the click id
is not live in ad serving: deleted, or with conversion tracking switched off. A cache reload lags a
settings change by up to ten minutes, so one of these right after an edit may simply be the ad
servers not having caught up.

| `XD-reason` | Which entity |
| --- | --- |
| `pair-unknown` | The key and the click id both parsed, but together they name no conversion action. |
| `action-unknown` | The conversion action. |
| `banner-unknown` | The creative — unknown, or conversion tracking is off for it. |
| `campaign-unknown` | The campaign — unknown, or conversion tracking is off for it. |
| `advertiser-unknown` | The advertiser. |
| `placement-unknown` | The placement. |
| `country-unknown` | Not an entity: the country of the conversion could not be resolved from the request. |
| `error` | Not an entity either: the ad server failed while processing the conversion. Worth reporting. |

Two more headers ride along on the same response:

| Header | What it says |
|---|---|
| `XD-attribution` | Which cookie jar answered, as an attribution type (`POST_CLICK`, `POST_VIEW`, and the expired variants). Set on the cookie pixels only, and worth reading when a landing page's click id went missing: the pixel reads both jars and a click beats a view, so a conversion you assumed was post-view is frequently a post-click whose `easclid=` never arrived. |
| `XD-warning` | A parameter the ad server did not use on a conversion it otherwise counted. Today the only value is `payout-word-refused`. Unlike `XD-reason` these accumulate — one response can carry several. |

Outcomes that predate the reason header still emit their original single-purpose flag alongside
it, valued `1`, for anything already parsing them:

| `XD-reason` | Legacy flag |
|---|---|
| `action-data-missing` | `XD-data-key` |
| `pair-unknown` | `XD-pair` |
| `action-unknown` | `XD-action` |
| `placement-unknown` | `XD-placement` |
| `banner-unknown` | `XD-banner` |
| `campaign-unknown` | `XD-campaign` |
| `advertiser-unknown` | `XD-advertiser` |
| `country-unknown` | `XD-countryData` |
| `error` | `XD-exc` |

Reading these headers from JavaScript on the advertiser's own page works: all of them, `XD-warning`
included, are named in `Access-Control-Expose-Headers`. A plain `new Image().src = …` pixel cannot
read response headers at all — use `fetch()`, or just `debug=1` from the command line.

> **Corner case:** on the server-to-server endpoints the HTTP status is *almost* the same answer —
> `/at` replies `404` when nothing was logged and `200` when something was. The exception is the
> one that matters: an **expired** conversion logs a diagnostic row, so it answers `200` while
> `XD-reason: expired` says it was not counted. Read the header, not the status.

## Corner cases and gotchas

> **Corner case:** repeated test conversions from the same machine can silently disappear.
> The pixel counts one conversion per click or view: fire it twice for the same click and the
> second is a duplicate, never shows up in reports, and answers `already-tracked`. A
> "Duplicate conversion window (per IP)" on the action removes further repeats from the same address.
> Wait out the window, click the ad again, or test from another machine.
>
> Server-to-server postbacks are different: there the only identity is the one your partner
> sends, so repeats are counted unless you tick **Reject duplicate conversions** on the action
> *and* your network runs duplicate detection — the checkbox is not even offered when it does not.
>
> The landing-page snippet posts to the same endpoint but refuses the repeat before it leaves the
> browser, so a second fire of the same event on the same click is not counted whatever those two
> settings say. See [Install the landing-page helper](https://epom.com/ad-server/docs/guides/conversions/landing-page-helper.md).

## Related

- [Get the pixel and S2S tracking code](https://epom.com/ad-server/docs/guides/conversions/s2s-and-pixels.md)
- [Postback parameters and partner integrations](https://epom.com/ad-server/docs/guides/conversions/postback-parameters.md)
- [Snippet tab options](https://epom.com/ad-server/docs/guides/conversions/s2s-snippet-options.md)
- [Create and edit conversion actions](https://epom.com/ad-server/docs/guides/conversions/conversion-actions.md)
- [Install the landing-page helper](https://epom.com/ad-server/docs/guides/conversions/landing-page-helper.md)
- [Analytics discrepancies](https://epom.com/ad-server/docs/troubleshooting/analytics-discrepancies.md)