Skip to main content
Advertisers can use third-party verification providers such as IAS to independently measure whether their ads rendered and were viewable. These providers run a small script on the page alongside the ad. This requires two things:
  1. The provider’s tag must travel with the creative, from campaign setup through the auction response.
  2. The storefront must insert the script into the rendered banner after the shopper has granted consent.
Topsort already supports carrying verification tags through JSON banner templates. Marketplaces can implement consent handling and script insertion themselves, or use the @topsort/verification library to handle these steps. The helper library currently supports IAS only. It reduces the custom code needed to manage tag insertion, banner re-renders, ad rotation, and consent changes. The initial 0.1.0 release supports custom web banner renderers using IAS monitoring tags. It does not yet include an automatic Banners.js integration, other verification providers, native mobile-app measurement, or direct <script> installation.

Before you start

  • Your banners must use JSON templates, which define named creative fields.
  • You need a Consent Management Platform (CMP) to collect and record the shopper’s consent. Topsort and this library do not provide a CMP. You connect the library to your existing CMP through a consent adapter.
Install the package in an npm-based application:
The package is an ES module intended for applications and bundlers. It does not provide an IIFE build for direct browser <script> installation.

Step 1: Configure the banner template

When creating the banner template, include a text field named verificationTag. This field holds the advertiser’s verification tag. You can use another field name, provided your storefront reads the same name from the auction response. This guide uses verificationTag.

Step 2: Supply the verification tag

During campaign creation, the advertiser pastes the tag supplied by their verification provider into the template field. For the library’s current IAS support, the accepted value is exactly one external script tag:
The library validates the tag against the following requirements:
  • The URL must use HTTPS.
  • The hostname must be staticjs.adsafeprotected.com.
  • The path must be /fw.js.
  • The URL must contain exactly one numeric advEntityId and one numeric pubEntityId.
  • Inline JavaScript, extra attributes, extra elements, other hosts, explicit ports, and URL fragments are rejected.
If the tag is rejected, the library does not insert a script. The banner itself continues to render normally.

Step 3: Read the tag from the auction response

The template fields are returned in the winning asset’s content object. Read verificationTag alongside the image URL, headline, and other creative fields. In the raw auction response, this is winner.asset[index].content.verificationTag, where index identifies the asset you are rendering. The examples below assume your application maps that asset’s content object to banner.content and the winner’s resolvedBidId to banner.resolvedBidId. These are application-level mappings, not a different auction response format.

Step 4: Register the rendered banner

The library inserts the validated script into the banner’s container after consent is granted. Your renderer must register each banner after its element is connected and dispose the registration when that banner is removed. Registering a different render key on the same element replaces the previous registration automatically. Three terms appear in the examples:
  • Runtime: The object returned by createVerificationRuntime(...). It connects to your consent adapter and tracks registered banner elements. Create one runtime for the page and reuse it across banners.
  • Register: Calling register(...) supplies the banner element, verification tag, and render key. The library checks consent before inserting the script.
  • Handle: The object returned by register(...). Its dispose() method terminates the registration and removes the script node the library inserted.
Create the consentSource adapter described in Connect your CMP, then register each banner after its container element is available:
renderKey distinguishes a re-render of the same ad from a new ad rendered into the same element. Registering a new renderKey on the same element automatically tears down and replaces the previous registration. Keep the key stable for re-renders of the same ad, and change it for a new ad render. An empty tag safely loads nothing and disposes any previous registration owned by the same element. Invalid elements, empty render keys, and malformed non-empty tags load nothing and produce bounded diagnostics. These conditions do not throw into your banner rendering code.

Using React

For React, create the runtime once in a shared module and import it wherever you render banners. Do not create it inside a component, where repeated mounts would create separate runtimes and consent subscriptions.
Use the React helper to connect the runtime to the banner element:
useVerificationRef returns a callback ref. React calls it with the DOM node when the banner mounts and with null when it unmounts. The helper registers the banner and handles cleanup, so you do not call dispose() yourself.

Connect your CMP

The library shows no consent UI and does not communicate directly with your CMP. You provide an adapter with two functions:
  • current() returns the current consent state.
  • subscribe(listener) reports consent changes and returns a function that stops listening.
Choose the CMP purpose that applies to vendor measurement, then map its state to "unknown", "granted", or "denied". The following example illustrates the adapter structure. Replace readMyCmp() and myCmp.on/off with your CMP’s actual APIs:
The library responds to each state as follows:
  • unknown: Waits without parsing the tag, fetching the provider script, or modifying the DOM.
  • granted: Validates the tag, creates a fresh <script> element from the validated src, and appends it inside the banner element. It does not insert stored markup through innerHTML.
  • denied: Terminates the registration without loading the script.
Denied consent is terminal for that registration. If consent is granted later, register the banner again or reload the page. Consent withdrawal and provider failure are also terminal; create a new registration to retry after correcting the underlying condition. Return the actual consent state from your CMP. Hardcoding "granted" bypasses consent gating and allows IAS to load as soon as the banner is registered. If consent is withdrawn later, the library terminates the registration and removes its own script node. It cannot undo vendor code that has already executed, requests already sent, globals already set, or storage already written. Cleanup is best-effort and covers only the script node created by the library.

Check the integration

Pass an onDiagnostic callback when creating the runtime to receive status codes such as:
  • registered
  • active
  • consent_denied
  • invalid_tag
  • provider_load_failed
  • consent_withdrawn
  • consent_source_failed
  • element_not_ready
  • runtime_disposed
Diagnostics include the provider name and elapsed milliseconds. They do not include the raw tag, URL query, or page content. active means only that the provider’s script finished loading. It does not confirm that IAS recorded an impression, considered the ad viewable, or accepted the data. Confirm measurement in IAS reporting.

Content Security Policy

If your storefront uses a Content Security Policy (CSP), allow staticjs.adsafeprotected.com in script-src so the browser can load the IAS script. This is not a complete production allowlist. The full set of IAS origins required for script-src, connect-src, img-src, and frame-src remains subject to IAS-side validation.

Banners.js

Automatic Banners.js integration is not part of 0.1.0. A custom integration can use the runtime only if it can provide the exact rendered element, verificationTag, and resolvedBidId, and can dispose the registration with the banner lifecycle. First-class Banners.js support will be documented separately when it is available.