Skip to content

0xARYA/taboola-backstage-sdk

Repository files navigation

Taboola Backstage SDK

npm version License: MIT TypeScript Node.js

A comprehensive TypeScript SDK for the Taboola Backstage API. Manage campaigns, ads, targeting, audiences, pixel tracking, and reporting programmatically with full type safety.

Features

  • Full TypeScript Support — Complete type definitions for all API endpoints, requests, and responses
  • Automatic Authentication — OAuth2 token management with automatic refresh
  • Comprehensive API Coverage — Campaigns, Items, Targeting, Pixel, Reports, Audiences, and more
  • Custom Error Classes — Typed errors for auth, validation, rate limiting, and not found scenarios
  • Built-in Retry Logic — Exponential backoff for transient failures
  • Dual Module Support — Works with both ESM and CommonJS

Installation

npm install taboola-backstage-sdk
yarn add taboola-backstage-sdk
pnpm add taboola-backstage-sdk

Quick Start

import { TaboolaClient } from 'taboola-backstage-sdk';

const client = new TaboolaClient({
  clientId: process.env.TABOOLA_CLIENT_ID,
  clientSecret: process.env.TABOOLA_CLIENT_SECRET,
});

// Get your account
const account = await client.accounts.getCurrent();
console.log('Account:', account.account_id);

// List campaigns
const { results: campaigns } = await client.campaigns.list(account.account_id);
console.log(`Found ${campaigns.length} campaigns`);

// Get campaign performance report
const report = await client.reports.campaignSummary(account.account_id, 'day', {
  start_date: '2024-01-01',
  end_date: '2024-01-31',
});

Configuration

const client = new TaboolaClient({
  // Required
  clientId: string,
  clientSecret: string,

  // Optional
  baseUrl?: string,    // API base URL (default: production)
  timeout?: number,    // Request timeout in ms (default: 30000)
  retries?: number,    // Retry attempts for failed requests (default: 3)
  debug?: boolean,     // Enable request/response logging
});

API Reference

Accounts

// Get current account
const account = await client.accounts.getCurrent();

// Get all allowed accounts
const { results } = await client.accounts.getAllowed();

// Get advertisers in a network
const { results } = await client.accounts.getNetworkAdvertisers('network-id');

Campaigns

// List campaigns
const { results } = await client.campaigns.list('account-id', {
  page: 1,
  pageSize: 50,
});

// Get single campaign
const campaign = await client.campaigns.get('account-id', 'campaign-id');

// Create campaign
const campaign = await client.campaigns.create('account-id', {
  name: 'My Campaign',
  branding_text: 'My Brand',
  cpc: 0.50,
  spending_limit: 1000,
  spending_limit_model: 'MONTHLY',
  marketing_objective: 'DRIVE_WEBSITE_TRAFFIC',
});

// Update campaign (partial updates - only specified fields are changed)
await client.campaigns.update('account-id', 'campaign-id', {
  cpc: 0.75,
  daily_cap: 500,
  country_targeting: {
    type: 'INCLUDE',
    value: ['US', 'CA', 'GB'],
  },
  platform_targeting: {
    type: 'INCLUDE',
    value: ['DESK', 'PHON'],
  },
});

// Pause / Unpause
await client.campaigns.pause('account-id', 'campaign-id');
await client.campaigns.unpause('account-id', 'campaign-id');

// Delete
await client.campaigns.delete('account-id', 'campaign-id');

// Duplicate
const copy = await client.campaigns.duplicate('account-id', 'campaign-id', 'Copy Name');

// Bulk update
await client.campaigns.bulkUpdate('account-id', {
  campaigns: [
    { campaign_id: '123', update: { is_active: false } },
    { campaign_id: '456', update: { cpc: 0.60 } },
  ],
});

// List campaigns (base/lightweight)
const { results: base } = await client.campaigns.listBase('account-id');

// Get publisher targeting whitelist
const whitelist = await client.campaigns.getTargetingWhitelist('account-id', 'campaign-id');

Items (Ads)

// List items
const { results } = await client.items.list('account-id', 'campaign-id');

// Get single item
const item = await client.items.get('account-id', 'campaign-id', 'item-id');

