Skip to content

TypeScript SDK

The fastest way to integrate Advalidation. One call to validate a creative, no manual polling, no response parsing.

npm install advalidation
import { Advalidation } from "advalidation";

const client = new Advalidation({ apiKey: "your-api-key" });

const result = await client.validate({
  url: "https://rtr.innovid.com/r1.66f3e735e66ba5.38642747;cb=[timestamp]",
  type: "video",
});

console.log(result.passed);    // true or false
console.log(result.issues);    // number of failed tests
console.log(result.reportUrl); // link to the full visual report

That’s it. The SDK resolves the ad specification, creates a campaign, uploads, polls until done, and returns the result.

Exactly one of url, tag, file, or data must be provided.

// URL (hosted creative, VAST endpoint, ad tag URL)
await client.validate({ url: "https://example.com/ad.html", type: "display" });

// Tag (raw HTML/JavaScript or VAST XML)
await client.validate({ tag: "<script src='https://example.com/ad.js'></script>", type: "display" });

// File (local path, max 16 MB)
await client.validate({ file: "/path/to/video.mp4", type: "video" });

// Data (Buffer or Uint8Array, max 16 MB)
const buffer = await fs.readFile("/path/to/video.mp4");
await client.validate({ data: buffer, fileName: "video.mp4", type: "video" });

Every validation needs an ad specification. Provide exactly one of campaign, spec, or type.

// Use the default ad specification for a type (creates a new campaign)
await client.validate({ url: "https://example.com/ad.html", type: "display" });

// Use a specific ad specification by ID (creates a new campaign)
await client.validate({ url: "https://example.com/ad.html", spec: "123" });

// Upload into an existing campaign (adspec is inherited)
await client.validate({ url: "https://example.com/ad.html", campaign: 12345 });

By default you get a summary: pass/fail, issue count, and report URL.

Pass details: true to fetch the full test breakdown, including individual test results, VAST media files, and variations.

const result = await client.validate({
  url: "https://example.com/vast.xml",
  type: "video",
  details: true,
});

console.log(result.tests);      // test results
console.log(result.mediaFiles); // VAST media files with their tests

You can also start with a summary and fetch details later:

const summary = await client.validate({ url: "https://example.com/ad.html", type: "display" });

if (!summary.passed) {
  const detailed = await client.getResults(summary.creativeId, { details: true });
  if (detailed.status === "finished") {
    console.log(detailed.tests);
  }
}

getResults() returns a discriminated union — check response.status === "finished" before accessing result fields. Other statuses are "pending", "failed", and "cancelled".

Already have a creative ID from a previous run or the Advalidation UI? Skip the upload and poll:

const response = await client.getResults(creativeId);

if (response.status === "finished") {
  console.log(response.passed, response.issues, response.reportUrl);
} else {
  console.log(response.status); // "pending", "failed", or "cancelled"
}
OptionTypeDefaultDescription
namestringautoCampaign name. Auto-generated from the input if omitted.
timeoutnumber300000Polling timeout in ms (default 5 minutes). validate() only.
signalAbortSignal-Cancel an in-progress operation via AbortController.
verbosebooleanfalseLog progress to stderr (won’t interfere with stdout piping).
detailsbooleanfalseFetch the full test breakdown. validate() and getResults() only.

validate() bundles upload + polling in a single long-running call. In serverless environments (Vercel, AWS Lambda, Cloudflare Workers) the function may timeout before the scan completes. Use submit() + getResults() to split the workflow across separate requests.

// Request 1: submit the creative (fast -- no polling)
const { creativeId } = await client.submit({
  url: "https://example.com/vast.xml",
  type: "video",
});

// Store creativeId (database, KV, cookie, query param, etc.)

// Request 2+: poll from separate short-lived requests
const response = await client.getResults(creativeId);
if (response.status === "finished") {
  console.log(response.passed, response.issues);
} else if (response.status === "pending") {
  // Not done yet -- try again in a few seconds
}

submit() accepts the same creative and targeting options as validate(), minus timeout and details (irrelevant without polling).

All errors extend AdvalidationError for easy catch-all handling, with specific subclasses for granular control.

import { Advalidation, AuthenticationError, InputError, ApiError, TimeoutError } from "advalidation";

try {
  const result = await client.validate({ url: "https://example.com/ad.html", type: "display" });
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error("Bad API key");
  } else if (error instanceof InputError) {
    console.error("Invalid input:", error.message);
  } else if (error instanceof ApiError) {
    console.error(`API error ${error.status}:`, error.body);
  } else if (error instanceof TimeoutError) {
    console.error("Scan timed out");
  }
}

See the SDK README on GitHub for the complete reference, including all options, result shape, verbose output, and more.