pixellint

Blog · Taboola S2S

Taboola lands tblci. The postback wants click-id. The hyphen is the conversion.

Landing pages receive tblci. S2S GET and bulk JSON require the query key click-id with a hyphen. Sending tblci on trc.taboola.com records nothing. Bulk POST returns 204 even when the JSON is junk.

That rename is the whole integration. Taboola appends tblci to the ad URL. Your thank-you worker has to send the same value back under a different key. The host is trc.taboola.com. The GET path is /actions-handler/log/3/s2s-action. The bulk path is /{account-id}/log/3/bulk-s2s-action. Neither path accepts tblci as the click field. Realize will still show a 204 on bulk. The conversion table will not move.

This is dated news for anyone wiring Taboola after a Meta or AppsFlyer hop. The click id exists. The query key does not travel with it. A gateway that only checks HTTP status will ship the wrong name forever.

tblci is inbound. click-id is the postback.

Taboola Help and the manual S2S guide say the same thing: Taboola automatically appends tblci={click_id} to all ad URLs. If your landing stack can store that parameter, you do not need a custom macro in Realize. If a hosted checkout or a redirector strips unknown keys, you either copy tblci through the hop or you add a custom Click ID param at campaign or ad level, still with the {click_id} macro on the right-hand side.

The value itself is a case-sensitive string. Help describes it as roughly 70 characters. The postback reference describes it as roughly 120. Pass it as is. Truncate it and Taboola ignores the conversion. Do not lowercase it. Do not put it in a cookie named click_id and assume the postback will find it.

When the conversion fires, the server is responsible for the hop. Two methods are documented. A GET to the postback URL, one conversion per call, with query parameters. A POST of JSON to bulk-s2s-action, up to 1,000 conversions, no authentication header. Both docs put a warning in the same words: the parameter must be named click-id with a hyphen, exactly as shown. That is different from the landing page parameter name.

Event Name is not Conversion Name

Realize has two labels that look interchangeable in a screenshot. Conversion Name is the descriptive label, Complete Registration or whatever the marketer typed. It is not used for matching. Event Name is the string you must send as name. The postback reference is explicit: refer to the Event Name field under the Conversion settings, not the Conversion Name. The Help article says if the naming convention is not identical, Taboola will not receive the event.

name is required on GET and on every bulk row. It is case-sensitive. Sending purchase when Realize has Purchase is a miss. Sending the Conversion Name because that is what the campaign brief used is a miss. Skip the Event Code snippet in Realize when you are S2S-only. The event values go out on the postback, not in a browser pixel.

GET can 400. Bulk will not.

The single-conversion postback is a GET:

https://trc.taboola.com/actions-handler/log/3/s2s-action?click-id=CLICK_ID&name=EVENT_NAME plus optional revenue, currency, quantity, and orderid. Required params are click-id and name. Missing or misspelled click-id is HTTP 400. An unparsable click-id value is 400. Missing name is 400. A misspelled endpoint, s2s-acton instead of s2s-action, is 400. A successful GET returns 204.

Bulk is a different contract. POST https://trc.taboola.com/{account-id}/log/3/bulk-s2s-action with Content-Type application/json and a body that is one object with an actions array. Each row needs click-id, timestamp, and name. timestamp is milliseconds since Unix epoch. The GET postback does not take timestamp at all. Copying a bulk row onto the GET URL drops the clock. Copying a GET query onto bulk drops the clock the other way, and bulk requires it.

The bulk response is always 204 with an empty body. Taboola says that indicates only that the request was received and is being processed. It does not indicate that valid data was received. Processing is asynchronous. No second response is sent. A failed row is skipped and the next row continues. Badly formed JSON means no action is taken. At this time, Taboola does not validate param values on bulk submit. The error-code page excludes bulk from the GET validations. MMP S2S such as AppsFlyer and DCO tracking are excluded too. A 204 on bulk is not a conversion in Realize.

The GET people will fire first

A landing-page query key on the postback host. Taboola documents that the Click ID param must be named click-id.

GET /actions-handler/log/3/s2s-action?tblci=GiC3sJdfEHXrroWoRIMZNc-HmQGs4UllzePkXl8h7XSOfSDOqFUoqNjkqZDk_6u1ATCn214&name=purchase HTTP/1.1
Host: trc.taboola.com

That request can look live in a HAR. The Click ID value is real. The event name might even match Realize. The key is tblci. The postback docs say the Click ID param must be named click-id, exactly as shown, otherwise no conversions will be recorded. The 400 table on the error-code page is the GET path telling you the param is missing or misspelled. If you moved the same object to bulk with click_id as an underscore, bulk will still 204. The hyphen never arrived.

Optional values are the usual ROAS set: revenue as an integer or decimal, currency as a case-sensitive three-letter code from Taboola's list, quantity as an integer, orderid as a string from your CRM. If currency is omitted, the account default is used. orderid is relevant for purchase-like events. None of those fields replace click-id.

Names that do not translate

Verify in Realize, not in the status line

Taboola's verification path is Realize, Tracking, Conversions, Test Events, Server Events. Generate a QR. The generator adds tblci with a test value. Walk the funnel. Fire your S2S call with that Click ID under click-id. The Events Received panel is the check, not a green 204. The alternative method copies a test link and then you wait up to 20 minutes and read Status, Last received, and Events received on the conversion rule.

If you configured a custom landing param, the campaign tracking code or the ad target URL must contain {click_id}. Default tblci does not need that macro for production, but the alternative test-link path still wants the macro even when you are testing tblci. That is a docs footgun, not a reason to send tblci on the postback.

Keep the click id next to the order the way you keep gclid. Persist it through hosted checkout. At emit time, map the stored value onto click-id. Do not share a query-string builder named clickId across Meta, TikTok, and Taboola. fbclid and ttclid are not tblci, and none of them is the hyphenated postback key.

Each request returns 204 with an empty body. This indicates only that Taboola received the request and is processing it. (It does not indicate that valid data was received.)

Taboola bulk submit S2S conversions

What to do

Capture tblci on the first landing hit. Copy it through redirects. On conversion, GET click-id and name to /actions-handler/log/3/s2s-action, or POST actions[] with click-id, timestamp in milliseconds, and name to /{account-id}/log/3/bulk-s2s-action. Chunk bulk at 1,000. Send revenue, currency, quantity, and orderid when you have them.

Treat GET 400 as a field-name bug. Treat bulk 204 as a mailbox receipt. Confirm the event in Realize Test Events. The Taboola S2S pack is vendor/taboola-s2s. Bulk JSON is a different pack. The UniPixel loader is a third pack. One fixture cannot cover all three.

The contract pages are the postback URL and bulk submit guides. This post is the market fact: the hyphen is the conversion. Pixellint is not affiliated with Taboola. Passing a linter means the artifact matches the published envelope. It does not mean Realize attributed the order, and it does not detect fraud.

Checklist

Sources

Contract pages

The dated argument is above. These pages are the field lists.

Open the Taboola S2S pack Docs