// Create item (static ad - only url accepted, starts in CRAWLING state)
const item = await client.items.create('account-id', 'campaign-id', {
  url: 'https://example.com/landing',
});
// Poll until item.status changes from CRAWLING to RUNNING, then update fields

// Update item (static or motion ad - partial updates supported)
await client.items.update('account-id', 'campaign-id', 'item-id', {
  title: 'Updated Title',
  url: 'https://example.com/new-landing-page',
});

// Update motion ad with video
await client.items.update('account-id', 'campaign-id', 'motion-ad-id', {
  title: 'Updated Motion Ad',
  performance_video_data: {
    video_url: 'https://example.com/video.mp4',
    fallback_url: 'https://example.com/fallback.jpg',
  },
});

// Pause / Unpause
await client.items.pause('account-id', 'campaign-id', 'item-id');
await client.items.unpause('account-id', 'campaign-id', 'item-id');

// Delete
await client.items.delete('account-id', 'campaign-id', 'item-id');

// Bulk create (supports both static and motion ads with full field set)
const { results } = await client.items.bulkCreate('account-id', 'campaign-id', {
  items: [
    { url: 'https://example.com/1', title: 'Title 1', thumbnail_url: '...' },
    { url: 'https://example.com/2', title: 'Title 2', thumbnail_url: '...' },
  ],
});

Targeting

// Postal code targeting
const postal = await client.targeting.getPostalCodes('account-id', 'campaign-id');
await client.targeting.updatePostalCodes('account-id', 'campaign-id', {
  type: 'INCLUDE',
  values: [
    { postal_code: '10001', country: 'US' },
    { postal_code: '10002', country: 'US' },
  ],
});

// Marketplace audience targeting
const audiences = await client.targeting.getMarketplaceAudiences('account-id', 'campaign-id');
await client.targeting.updateMarketplaceAudiences('account-id', 'campaign-id', {
  type: 'INCLUDE',
  collection: [{ id: 'segment-123' }],
});

// Custom audience targeting
const custom = await client.targeting.getCustomAudiences('account-id', 'campaign-id');

// Lookalike audience targeting
const lookalike = await client.targeting.getLookalikeAudiences('account-id', 'campaign-id');

// Contextual targeting
const contextual = await client.targeting.getContextual('account-id', 'campaign-id');
await client.targeting.updateContextual('account-id', 'campaign-id', {
  type: 'INCLUDE',
  collection: [{ id: 'context-456' }],
});

// First party audience targeting
const firstParty = await client.targeting.getFirstPartyAudiences('account-id', 'campaign-id');

// Marking labels (pixel retargeting) targeting
const labels = await client.targeting.getMarkingLabels('account-id', 'campaign-id');
await client.targeting.updateMarkingLabels('account-id', 'campaign-id', {
  type: 'EXISTS',
  collection: ['label-1', 'label-2'],
});

Pixel API

Manage conversion tracking and custom audience rules.

// List conversion rules
const rules = await client.pixel.listConversionRules('account-id');

// Get single conversion rule
const rule = await client.pixel.getConversionRule('account-id', 'rule-id');

// Create conversion rule
const rule = await client.pixel.createConversionRule('account-id', {
  display_name: 'Purchase Completed',
  type: 'EVENT_BASED',
  category: 'PURCHASE',
  event_name: 'purchase',
  conditions: [],
  effect: {
    type: 'DYNAMIC_VALUE',
    currency: 'USD',
    value_parameter: 'order_total',
  },
  conversion_window_days: 30,
  view_through_window_days: 1,
});

// Archive / Unarchive
await client.pixel.archiveConversionRule('account-id', 'rule-id');
await client.pixel.unarchiveConversionRule('account-id', 'rule-id');

// Custom audience rules
const audienceRules = await client.pixel.listCustomAudienceRules('account-id');

const audienceRule = await client.pixel.createCustomAudienceRule('account-id', {
  display_name: 'Cart Abandoners',
  conditions: [
    { type: 'EVENT_NAME', operator: 'EQUALS', value: 'add_to_cart' },
  ],
  ttl_days: 7,
});

