Skip to main content

GUIDE · TABOOLA

Taboola server to server events with TrackLayer

This guide shows how to move Taboola conversion delivery onto the server side path that TrackLayer already controls. The critical pieces are click id capture from tblci, OAuth2 token management, exact event naming, and stable deduplication with external_id.

01

TL;DR

  • Capture the Taboola landing click id from the tblci query parameter and persist it as click_id before checkout starts.
  • Exchange client_id and client_secret for a 3600 second OAuth2 access token, then post conversions to the Backstage conversions endpoint.
  • Send a stable external_id for deduplication and validate every payload in the TrackLayer dashboard before moving traffic to production.
02

Prerequisites

  • A Taboola advertiser account with access to the target account_id in Backstage.
  • Taboola API credentials with client_id and client_secret for the OAuth2 client_credentials flow.
  • TrackLayer installed so click ids, order ids, and canonical commerce events are available on the server.
  • Landing pages that preserve the tblci parameter through redirects, locale routers, and checkout handoff.
  • A deterministic order or lead id that can be reused as external_id for retries and deduplication.
03

Setup Steps

01

Capture the Taboola click id at landing time

Taboola appends tblci to the landing URL. Read it on the first page view, persist it in a first party cookie or session record, and copy it into TrackLayer as click_id. If redirects strip tblci, Taboola cannot attribute the later conversion.

const params = new URLSearchParams(window.location.search);
const tblci = params.get("tblci");

if (tblci) {
  document.cookie = [
    "tl_taboola_click_id=" + encodeURIComponent(tblci),
    "Path=/",
    "Max-Age=2592000",
    "SameSite=Lax",
    "Secure",
  ].join("; ");
}

// TrackLayer canonical transport
window.tracklayer = window.tracklayer || [];
window.tracklayer.push({
  type: "identity",
  network: "taboola",
  click_id: tblci || undefined,
});
02

Request a short lived OAuth token

Taboola uses OAuth2 client_credentials. Request a bearer token on the server, cache it with its 3600 second lifetime, and refresh slightly before expiry. Do not mint a new token for every event because burst traffic can turn auth into the bottleneck.

const tokenResponse = await fetch(
  "https://backstage.taboola.com/backstage/oauth/token",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
    },
    body: new URLSearchParams({
      grant_type: "client_credentials",
      client_id: process.env.TABOOLA_CLIENT_ID || "",
      client_secret: process.env.TABOOLA_CLIENT_SECRET || "",
    }),
  }
);

if (!tokenResponse.ok) {
  throw new Error("Taboola token request failed");
}

const token = await tokenResponse.json();
// token.access_token
// token.token_type === "bearer"
// token.expires_in === 3600
03

Map TrackLayer canonical events to Taboola names

Keep the mapping explicit. Taboola expects the event_name you configured in Backstage, plus click_id, event_timestamp, revenue, currency, and external_id when relevant. TrackLayer should also keep any normalized email or phone hashes internally for cross network fan out, even though this Taboola call is primarily click id driven.

const taboolaEventMap = {
  page_view: "PageView",
  view_item: "ViewContent",
  add_to_cart: "AddToCart",
  begin_checkout: "InitiateCheckout",
  generate_lead: "Lead",
  purchase: "Purchase",
} as const;

function toTaboolaEvent(tracklayerEvent) {
  const eventName = taboolaEventMap[tracklayerEvent.name];

  if (!eventName) {
    return null;
  }

  return {
    click_id: tracklayerEvent.click_id,
    event_name: eventName,
    event_timestamp: new Date(tracklayerEvent.timestamp).toISOString(),
    revenue: tracklayerEvent.value ?? 0,
    currency: tracklayerEvent.currency ?? "USD",
    external_id: tracklayerEvent.order_id ?? tracklayerEvent.event_id,
  };
}
04

Post conversions to the account endpoint

