Docs/SDKs

Web (Browser)

Zero-dependency browser SDK with an auto-rendering banner API and a framework-agnostic client.

Package@theaimart/adx-web
LanguageTypeScript
Distributionnpm / CDN
RequirementsAny modern browser (evergreen Chrome/Firefox/Safari/Edge).

Install

npm

bash
npm install @theaimart/adx-web

Script tag (auto-attaches window.TaimAds)

html
<script src="https://cdn.jsdelivr.net/npm/@theaimart/adx-web/dist/taimads.global.js"
        data-api-key="pk_your_publisher_key"></script>

Usage

Auto-rendering banner

html
<div id="taim-ad-8b1f2c3d"></div>
<script type="module">
  import { TaimAds } from '@theaimart/adx-web';
  TaimAds.init({ apiKey: 'pk_your_publisher_key' });
  TaimAds.createBanner({
    slotId: '8b1f2c3d-....-uuid',   // container defaults to #taim-ad-<slotId>
    lazy: true,                      // request only when near viewport
    refresh: 60,                     // auto-refresh seconds (clamped to >=30)
    onLoad: (ad) => console.log('filled', ad.source),
    onError: (err) => console.log('no fill', err.message),
  });
</script>

Framework-agnostic client (React/Vue/custom)

ts
import { AdxWebClient, AdKind } from '@theaimart/adx-web';

const client = new AdxWebClient({ apiKey: 'pk_your_publisher_key' });
const ad = await client.requestAd({ slotId: '8b1f-uuid', pageUrl: location.href });
if (ad.filled) {
  // render ad.creative yourself (img+anchor, or sandboxed iframe for ad.kind === AdKind.Html)
  if (ad.isTrackable) await client.reportViewable(ad.impId!);
}
CORS origin note: the backend currently allows cross-origin serving only from adx.theaimart.co/theaimart.co. To serve on arbitrary publisher domains the backend must widen CORS or front /api/v1/serve/* with an origin-reflecting edge. Native mobile/server SDKs are unaffected.

Production hardening

  • SQL-filter-safe encoding of pageUrl/keywords/consent so real URLs never trip the backend WAF.
  • Header-less simple GET with credentials: 'include' — no custom header means no CORS preflight; the _an_id identity cookie flows automatically.
  • Fail-closed: any error/non-200 → no-fill; ads never throw into your page.
  • Beacons use navigator.sendBeacon (survives teardown), falling back to keepalive fetch.

These behaviors come directly from the wire contract — see User-Agent rules and WAF-safe encoding for why they matter. Not getting fills? See Troubleshooting.

API

MemberNotes
TaimAds.init({ apiKey, baseUrl? })Configure the global auto-render controller once.
TaimAds.createBanner({ slotId, container?, lazy?, refresh?, onLoad?, onError? })Render a banner into a container (defaults to #taim-ad-<slotId>).
new AdxWebClient({ apiKey, baseUrl? })Framework-agnostic client for custom rendering.
client.requestAd({ slotId?, slotName?, pageUrl?, pageKeywords?, usPrivacy?, euconsentV2? })Request an ad decision — returns a normalized Ad.
client.reportViewable(impId)Fire the viewability beacon.
isSafeHttpUrl(url)The same http(s)-only scheme check the SDK uses internally before turning a click_url into a link — exported for custom renderers.

The normalized Ad model

AdKind (Image/Html/NoFill), AdSource (Internal/OpenRtb/House), plus the shared filled/impId/creative/auction/isTrackable fields common to every SDK.

Advanced

Beyond the core v1 contract, this SDK ships additional client-side capabilities:

Mediation (waterfall + bidding across networks)

MediationController fetches a publisher's mediation chain from the public config endpoint and runs it: taimads first-party demand and any bidding adapters compete in parallel on price; if nothing bids, waterfall adapters are called in priority order until one fills. External networks (AdMob, Meta, …) ship their own proprietary SDKs the package can't bundle, so integrators register an AdapterFn per network that wraps that network's SDK — taimads itself is always the built-in bidding entry, no adapter needed.

VAST video playback

parseVast understands the VAST 2.0/4.0 documents the ad server emits (a single InLine linear ad) — it is deliberately not a general-purpose VAST parser. playVastAd wires the result onto an HTML5 <video> element with IAB-correct beaconing (impression fires once on first play).

On-device persona (privacy-preserving contextual targeting)

recordTopic/topTopics count interest topics in the user's own localStorage — nothing is uploaded. At request time, the top topics ride the serve call as plain contextual keywords: no identifier, no profile, nothing joinable server-side. clearPersona lets the user wipe it entirely.

Ad inspector overlay

enableInspector() drops a floating debug panel listing every ad the page rendered — network, impression id, clearing price — with one-click links to the public nutrition label at /why/{imp_id} where the signed receipt proves the money trail. Zero dependencies, inline styles only, safe to ship in production behind ?adx_debug=1.

Build & test

bash
cd packages/web
npm install
npm test           # node --test (core + encoding logic)
npm run typecheck  # tsc --noEmit
npm run build      # tsc -> dist (ESM + types)
npm run build:cdn  # esbuild -> dist/taimads.global.js (IIFE for <script>)