// Pause / Resume / Archive
await client.pixel.pauseCustomAudienceRule('account-id', 'rule-id');
await client.pixel.resumeCustomAudienceRule('account-id', 'rule-id');
await client.pixel.archiveCustomAudienceRule('account-id', 'rule-id');

Reports

// Campaign summary report (by dimension)
const report = await client.reports.campaignSummary('account-id', 'day', {
  start_date: '2024-01-01',
  end_date: '2024-01-31',
});

// Available dimensions: 'day', 'week', 'month', 'campaign_breakdown', 'site_breakdown',
//   'country_breakdown', 'platform_breakdown', 'by_hour_of_day', 'region_breakdown',
//   'dma_breakdown', 'campaign_day_breakdown', 'campaign_site_day_breakdown', and more
const byPlatform = await client.reports.campaignSummary('account-id', 'platform_breakdown', {
  start_date: '2024-01-01',
  end_date: '2024-01-31',
  campaign: '12345', // Optional filter
});

// Report data
for (const row of report.results) {
  console.log(`${row.date}: ${row.clicks} clicks, $${row.spent} spent, ${row.ctr}% CTR`);
}

// Top campaign content report
const topContent = await client.reports.topCampaignContent('account-id', {
  start_date: '2024-01-01',
  end_date: '2024-01-31',
  limit: 100,
});

// Realtime campaign report (rate limited: 10 req/min)
const realtime = await client.reports.realtimeCampaign('account-id', 'by_campaign', {
  start_date: '2024-01-15T00:00:00',
  end_date: '2024-01-15T23:59:59',
});

// Realtime ads report (requires item IDs)
const realtimeAds = await client.reports.realtimeAds('account-id', 'by_item', {
  start_date: '2024-01-15T00:00:00',
  end_date: '2024-01-15T23:59:59',
  item: '1001,1002',
});

Publishers

// List available publishers (requires admin network)
const publishers = await client.publishers.list('account-id');

// Get blocked publishers
const blocked = await client.publishers.getBlocked('account-id');

// Block / Unblock publishers
await client.publishers.blockPublisher('account-id', 'site.com');
await client.publishers.unblockPublisher('account-id', 'site.com');

// Bulk update blocked publishers
await client.publishers.updateBlocked('account-id', {
  sites: ['site1.com', 'site2.com'],
});

// Clear all blocks
await client.publishers.clearBlocked('account-id');

Dictionary (Reference Data)

// Geographic data
const countries = await client.dictionary.getCountries();
const regions = await client.dictionary.getRegions('US');
const dmas = await client.dictionary.getDMAs('US');

// Platform/device data
const platforms = await client.dictionary.getPlatforms();

// Audience segments
const marketplace = await client.dictionary.getMarketplaceAudiences('account-id');
const contextual = await client.dictionary.getContextualSegments('account-id');

Combined Audiences

// List available audiences for targeting
const available = await client.combinedAudiences.listAvailable('account-id');

// List combined audiences
const audiences = await client.combinedAudiences.list('account-id');

// Get single combined audience
const audience = await client.combinedAudiences.get('account-id', 'audience-id');

// Create combined audience
const audience = await client.combinedAudiences.create('account-id', {
  name: 'High Value Users',
  rules: [
    { type: 'INCLUDE', audience_id: 'audience-1' },
    { type: 'EXCLUDE', audience_id: 'audience-2' },
  ],
});

Shared Budgets

// List shared budgets (base fields)
const { results } = await client.sharedBudgets.listBase('account-id');

// Get a shared budget
const budget = await client.sharedBudgets.get('account-id', 'budget-id');

// Create shared budget
const budget = await client.sharedBudgets.create('account-id', {
  name: 'Q1 Budget',
  marketing_objective: 'DRIVE_WEBSITE_TRAFFIC',
  spending_limit_model: 'MONTHLY',
  spending_limit: 5000,
  daily_cap: 200,
});

// Update shared budget
await client.sharedBudgets.update('account-id', 'budget-id', {
  spending_limit: 10000,
});

First Party Audiences

// List first party audiences
const audiences = await client.firstPartyAudiences.list('account-id');

// Get single audience
const audience = await client.firstPartyAudiences.get('account-id', 'audience-id');

