Release 149
Post-click / post-view conversion attribution, weekly and monthly limits on every metric, saved conversion funnels, a minimum margin floor for direct campaigns, and piggybacks that can be limited to one attribution model.
Release 149 is built around one question a conversion report could not answer before: did this conversion follow a click, or a view? On top of that it completes the delivery-limits grid — every metric can now be capped over a week and a month, not just a day and a lifetime — adds saved conversion funnels, and gives publishers a minimum margin floor for direct demand.
New features
Post-click / post-view conversion attribution
The ad server now records how every conversion was attributed — Post-click (a click within the action’s post-click window; click beats view), Post-view (a view within the post-view window with no eligible click), System (video/viewability tracking-event actions) or Unattributed (a postback that declared nothing on an action with no default, historical data, self-reported pixels) — and reporting splits by it:
- New report columns — Post-click Conversions and Post-view Conversions, their I2C/CCR rates, and the post-click/post-view Net / Revenue / Gross / Charges money split. The columns are opt-in via Reports Layout Settings and follow the same permissions as the existing Conversions columns; Total Conversions is unchanged. See Analytics metrics.
- Attribution Type group-by in General analytics, next to the Conversion Action dimension. See Analytics dimensions.
- Conversions Log gains Attribution Type and Time to Convert columns.
- Expired-window diagnostics — a conversion whose matched click or view was older than its attribution window used to vanish silently; it is now recorded as a zero-revenue Expired post-click conversions / Expired post-view conversions diagnostic (excluded from all totals; never triggers CPA pricing, capping, limits or piggybacks). See the conversion attribution overview.
- Attribution window on S2S conversions is opt-in — expired-window diagnostics are produced for tracking-pixel conversions automatically, but a server-to-server conversion is window-checked only when its action has Apply attribution window to server-to-server conversions ticked. Every action that already exists has it off, so no running S2S integration changes what it counts; actions created from this release on have it ticked, because a new integration should be measured from the start rather than opted in later. See Create and edit conversion actions.
- A click now signs the value it hands to the landing page — a
$$SUB_ID(...)$$or$$ACTION_DATA$$value the ad server expands while processing a click carries that click, so a postback replaying it is recorded as post-click on its own. Values expanded by the ordinary ad render carry no attribution;att=classifies those. Every value now also carries the moment it was expanded, which is what the attribution window is measured from — except a system tracking action’s, which is always recorded as System and never measured against a window. See Get the pixel and S2S tracking code. att=postback parameter, generated into the tracking URL — both Conversion Tracking URLs now end withatt=. The integrator replaces the placeholder withclickorview(common aliases accepted); leaving it, or dropping the parameter, falls back to the action’s default without any warning. Unrecognized values never lose the conversion. See Get the pixel and S2S tracking code.- The tracking URLs name what you have to substitute — the values an integrator must replace
are written
subid,clickidandclick or viewinstead of borrowing the$$…$$macro spelling. Only the landing page URL carries macros now ($$SUB_ID(...)$$,$$ACTION_DATA$$), so the two halves of an integration no longer look alike. A URL a partner copied earlier keeps working: anatt=value the ad server cannot read is counted exactly as an absent one. - The ad-serving domain governs the whole tracking window — the domain selector moved out of the Pixel Tracking tab to sit above the tabs, and it now rewrites the server-to-server Conversion Tracking URLs as well as the pixel snippets. Opened from a campaign the choice is still saved on the campaign; opened from the global Conversion Actions page it applies to what you are copying and is not persisted. See Get the pixel and S2S tracking code.
- Default attribution type, per action — a partner who cannot send
att=no longer forces every one of their conversions into the Unattributed bucket: whoever manages the action sets Default attribution type on it and it classifies whatever arrived undeclared. It is read last — after system tracking actions, afteratt=, after a click the ad server observed — so it fills gaps and overrides nothing, and pixel conversions never reach it. New and existing actions both default to Unattributed, which is exactly today’s behaviour. Setting it to Post-click or Post-view also brings those conversions under the attribution window when the option above is ticked. System tracking actions offer neither control — they are always recorded as System, so neither would ever be read. See Create and edit conversion actions. $$ATTRIBUTION_TYPE$$macro — forward the attribution type downstream in piggyback and postback URLs. See Macros.- The conversion pixel says why it did not count — every
/action.gifand/action.jsresponse now carries anXD-reasonheader naming the outcome (ok,no-cookie,no-match,already-tracked,expired,key-unknown…), readable from the advertiser’s own page, anddebug=1on the same URL returns it as JSON instead of the 1x1 image. The response is still a 200 with the pixel, so nothing about existing integrations changes. See Get the pixel and S2S tracking code.
Conversions recorded before this release report as Unattributed; totals are unaffected.
Weekly and monthly caps on every metric
The Limits card is now a grid: a metric reads across, a period reads down. Every metric that could be capped over a day or a lifetime can also be capped over an ISO week and a calendar month, and Requests — which only ever had a lifetime cap — gains the other three. Each cap carries a progress bar and its own percentage, so “how much of the weekly budget is left” is a glance rather than two boxes and a subtraction.
The same card now serves both sides of the platform, so sites and placements get Requests, Impressions, Clicks and Conversions over all four periods too.
Worth knowing:
- The monthly impressions cap now actually caps. It has been a field on the form for years with nothing behind it — you could type a number in and watch delivery ignore it. It works from this release.
- Caps nest for every metric, not just budget. A daily cap cannot exceed the weekly one, which cannot exceed the monthly one, which cannot exceed the total; the form now checks the whole ladder and tells you which pair is wrong instead of accepting a cap that can never bite.
- A picked start date begins its day and an end date closes it (00:00 and 23:59), the way the old date field behaved. Previously the picker filled in the time from the clock, so enabling limits at 14:23 quietly lost the first day’s morning and the last day’s afternoon.
- Enter saves, and a cap the database cannot store is refused with the field named rather than failing as an internal error.
- A column disappears once no visible cap uses that period, and the grid scrolls sideways rather than shrinking fields until ten-digit numbers clip.
These caps are off until your network owner grants them. Nineteen new permissions ship disabled, so nothing new appears on your advertisers, campaigns, banners, sites and placements until someone turns them on in Roles & Permissions. See Limits and Users and roles.
Saved conversion funnels
A funnel used to be a selection you rebuilt on every report: find the steps among every conversion action on the account, pick them in the right order because that order is the column order, and hope the next person could work out the sequence from the names. You can now save it — a name and an ordered list of actions — under Conversion Actions, and pick it by name in the analytics split control, where it is listed first.
Two rules to know before they surprise you:
- A funnel is visible to whoever can see every one of its steps. There is no separate sharing setting, and the same rule decides who can read, edit and delete it.
- A deleted action shortens the funnel silently on its next save. A deactivated action is different: it stays in the funnel, greyed, and is simply left out of the report, because you can switch it back on.
A funnel needs at least two steps — the report already offers a single action on its own. One that drops to a single usable step disappears from the analytics picker but stays in the funnels list, so you can still repair or delete it. See Save a conversion funnel.
A minimum margin floor for direct demand
A placement or site can now declare the smallest gap it requires between the advertiser price and its own payout — the publisher-side counterpart of an RTB bid floor. Direct CPM creatives that fail it are dropped before the winner is picked, so the runner-up serves instead of the underpriced one.
Set it on the inventory Pricing card as Absolute (a CPM amount) or Percent (a share of the advertiser price). None is the default on every existing row, so nothing changes until you set one. The placement’s requirement wins; a placement left at None inherits the site’s, so the rule can be set once per site.
A margin requirement does not protect against CPC/CPA demand. Their effective CPM depends on a click or conversion rate that is unknown at the moment the ad is picked, so those campaigns serve untouched. The card says so inline. Revenue-share inventory is skipped as well (a share of gross can never breach a margin), and OpenRTB creatives keep clearing their own bid floor in the auction. Unpriced demand is blocked — a creative with no price on either itself or its campaign is treated like one priced at zero, so house and filler campaigns stop serving on a placement with a margin requirement.
The feature is off until a network owner grants the new Manage Minimum Margin permission. See Pricing.
Piggybacks can be limited to post-click or post-view conversions
Each piggyback — on a campaign, site or placement — now has a Fire for setting: All conversions (the default, unchanged behaviour), Post-click only or Post-view only. Use it when a partner is paid on one attribution model and should not receive the other one’s conversions. It applies to both piggyback types, the server-side URL and the client-side JS snippet. Narrowing sends only conversions positively identified as that type — undeclared and System ones are not delivered, and expired conversions never fire a piggyback at all.
The piggyback dialog and grid toolbar also gained a Piggyback macros button. A piggyback is substituted at conversion time with no ad request attached, so the request-derived macros — IP, user agent, referer, device, advertising id, click URLs — resolve to nothing there. The new window lists only what actually works in a piggyback. See Piggyback pixels and Macros.
Improvements
- The dashboard no longer freezes the interface on large networks. Eight widgets used to fire around thirty requests on open, several of them slow, which filled the browser’s connection budget so everything else on the page queued behind them. Widget data now arrives in one request per widget and is cached for 30 minutes (analytics itself refreshes hourly, and editing a widget refreshes its data immediately). Hover statistics on the entity tree are cached the same way and are cancelled when you close the card. See Dashboards.
- The limits card tells you which level above stopped delivery. A banner well under every cap it can see could sit dark with nothing to explain it, because a cap reached on its campaign or advertiser stops it too — and on the supply side, a spent site stops its placements. The card now opens with a note naming the nearest level that is spent and the cap it reached, with a link straight to it. The note appears whether the limits card is open or closed. Caps you do not have permission to see are left out of the sentence, and networks that mask entity names see the masked form here as well.
- A rejected save says which field was rejected and why. Nine places in the account and admin interface used to answer a refused save with a generic “Cannot edit record”, or — for the action-pricing toggle and a funnel delete — with nothing at all, leaving a switch flipped on a change the server had not accepted. They all show the server’s own reason now.
- The serving pill tells the truth about paused links. A paused banner with active linked placements used to show a green Serving · 4. There is a grey Paused state now, and pausing or resuming from anywhere — the hover card, the Active switch, a grid bulk action, an Undo — refreshes an open edit page on the other side of the link. See Statuses and indicators.
- Long multi-select lists keep your picks in view. Past ten options, the ones you have ticked are gathered into a Selected (N) section at the top, with the natural groups surviving underneath. The arrangement is taken when you open the list and held until you close it, so ticking a row never moves it out from under your cursor. Lists whose order is itself the information — months, years, days of the month — are left alone.
- Traffic quality recovers on its own. The daily analysis had exactly one attempt: if the data it reads arrived late, the day simply stayed unscored until someone noticed and pressed the admin button. A sweep now re-checks the last three days every two hours. Separately, a scan that died without cleaning up used to answer every later click with “already in progress” until the server was restarted — the admin page now reports how long the current run has been going and for which days, or why the previous one failed. See Moderation and traffic quality.
- Placement adapter templates over the API. The template a native placement renders through was reachable only from the interface, so an integration had to open a browser to finish configuring a placement it had just created. It is now reported and accepted by the placement endpoints, and the property list describes what the template declares — including the properties you have not filled in yet, and which of them are required. The placement endpoints also shed most of their parameter list in the API reference (139 → 54), which was inflated by fields no caller could send. See Ad tags and API.
- Admin: sortable DSP grids and a working Troubleshooting Log Tasks page. DSP Partners and DSP Partners Analytics gained column sorting. On Troubleshooting Log Tasks, a task you created now appears in the list without a manual reload, and titles are searchable. See troubleshooting log tasks.
- TCF 1.1 is gone. IAB switched version 1.1 off in August 2020, and Epom has refused version 1 consent strings for a long time since — but the interface still advertised “TCF 1.1/2.0/2.3 Supported”, and two version-1 endpoints were still published. The claim, the fallback and both endpoints have been removed, and the GDPR card now reads TCF 2.x. If your consent tool still speaks TCF 1.1, it no longer has any path into Epom: you need a TCF 2.x CMP.
Bug fixes
- DSP analytics silently lost rows. A table design flaw made every server insert into the same spot, so flushes deadlocked and dropped roughly 144 000 rows per three hours. The table has been rebuilt; measured on a copy of production, 79.5% of flush statements deadlocked before and none do after. Historical rows are preserved and merged.
- A publisher earned nothing where the global price was left unset. An unset global price was read by ad serving as an explicit zero, so the payout cascade stopped on it — exactly the countries a per-country fixed price exists to serve. The interface said Not set, the database agreed, and ad serving did not. An unset price now falls through to the next step of the cascade, while an explicit zero stays a real price that outranks it. Switching a pricing panel on no longer writes a zero on your behalf, which is what made “fixed price for these countries, revenue share for the rest” impossible to configure. The pricing cards now also spell out the precedence that makes a correct configuration look broken: a revenue share bound to one advertiser outranks a per-country fixed price, and any rule on a placement hides the site’s entirely. See Pricing.
- Always-redirect ad tags returned a broken link. Cookie-sync scripts and tracking beacons were appended to the redirect URL, so consumers requested the zone with those scripts glued onto the zone id.
- Limit start and end dates drifted on every save for anyone running a timezone-spoofing browser extension — a little further each time. Both the classic and the new date pickers are guarded against it now.
- Splitting analytics columns by custom parameter failed with an internal error unless the report also grouped by conversion action. A report that asks for the impossible combination now simply arrives without the split, so a saved report carrying an older combination keeps working.
- New UI: the Roles & Permissions page was missing the Ad Units and DSP Partners sections. They were gated on a condition no role could ever satisfy.
- New UI: a placement’s Revenue Share switch showed the Frequency Capping setting — on with an empty grid for placements that share nothing, off for placements that do.
- Encrypted links pointing at a custom invocation path came back without CORS headers, so fetching one from a page failed.
- Template properties lost their order on the banner and placement edit pages — URL properties were pulled to the front instead of following the order the template defines.
- White-label: six interface strings named the product to a white-label network’s own publishers and advertisers, the maintenance page most visibly. All are rewritten without the brand in all 15 languages, and the fallback wordmark now shows the network’s own company name.
- Dates rendered in the browser’s language, not the one you picked in Preferences.
- Ads on a page with a consent banner now wait for the consent tool to answer. The ad request used to give it 300 milliseconds and then go without it — enough for a tool that replies instantly, never enough for one still waiting on the visitor. The request went out saying GDPR applied but carrying no consent string, a combination the IAB standard counts as an error and demand partners refuse, so EEA traffic lost fill it should have had. The request now waits for a real answer, and takes one only once the banner is finished rather than while it is still on screen. It also reaches consent tools running in a parent window, which it could not ask at all before. If the visitor takes their time, the next ad on the page uses what they decided instead of what was known before they decided it. A page with no consent tool is not delayed at all, and a tool that never answers is given up on as before.
Under the hood
Platform upgrades and performance work.