Send one authenticated POST per accepted conversion to the account specific endpoint. A purchase should include revenue and currency. A lead without revenue can still be sent with revenue set to 0. Use external_id on every retry so TrackLayer and Taboola treat replays as the same business event.

const url =
  "https://backstage.taboola.com/backstage/api/1.0/account/ACCOUNT_ID/conversions";

const payload = {
  click_id: conversion.click_id,
  event_name: conversion.event_name,
  event_timestamp: conversion.event_timestamp,
  revenue: conversion.revenue,
  currency: conversion.currency,
  external_id: conversion.external_id,
};

const conversionResponse = await fetch(url, {
  method: "POST",
  headers: {
    Authorization: "Bearer " + accessToken,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(payload),
});

if (!conversionResponse.ok) {
  const errorBody = await conversionResponse.text();
  throw new Error("Taboola conversion rejected: " + errorBody);
}
05

Normalize identity and dedup on the TrackLayer side

Taboola attribution is click id centric, but your broader server side stack still needs disciplined identity handling. Normalize email and phone if you store them in TrackLayer, hash them with SHA 256 before persistence, and keep the unhashed values out of logs. For Taboola itself, the dedup anchor is external_id, usually your order number or lead primary key.

import { createHash } from "node:crypto";

function sha256(value) {
  return createHash("sha256")
    .update(value.trim().toLowerCase(), "utf8")
    .digest("hex");
}

const identity = {
  email_sha256: customer.email ? sha256(customer.email) : undefined,
  phone_sha256: customer.phone ? sha256(customer.phone) : undefined,
};

await saveTrackLayerEvent({
  network: "taboola",
  click_id: conversion.click_id,
  external_id: conversion.external_id,
  identity,
});
06

Test in TrackLayer before sending live budget

Run one controlled visit from a Taboola ad or test redirect, then complete the downstream conversion. In the TrackLayer dashboard, confirm the inbound click id, the mapped event_name, the outbound payload, the Taboola response, and the dedup key. Only after those five checks are green should you mark the integration live.

Checklist for one test order
1. Landing URL contains tblci
2. TrackLayer stores click_id
3. Purchase event has revenue and currency
4. external_id matches the order id
5. Outbound request hits /account/ACCOUNT_ID/conversions
6. Response status is success
7. Replay with same external_id does not create a second business event
04

Troubleshooting

Taboola rejects the payload with missing click id

Check the original landing URL for tblci, then inspect redirects and checkout domain hops. The most common failure is capturing the parameter on the first page but not persisting it into the order context that TrackLayer reads on the server.

The API accepts the request but no conversions appear in reports

Verify account_id, event_name spelling, timezone on event_timestamp, and the age of the click id. Also confirm that you are posting against the correct advertiser account and not a sandbox or sister account with a similar name.

Duplicate purchases appear after retries or queue replays

Reuse the same external_id every time the exact business event is replayed. A common mistake is generating a new UUID per retry, which turns a safe retry into a second conversion.

OAuth works intermittently during spikes

Cache the bearer token for slightly less than 3600 seconds and refresh it centrally. If every worker independently requests a token during a traffic burst, token churn can look like random auth failure.

05

Launch Checklist

  • Landing pages preserve tblci from first click through final checkout step.
  • TrackLayer stores the Taboola identifier as click_id in the server event record.
  • OAuth2 client_id and client_secret are present only on the server.
  • Bearer tokens are cached and refreshed before the 3600 second expiry.
  • POST requests go to /backstage/api/1.0/account/{account_id}/conversions.
  • Every payload includes event_name, event_timestamp, revenue, currency, and external_id when applicable.
  • TrackLayer logs the raw Taboola response code and body for failed deliveries.
  • external_id is stable across retries, queues, and webhook replays.
  • A manual end to end test is visible in both the TrackLayer dashboard and Taboola reporting.

We use essential cookies to keep the site secure and functional. Analytics and third-party tags run only with your consent. See our Cookie Policy.

We use essential cookies to keep the site secure and functional. Analytics and third-party tags run only with your consent. See our Cookie Policy.