// Create first party audience
const audience = await client.firstPartyAudiences.create('account-id', {
  name: 'My Audience',
  ttl_in_days: 30,
});

// Add/remove users
await client.firstPartyAudiences.addUsers('account-id', 'audience-id', {
  operation: 'ADD',
  users: [
    { type: 'EMAIL_SHA256', id: 'hashed-email-1' },
    { type: 'EMAIL_SHA256', id: 'hashed-email-2' },
  ],
});

Error Handling

The SDK provides typed error classes for different scenarios:

import {
  TaboolaError,
  TaboolaAuthError,
  TaboolaValidationError,
  TaboolaNotFoundError,
  TaboolaRateLimitError,
  TaboolaForbiddenError,
} from 'taboola-backstage-sdk';

try {
  await client.campaigns.get('account-id', 'invalid-id');
} catch (error) {
  if (error instanceof TaboolaNotFoundError) {
    console.error('Campaign not found');
  } else if (error instanceof TaboolaAuthError) {
    console.error('Authentication failed');
  } else if (error instanceof TaboolaValidationError) {
    console.error('Validation error:', error.fieldErrors);
  } else if (error instanceof TaboolaRateLimitError) {
    console.error(`Rate limited. Retry after ${error.retryAfter}s`);
  } else if (error instanceof TaboolaForbiddenError) {
    console.error('Access denied');
  } else if (error instanceof TaboolaError) {
    console.error(`API error: ${error.message} (${error.statusCode})`);
  }
}

TypeScript

All types are exported for use in your application:

import type {
  // Core types
  Campaign,
  CampaignBase,
  CampaignItem,
  Account,
  SharedBudget,

  // Request types
  CreateCampaignRequest,
  UpdateCampaignRequest,
  CreateItemRequest,
  BulkCreateItemData,
  CreateSharedBudgetRequest,

  // Report types
  CampaignSummaryReport,
  CampaignSummaryRow,
  RealtimeCampaignReport,

  // Targeting types
  PostalCodeTargeting,
  AudienceTargeting,
  MarkingLabelsTargeting,

  // Pixel types
  ConversionRule,
  CustomAudienceRule,

  // Enums / dimension types
  MarketingObjective,
  BidStrategy,
  CampaignStatus,
  ItemStatus,
  ReportDimension,
  RealtimeCampaignDimension,
} from 'taboola-backstage-sdk';

CommonJS Usage

const { TaboolaClient } = require('taboola-backstage-sdk');

const client = new TaboolaClient({
  clientId: process.env.TABOOLA_CLIENT_ID,
  clientSecret: process.env.TABOOLA_CLIENT_SECRET,
});

Requirements

  • Node.js 18.0.0 or higher

API Documentation

For detailed API documentation, see the Taboola Backstage API Reference.

Changelog

v0.3.0 (2024)

Enhanced Update Support - Comprehensive updates for campaigns and items

  • Campaign Updates: Expanded UpdateCampaignRequest to support all updatable fields including:

    • Geographic targeting (DMA, region, city, postal code, sub-country)
    • Advanced targeting (contextual, browser, connection type, auto publisher)
    • Bid modifiers (publisher bid modifiers and bid strategy modifiers)
    • Audience targeting (marketplace, custom, lookalike, marking labels, contextual segments)
    • Additional fields (pricing model, campaign profile, traffic allocation, external brand safety, verification pixels, viewability tags)
  • Item Updates: Expanded UpdateItemRequest to support both static items and motion ads:

    • Static items: url, thumbnail_url, verification_pixel, viewability_tag, creative_focus
    • Motion ads: New PerformanceVideoData type with video_url and fallback_url
    • Enhanced documentation with examples for both item types
  • Partial Updates: Both endpoints properly support partial updates where only specified fields are modified

  • Improved Documentation: Added comprehensive JSDoc examples and better API alignment

v0.2.1 (2024)

Minor bug fixes and documentation improvements.

v0.2.0 (2024)

Added support for shared budgets, marking labels, and realtime report signatures.

v0.1.0 (2024)

Initial release with core API support.

License

MIT

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Links

About

TypeScript SDK for Taboola Backstage API - Campaign management, reporting, and audience targeting

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors